Add support for FileDispatcherImpl/UnixNativeDispatcher
This commit is contained in:
8 files changed
+216
-98
No files matched your search
+1
-1
@@ -14,7 +14,7 @@ add_custom_target(build_info ALL
|
||||
|
||||
find_package(JNI REQUIRED)
|
||||
|
||||
add_library(substagent SHARED src/substagent.c src/fis_hook.c src/utils.c)
|
||||
add_library(substagent SHARED src/substagent.c src/fis_hook.c src/fdi_hook.c src/utils.c)
|
||||
add_library(stb INTERFACE)
|
||||
|
||||
target_include_directories(stb INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/external/stb)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "fdi_hook.h"
|
||||
#include "stb_ds.h"
|
||||
#include "utils.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
und_open0_t und_real_open0 = NULL;
|
||||
|
||||
fdi_read0_t fdi_real_read0 = NULL;
|
||||
|
||||
struct file {
|
||||
jint key;
|
||||
struct file_data value;
|
||||
} *fdi_files_map = NULL;
|
||||
|
||||
jint JNICALL und_open0_hook(JNIEnv *env, jobject thiz, jlong path_address, jint flags, jint mode) {
|
||||
jint fd = und_real_open0(env, thiz, path_address, flags, mode);
|
||||
const char *path = (const char *)(intptr_t)path_address;
|
||||
if (!path || !is_config_path(path)) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (!file) {
|
||||
jclass fileNotFoundException =
|
||||
(*env)->FindClass(env, "java/io/FileNotFoundException");
|
||||
(*env)->ThrowNew(env, fileNotFoundException, path);
|
||||
return fd;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t fsize = ftell(file);
|
||||
if (fsize == 0) {
|
||||
return fd;
|
||||
}
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
char *data = malloc(fsize + 1);
|
||||
fread(data, fsize, 1, file);
|
||||
data[fsize] = '\0';
|
||||
|
||||
parse_file(&data, fsize);
|
||||
|
||||
size_t fd_len = strlen(data);
|
||||
|
||||
struct file_data file_data;
|
||||
file_data.data = data;
|
||||
file_data.length = fd_len;
|
||||
file_data.index = 0;
|
||||
file_data.freed = 0;
|
||||
hmput(fdi_files_map, fd, file_data);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
jint JNICALL fdi_read0_hook(JNIEnv *env, jobject thiz, jobject fdObject, jlong address, jint len) {
|
||||
jclass class = (*env)->GetObjectClass(env, fdObject);
|
||||
jfieldID fieldID = (*env)->GetFieldID(env, class, "fd", "I");
|
||||
jint fd = (*env)->GetIntField(env, fdObject, fieldID);
|
||||
|
||||
struct file *file = hmgetp(fdi_files_map, fd);
|
||||
if (file->key != fd) {
|
||||
return fdi_real_read0(env, thiz, fdObject, address, len);
|
||||
} else if (file->value.freed) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct file_data *file_data = &file->value;
|
||||
|
||||
int n = MIN(len, file_data->length - file_data->index);
|
||||
memcpy((void *)(intptr_t)address, file_data->data + file_data->index, n);
|
||||
|
||||
if (n == file_data->length - file_data->index) {
|
||||
free(file_data->data);
|
||||
file_data->freed = 1;
|
||||
} else {
|
||||
file_data->index += n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef FDI_HOOK_H
|
||||
#define FDI_HOOK_H
|
||||
|
||||
#include <jvmti.h>
|
||||
#include <jni.h>
|
||||
|
||||
typedef jint (JNICALL *und_open0_t)(JNIEnv*, jobject, jlong, jint, jint);
|
||||
extern und_open0_t und_real_open0;
|
||||
|
||||
typedef jint (JNICALL *fdi_read0_t)(JNIEnv*, jobject, jobject, jlong, jint);
|
||||
extern fdi_read0_t fdi_real_read0;
|
||||
|
||||
jint JNICALL und_open0_hook(JNIEnv*, jobject, jlong, jint, jint);
|
||||
|
||||
jint JNICALL fdi_read0_hook(JNIEnv*, jobject, jobject, jlong, jint);
|
||||
|
||||
#endif
|
||||
+27
-73
@@ -3,19 +3,19 @@
|
||||
#define STB_DS_IMPLEMENTATION
|
||||
#include "stb_ds.h"
|
||||
|
||||
readBytes_t fis_real_readBytes = NULL;
|
||||
open0_t fis_real_open0 = NULL;
|
||||
read0_t fis_real_read0 = NULL;
|
||||
length0_t fis_real_length0 = NULL;
|
||||
position0_t fis_real_position0 = NULL;
|
||||
skip0_t fis_real_skip0 = NULL;
|
||||
available0_t fis_real_available0 = NULL;
|
||||
close_t fis_real_close = NULL;
|
||||
fis_readBytes_t fis_real_readBytes = NULL;
|
||||
fis_open0_t fis_real_open0 = NULL;
|
||||
fis_read0_t fis_real_read0 = NULL;
|
||||
fis_length0_t fis_real_length0 = NULL;
|
||||
fis_position0_t fis_real_position0 = NULL;
|
||||
fis_skip0_t fis_real_skip0 = NULL;
|
||||
fis_available0_t fis_real_available0 = NULL;
|
||||
fis_close_t fis_real_close = NULL;
|
||||
|
||||
struct file{
|
||||
jint key;
|
||||
struct file_data value;
|
||||
} *files_map = NULL;
|
||||
} *fis_files_map = NULL;
|
||||
|
||||
jint JNICALL fis_readBytes_hook(JNIEnv* env, jobject thiz, jbyteArray buf, jint off, jint len) {
|
||||
if (!has_tag(thiz)) {
|
||||
@@ -27,7 +27,7 @@ jint JNICALL fis_readBytes_hook(JNIEnv* env, jobject thiz, jbyteArray buf, jint
|
||||
|
||||
jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method);
|
||||
|
||||
struct file *file = hmgetp(files_map, hash);
|
||||
struct file *file = hmgetp(fis_files_map, hash);
|
||||
if (file->key != hash || file->value.freed) {
|
||||
return -1;
|
||||
}
|
||||
@@ -86,66 +86,20 @@ void JNICALL fis_open0_hook(JNIEnv* env, jobject thiz, jstring jpath) {
|
||||
}
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
char *file_data = malloc(fsize + 1);
|
||||
fread(file_data, fsize, 1, file);
|
||||
file_data[fsize] = '\0';
|
||||
char *data = malloc(fsize + 1);
|
||||
fread(data, fsize, 1, file);
|
||||
data[fsize] = '\0';
|
||||
|
||||
int dollar_sign_matched_index = -1;
|
||||
char env_var[4096];
|
||||
env_var[0] = '\0';
|
||||
for (size_t i = 0; i < fsize; i++) {
|
||||
char c = file_data[i];
|
||||
if (dollar_sign_matched_index != -1) {
|
||||
if ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c == 95) {
|
||||
size_t len = strlen(env_var);
|
||||
env_var[len] = c;
|
||||
env_var[len + 1] = '\0';
|
||||
} else {
|
||||
if (strlen(env_var) == 0) continue;
|
||||
char* value = getenv(env_var);
|
||||
if (!value) {
|
||||
dollar_sign_matched_index = -1;
|
||||
env_var[0] = '\0';
|
||||
continue;
|
||||
}
|
||||
parse_file(&data, fsize);
|
||||
|
||||
size_t env_len = i - dollar_sign_matched_index;
|
||||
size_t fd_len = strlen(data);
|
||||
|
||||
char* new_data = substitute(value, dollar_sign_matched_index, i, env_len, file_data);
|
||||
free(file_data);
|
||||
file_data = new_data;
|
||||
|
||||
dollar_sign_matched_index = -1;
|
||||
env_var[0] = '\0';
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (c == '$') {
|
||||
dollar_sign_matched_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dollar_sign_matched_index != -1) {
|
||||
if (strlen(env_var) != 0) {
|
||||
char* value = getenv(env_var);
|
||||
if (value) {
|
||||
size_t env_len = fsize - dollar_sign_matched_index;
|
||||
|
||||
char* new_data = substitute(value, dollar_sign_matched_index, fsize, env_len, file_data);
|
||||
free(file_data);
|
||||
file_data = new_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t fd_len = strlen(file_data);
|
||||
|
||||
struct file_data fd;
|
||||
fd.data = file_data;
|
||||
fd.length = fd_len;
|
||||
fd.index = 0;
|
||||
fd.freed = 0;
|
||||
hmput(files_map, hash, fd);
|
||||
struct file_data file_data;
|
||||
file_data.data = data;
|
||||
file_data.length = fd_len;
|
||||
file_data.index = 0;
|
||||
file_data.freed = 0;
|
||||
hmput(fis_files_map, hash, file_data);
|
||||
(*env)->ReleaseStringUTFChars(env, jpath, path);
|
||||
}
|
||||
|
||||
@@ -159,7 +113,7 @@ jint JNICALL fis_read0_hook(JNIEnv* env, jobject thiz) {
|
||||
|
||||
jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method);
|
||||
|
||||
struct file *file = hmgetp(files_map, hash);
|
||||
struct file *file = hmgetp(fis_files_map, hash);
|
||||
if (file->key != hash || file->value.freed) {
|
||||
return -1;
|
||||
}
|
||||
@@ -183,7 +137,7 @@ jlong JNICALL fis_length0_hook(JNIEnv* env, jobject thiz) {
|
||||
|
||||
jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method);
|
||||
|
||||
struct file *file = hmgetp(files_map, hash);
|
||||
struct file *file = hmgetp(fis_files_map, hash);
|
||||
if (file->key != hash) {
|
||||
return -1;
|
||||
}
|
||||
@@ -201,7 +155,7 @@ jlong JNICALL fis_position0_hook(JNIEnv* env, jobject thiz) {
|
||||
|
||||
jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method);
|
||||
|
||||
struct file *file = hmgetp(files_map, hash);
|
||||
struct file *file = hmgetp(fis_files_map, hash);
|
||||
if (file->key != hash) {
|
||||
return -1;
|
||||
}
|
||||
@@ -219,7 +173,7 @@ jlong JNICALL fis_skip0_hook(JNIEnv* env, jobject thiz, jlong n) {
|
||||
|
||||
jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method);
|
||||
|
||||
struct file *file = hmgetp(files_map, hash);
|
||||
struct file *file = hmgetp(fis_files_map, hash);
|
||||
if (file->key != hash) {
|
||||
return 0;
|
||||
}
|
||||
@@ -248,7 +202,7 @@ jint JNICALL fis_available0_hook(JNIEnv* env, jobject thiz) {
|
||||
|
||||
jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method);
|
||||
|
||||
struct file *file = hmgetp(files_map, hash);
|
||||
struct file *file = hmgetp(fis_files_map, hash);
|
||||
if (file->key != hash) {
|
||||
return 0;
|
||||
}
|
||||
@@ -267,7 +221,7 @@ void JNICALL fis_close_hook(JNIEnv* env, jobject thiz) {
|
||||
|
||||
jint hash = (*env)->CallIntMethod(env, thiz, hash_code_method);
|
||||
|
||||
struct file *file = hmgetp(files_map, hash);
|
||||
struct file *file = hmgetp(fis_files_map, hash);
|
||||
if (file->key != hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
+16
-16
@@ -4,22 +4,22 @@
|
||||
#include <jvmti.h>
|
||||
#include <jni.h>
|
||||
|
||||
typedef void (JNICALL *open0_t)(JNIEnv*, jobject, jstring);
|
||||
typedef jint (JNICALL *readBytes_t)(JNIEnv*, jobject, jbyteArray, jint, jint);
|
||||
typedef jint (JNICALL *read0_t)(JNIEnv*, jobject);
|
||||
typedef jlong (JNICALL *length0_t)(JNIEnv*, jobject);
|
||||
typedef jlong (JNICALL *position0_t)(JNIEnv*, jobject);
|
||||
typedef jlong (JNICALL *skip0_t)(JNIEnv*, jobject, jlong);
|
||||
typedef jint (JNICALL *available0_t)(JNIEnv*, jobject);
|
||||
typedef void (JNICALL *close_t)(JNIEnv*, jobject);
|
||||
extern readBytes_t fis_real_readBytes;
|
||||
extern open0_t fis_real_open0;
|
||||
extern read0_t fis_real_read0;
|
||||
extern length0_t fis_real_length0;
|
||||
extern position0_t fis_real_position0;
|
||||
extern skip0_t fis_real_skip0;
|
||||
extern available0_t fis_real_available0;
|
||||
extern close_t fis_real_close;
|
||||
typedef void (JNICALL *fis_open0_t)(JNIEnv*, jobject, jstring);
|
||||
typedef jint (JNICALL *fis_readBytes_t)(JNIEnv*, jobject, jbyteArray, jint, jint);
|
||||
typedef jint (JNICALL *fis_read0_t)(JNIEnv*, jobject);
|
||||
typedef jlong (JNICALL *fis_length0_t)(JNIEnv*, jobject);
|
||||
typedef jlong (JNICALL *fis_position0_t)(JNIEnv*, jobject);
|
||||
typedef jlong (JNICALL *fis_skip0_t)(JNIEnv*, jobject, jlong);
|
||||
typedef jint (JNICALL *fis_available0_t)(JNIEnv*, jobject);
|
||||
typedef void (JNICALL *fis_close_t)(JNIEnv*, jobject);
|
||||
extern fis_readBytes_t fis_real_readBytes;
|
||||
extern fis_open0_t fis_real_open0;
|
||||
extern fis_read0_t fis_real_read0;
|
||||
extern fis_length0_t fis_real_length0;
|
||||
extern fis_position0_t fis_real_position0;
|
||||
extern fis_skip0_t fis_real_skip0;
|
||||
extern fis_available0_t fis_real_available0;
|
||||
extern fis_close_t fis_real_close;
|
||||
|
||||
jint JNICALL fis_readBytes_hook(JNIEnv* env, jobject thiz, jbyteArray buf, jint off, jint len);
|
||||
void JNICALL fis_open0_hook(JNIEnv* env, jobject thiz, jstring jpath);
|
||||
|
||||
+21
-8
@@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "build_info.h"
|
||||
#include "fdi_hook.h"
|
||||
#include "fis_hook.h"
|
||||
#include "utils.h"
|
||||
|
||||
@@ -25,37 +26,49 @@ static void JNICALL onNativeMethodBind(jvmtiEnv* jvmti_env, JNIEnv* env, jthread
|
||||
if (strcmp(csig, "Ljava/io/FileInputStream;") == 0) {
|
||||
// private native void open0(String name)
|
||||
if (strcmp(mname, "open0") == 0 && strcmp(msig, "(Ljava/lang/String;)V") == 0) {
|
||||
fis_real_open0 = (open0_t)address;
|
||||
fis_real_open0 = (fis_open0_t)address;
|
||||
*new_address_ptr = (void*)&fis_open0_hook;
|
||||
// private native int readBytes(byte b[], int off, int len)
|
||||
} else if (strcmp(mname, "readBytes") == 0 && strcmp(msig, "([BII)I") == 0) {
|
||||
fis_real_readBytes = (readBytes_t)address;
|
||||
fis_real_readBytes = (fis_readBytes_t)address;
|
||||
*new_address_ptr = (void*)&fis_readBytes_hook;
|
||||
// private native int read0
|
||||
} else if (strcmp(mname, "read0") == 0 && strcmp(msig, "()I") == 0) {
|
||||
fis_real_read0 = (read0_t)address;
|
||||
fis_real_read0 = (fis_read0_t)address;
|
||||
*new_address_ptr = (void*)&fis_read0_hook;
|
||||
// private native long length0()
|
||||
} else if (strcmp(mname, "length0") == 0 && strcmp(msig, "()J") == 0) {
|
||||
fis_real_length0 = (length0_t)address;
|
||||
fis_real_length0 = (fis_length0_t)address;
|
||||
*new_address_ptr = (void*)&fis_length0_hook;
|
||||
// private native long position0()
|
||||
} else if (strcmp(mname, "position0") == 0 && strcmp(msig, "()J") == 0) {
|
||||
fis_real_position0 = (position0_t)address;
|
||||
fis_real_position0 = (fis_position0_t)address;
|
||||
*new_address_ptr = (void*)&fis_position0_hook;
|
||||
// private native long skip0(long n)
|
||||
} else if (strcmp(mname, "skip0") == 0 && strcmp(msig, "(J)J") == 0) {
|
||||
fis_real_skip0 = (skip0_t)address;
|
||||
fis_real_skip0 = (fis_skip0_t)address;
|
||||
*new_address_ptr = (void*)&fis_skip0_hook;
|
||||
// private native int available0()
|
||||
} else if (strcmp(mname, "available0") == 0 && strcmp(msig, "()I") == 0) {
|
||||
fis_real_available0 = (available0_t)address;
|
||||
fis_real_available0 = (fis_available0_t)address;
|
||||
*new_address_ptr = (void*)&fis_available0_hook;
|
||||
// public void close()
|
||||
} else if (strcmp(mname, "close") == 0 && strcmp(msig, "()V") == 0) {
|
||||
fis_real_close = (close_t)address;
|
||||
fis_real_close = (fis_close_t)address;
|
||||
*new_address_ptr = (void*)&fis_close_hook;
|
||||
}
|
||||
} else if (strcmp(csig, "Lsun/nio/fs/UnixNativeDispatcher;") == 0) {
|
||||
// private static native int open0(long pathAddress, int flags, int mode)
|
||||
if (strcmp(mname, "open0") == 0 && strcmp(msig, "(JII)I") == 0) {
|
||||
und_real_open0 = (und_open0_t)address;
|
||||
*new_address_ptr = (void*)&und_open0_hook;
|
||||
}
|
||||
} else if (strcmp(csig, "Lsun/nio/ch/FileDispatcherImpl;") == 0) {
|
||||
// static native int read0(FileDescriptor fd, long address, int len)
|
||||
if (strcmp(mname, "read0") == 0 && strcmp(msig, "(Ljava/io/FileDescriptor;JI)I") == 0) {
|
||||
fdi_real_read0 = (fdi_read0_t)address;
|
||||
*new_address_ptr = (void*)&fdi_read0_hook;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+53
@@ -42,4 +42,57 @@ char* substitute(const char* value, int dollar_sign_matched_index, size_t i, siz
|
||||
assert(dollar_sign_matched_index+value_len+after_len == new_len);
|
||||
new_data[new_len] = '\0';
|
||||
return new_data;
|
||||
}
|
||||
|
||||
void parse_file(char **data_ptr, size_t fsize) {
|
||||
char *data = *data_ptr;
|
||||
int dollar_sign_matched_index = -1;
|
||||
char env_var[4096];
|
||||
env_var[0] = '\0';
|
||||
for (size_t i = 0; i < fsize; i++) {
|
||||
char c = data[i];
|
||||
if (dollar_sign_matched_index != -1) {
|
||||
if ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c == 95) {
|
||||
size_t len = strlen(env_var);
|
||||
env_var[len] = c;
|
||||
env_var[len + 1] = '\0';
|
||||
} else {
|
||||
if (strlen(env_var) == 0) continue;
|
||||
char* value = getenv(env_var);
|
||||
if (!value) {
|
||||
dollar_sign_matched_index = -1;
|
||||
env_var[0] = '\0';
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t env_len = i - dollar_sign_matched_index;
|
||||
|
||||
char* new_data = substitute(value, dollar_sign_matched_index, i, env_len, data);
|
||||
free(data);
|
||||
data = new_data;
|
||||
*data_ptr = new_data;
|
||||
|
||||
dollar_sign_matched_index = -1;
|
||||
env_var[0] = '\0';
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (c == '$') {
|
||||
dollar_sign_matched_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dollar_sign_matched_index != -1) {
|
||||
if (strlen(env_var) != 0) {
|
||||
char* value = getenv(env_var);
|
||||
if (value) {
|
||||
size_t env_len = fsize - dollar_sign_matched_index;
|
||||
|
||||
char* new_data = substitute(value, dollar_sign_matched_index, fsize, env_len, data);
|
||||
free(data);
|
||||
data = new_data;
|
||||
*data_ptr = new_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ void tag(jobject obj);
|
||||
int has_tag(jobject obj);
|
||||
int is_config_path(const char* path);
|
||||
char* substitute(const char* value, int dollar_sign_matched_index, size_t i, size_t env_len, const char *data);
|
||||
void parse_file(char **data_ptr, size_t fsize);
|
||||
|
||||
struct file_data {
|
||||
char* data;
|
||||
|
||||
Reference in new issue
Block a user