Last active
March 14, 2023 23:46
-
-
Save apangin/42e3b5c53555284c3ce0 to your computer and use it in GitHub Desktop.
Patch to enable O_SYNC on RandomAccessFile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Compile: gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -fPIC -O3 -olibrafpatch.so -Wl,-soname,librafpatch.so rafpatch.c $JAVA_HOME/lib/amd64/libjava.so | |
* Run: java -agentpath:/path/to/librafpatch.so MainClass | |
*/ | |
#include <jvmti.h> | |
#include <jni.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <errno.h> | |
static jfieldID randomAccessFile_fd; | |
static jfieldID fileDescriptor_fd; | |
JNIEXPORT const char* JNICALL | |
JNU_GetStringPlatformChars(JNIEnv* env, jstring jstr, jboolean* isCopy); | |
JNIEXPORT void JNICALL | |
JNU_ReleaseStringPlatformChars(JNIEnv* env, jstring jstr, const char* str); | |
JNIEXPORT void JNICALL | |
JNU_ThrowNullPointerException(JNIEnv *env, const char* msg); | |
void throwFileNotFoundException(JNIEnv* env, jstring path); | |
#define RESTARTABLE(cmd, result) \ | |
do { \ | |
result = cmd; \ | |
} while(result == -1 && errno == EINTR); | |
int handleOpen(const char* path, int oflag, int mode) { | |
int fd; | |
RESTARTABLE(open64(path, oflag, mode), fd); | |
if (fd != -1) { | |
struct stat buf64; | |
int result; | |
RESTARTABLE(fstat64(fd, &buf64), result); | |
if (result == -1) { | |
close(fd); | |
return -1; | |
} else if (S_ISDIR(buf64.st_mode)) { | |
close(fd); | |
errno = EISDIR; | |
return -1; | |
} | |
} | |
return fd; | |
} | |
JNIEXPORT void JNICALL | |
Hook_java_io_RandomAccessFile_open0(JNIEnv* env, jobject this, jstring path, jint mode) { | |
int flags = 0; | |
if (mode & 1) { | |
flags = O_RDONLY; | |
} else if (mode & 2) { | |
flags = O_RDWR | O_CREAT; | |
if (mode & 4) { | |
flags |= O_SYNC; | |
} else if (mode & 8) { | |
flags |= O_DSYNC; | |
} | |
} | |
if (path == NULL) { | |
JNU_ThrowNullPointerException(env, NULL); | |
return; | |
} | |
const char* ps = JNU_GetStringPlatformChars(env, path, NULL); | |
if (ps == NULL) return; | |
// Strip trailing slashes | |
char* p = (char*)ps + strlen(ps) - 1; | |
while (p > ps && *p == '/') { | |
*p-- = '\0'; | |
} | |
int fd = handleOpen(ps, flags, 0666); | |
if (fd == -1) { | |
throwFileNotFoundException(env, path); | |
} else { | |
jobject fileDescriptor = (*env)->GetObjectField(env, this, randomAccessFile_fd); | |
if (fileDescriptor != NULL) { | |
(*env)->SetIntField(env, fileDescriptor, fileDescriptor_fd, fd); | |
} | |
} | |
JNU_ReleaseStringPlatformChars(env, path, ps); \ | |
} | |
void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) { | |
jclass randomAccessFile = (*env)->FindClass(env, "java/io/RandomAccessFile"); | |
jclass fileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); | |
randomAccessFile_fd = (*env)->GetFieldID(env, randomAccessFile, "fd", "Ljava/io/FileDescriptor;"); | |
fileDescriptor_fd = (*env)->GetFieldID(env, fileDescriptor, "fd", "I"); | |
JNINativeMethod open0 = {"open0", "(Ljava/lang/String;I)V", Hook_java_io_RandomAccessFile_open0}; | |
(*env)->RegisterNatives(env, randomAccessFile, &open0, 1); | |
printf("RandomAccessFile patch installed\n"); | |
} | |
JNIEXPORT jint JNICALL | |
Agent_OnLoad(JavaVM* vm, char *options, void* reserved) { | |
jvmtiEnv* jvmti; | |
jvmtiEventCallbacks callbacks; | |
(*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0); | |
memset(&callbacks, 0, sizeof(callbacks)); | |
callbacks.VMInit = VMInit; | |
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks)); | |
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment