Question

Some quick background on my problem:

I'm writing a compiler that converts Domain Type Enforcement specs into Java Security Manager code. In a nutshell, DTE defines "types" (objects), assigns paths to those types; then defines "domains" (subjects), and defines what permissions (rwxdc) domains have to various types. I need to emulate this behavior as closely as possible in the JSM.

Currently I'm working on write permissions. I've overridden the JSM's checkWrite(String filename) method successfully. Next on the list is checkWrite(FileDescriptor filedescriptor) and this one is proving trickier. Due to the way DTE is defined, I need path information to determine whether a write action is permissible.

  • Is it possible to extract path data from a FileDescriptor? I'm guessing no -- I've checked the documentation and various tutorials, and I've found nothing to suggest that there's any way for me to obtain this information (I'd be delighted to be shown wrong, however; that would make my job easier).

  • If the answer to the above is NO, could anyone suggest a viable workaround? For example, is there some way I could write native code to do what I want and tie this into my custom JSM class? I'm fine with doing something "advanced" like that, but I'd need some idea how to get started.

  • Or is my only option basically to deny all write permissions that use a FileDescriptor? I'd very much like to avoid this because it's a crummy solution, but if that's the reality I need to know.

Thanks very much for your time.

Was it helpful?

Solution

The short answer is no, because a file is independent from the path used to access that file (at least on any OS that matters).

One possible work-around is to trap the calls that open files, using an aspect framework, and put the referenced file descriptors into a WeakHashMap<FileDescriptor,File>. Then you simply look at this map whenever you need to validate a write.

OTHER TIPS

Hopefully won't be blocked by reflection restrictions, but for now you can use this (code based a bit on the other answer), starting from Android O :

val file = File(filesDir, "ff")
file.parentFile!!.mkdirs()
val fileOutputStream = FileOutputStream(file)
val fd = fileOutputStream.fd
val method = fd.javaClass.getMethod("getInt$")
val fdId = method.invoke(fd)
val path = Paths.get("/proc/self/fd/$fdId")
val filePath = Files.readSymbolicLink(path)
Log.d("AppLog", "filePath:$filePath")

Not sure about FileChannel though. Its implementation file ("FileChannelImpl") is supposed to have "path" (file path String type) and "fd" which is the FileDescriptor , but both are hidden via reflection

the solution to get the path from FileDescriptor in java:

How it works:

We know that file descriptor contains descriptor id to locate the open file in the current process.

What are file descriptors, explained in simple terms?

if we know the descriptor id then we can easily find file path by following java code:

Path path = Paths.get("/proc/self/fd/"+fd_id);
System.out.println(Files.readSymbolicLink(path)); //return file path in file descriptor

Here:

fd_id file descriptor id (0,1,2 .....)

/proc its a Directory contains all process running in system

/self currently running java class process id

/fd file descriptor directory

//fd_id file descriptor id

SafeFileDescriptor.java

import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.nio.file.Path;  
public class SafeFileDescriptor {

 static {
    System.load("Documents/java native interface exmples/libSafeFileDescriptor.so");
}

private native int getFDid(FileDescriptor fd);

public static void main(String[] args) throws IOException{  
    FileOutputStream fout = new FileOutputStream("Documents/test.txt");
    FileDescriptor fd=fout.getFD();
    int fd_id = new SafeFileDescriptor().getFDid(fd);
    Path path = Paths.get("/proc/self/fd/"+fd_id);
    System.out.println(Files.readSymbolicLink(path));
}
}

getFDid() is a native method used to get descriptor id of the given file descriptor object

following code is implementation of getFDid() native method

SafeFileDescriptor.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class SafeFileDescriptor */

#ifndef _Included_SafeFileDescriptor
#define _Included_SafeFileDescriptor
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     SafeFileDescriptor
 * Method:    getFDid
 * Signature: (Ljava/io/FileDescriptor;)I
 */
JNIEXPORT jint JNICALL Java_SafeFileDescriptor_getFDid
  (JNIEnv *, jobject, jobject);

#ifdef __cplusplus
}
#endif
#endif

create SafeFileDescriptor.h from java file SafeFileDescriptor.java

javac -h dir SafeFileDescriptor.java

replace "dir" with your directory to store SafeFileDescriptor.h

SafeFileDescriptor.c

#include <jni.h>
#include "SafeFileDescriptor.h"

JNIEXPORT jint JNICALL Java_SafeFileDescriptor_getFDid
  (JNIEnv *env, jobject this_object, jobject fdObject) {

    jclass fileDescriptor = (*env)->GetObjectClass(env,fdObject);

    jfieldID id_fd = (*env)->GetFieldID(env, fileDescriptor, "fd", "I");

    return (*env)->GetIntField(env,fdObject,id_fd);
}

compile SafeFileDescriptor.c

gcc -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -shared -o libSafeFileDescriptor.so SafeFileDescriptor.c

To add libSafeFileDescriptor.so file to java class file

System.load("Documents/java native interface exmples/libSafeFileDescriptor.so");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top