diff --git a/src/GNUmakefile b/src/GNUmakefile index 0cb264f9..27879807 100644 --- a/src/GNUmakefile +++ b/src/GNUmakefile @@ -16,7 +16,7 @@ OBJDUMP ?= $(CROSS_COMPILE)objdump CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I. -I$(VPATH) CFLAGS += -Wall -Wextra -O2 -LDFLAGS += -ltalloc -Wl,-z,noexecstack +LDFLAGS += -lleveldb -ltalloc -Wl,-z,noexecstack OBJECTS += \ cli/cli.o \ @@ -66,8 +66,6 @@ OBJECTS += \ extension/fake_id0/utimensat.o \ extension/fake_id0/access.o \ extension/fake_id0/exec.o \ - extension/fake_id0/link.o \ - extension/fake_id0/symlink.o \ extension/fake_id0/mk.o \ extension/fake_id0/stat.o \ extension/fake_id0/helper_functions.o \ diff --git a/src/extension/fake_id0/access.c b/src/extension/fake_id0/access.c index d9197843..779945c6 100644 --- a/src/extension/fake_id0/access.c +++ b/src/extension/fake_id0/access.c @@ -6,15 +6,13 @@ #include "extension/fake_id0/helper_functions.h" /** Handles the access and faccessat syscalls. Checks permissions according to - * a meta file if it exists. See access(2) for returned errors. + * the meta info if it exists. See access(2) for returned errors. */ int handle_access_enter_end(Tracee *tracee, Reg path_sysarg, Reg mode_sysarg, Reg dirfd_sysarg, Config *config) { int status, mode, perms, mask; char path[PATH_MAX]; - char rel_path[PATH_MAX]; - char meta_path[PATH_MAX]; status = read_sysarg_path(tracee, path, path_sysarg, CURRENT); if(status < 0) @@ -22,23 +20,11 @@ int handle_access_enter_end(Tracee *tracee, Reg path_sysarg, if(status == 1) return 0; - status = get_fd_path(tracee, rel_path, dirfd_sysarg, CURRENT); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'r', path, rel_path, config); - if(status < 0) - return status; - // Only care about calls checking permissions. mode = peek_reg(tracee, ORIGINAL, mode_sysarg); if(mode & F_OK) return 0; - status = get_meta_path(path, meta_path); - if(status < 0) - return status; - mask = 0; if((mode & R_OK) == R_OK) mask += 4; @@ -47,7 +33,7 @@ int handle_access_enter_end(Tracee *tracee, Reg path_sysarg, if((mode & X_OK) == X_OK) mask += 1; - perms = get_permissions(meta_path, config, 1); + perms = get_permissions(path, config, 1); if((perms & mask) != mask) return -EACCES; diff --git a/src/extension/fake_id0/chmod.c b/src/extension/fake_id0/chmod.c index e1accbc5..85bc1e18 100644 --- a/src/extension/fake_id0/chmod.c +++ b/src/extension/fake_id0/chmod.c @@ -6,8 +6,8 @@ #include "extension/fake_id0/helper_functions.h" -/** Handles chmod, fchmod, and fchmodat syscalls. Changes meta files to the new - * permissions if the meta file exists. See chmod(2) for returned permission +/** Handles chmod, fchmod, and fchmodat syscalls. Changes meta info to the new + * permissions if the meta info exists. See chmod(2) for returned permission * errors. */ int handle_chmod_enter_end(Tracee *tracee, Reg path_sysarg, Reg mode_sysarg, @@ -18,8 +18,6 @@ int handle_chmod_enter_end(Tracee *tracee, Reg path_sysarg, Reg mode_sysarg, uid_t owner; gid_t group; char path[PATH_MAX]; - char rel_path[PATH_MAX]; - char meta_path[PATH_MAX]; // When path_sysarg is set to IGNORE, the call being handled is fchmod. if(path_sysarg == IGNORE_SYSARG) @@ -34,23 +32,11 @@ int handle_chmod_enter_end(Tracee *tracee, Reg path_sysarg, Reg mode_sysarg, return 0; } - status = get_meta_path(path, meta_path); - if(path_exists(meta_path) < 0) - return 0; - - status = get_fd_path(tracee, rel_path, dirfd_sysarg, CURRENT); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'r', path, rel_path, config); - if(status < 0) - return status; - - read_meta_file(meta_path, &read_mode, &owner, &group, config); + read_meta_info(path, &read_mode, &owner, &group, config); if(config->euid != owner && config->euid != 0) return -EPERM; call_mode = peek_reg(tracee, ORIGINAL, mode_sysarg); set_sysnum(tracee, PR_getuid); - return write_meta_file(meta_path, call_mode, owner, group, 0, config); + return write_meta_info(path, call_mode, owner, group, 0, config); } diff --git a/src/extension/fake_id0/chown.c b/src/extension/fake_id0/chown.c index bca332bf..ce3ab7bc 100644 --- a/src/extension/fake_id0/chown.c +++ b/src/extension/fake_id0/chown.c @@ -26,8 +26,8 @@ int handle_chown_enter_end(Tracee *tracee, Config *config, Reg uid_sysarg, Reg g #endif /* ifndef USERLAND */ #ifdef USERLAND -/** Handles chown, lchown, fchown, and fchownat syscalls. Changes the meta file - * to reflect arguments sent to the syscall if the meta file exists. See +/** Handles chown, lchown, fchown, and fchownat syscalls. Changes the meta info + * to reflect arguments sent to the syscall if the meta info exists. See * chown(2) for returned permission errors. */ int handle_chown_enter_end(Tracee *tracee, Reg path_sysarg, Reg owner_sysarg, @@ -38,8 +38,6 @@ int handle_chown_enter_end(Tracee *tracee, Reg path_sysarg, Reg owner_sysarg, uid_t owner, read_owner; gid_t group, read_group; char path[PATH_MAX]; - char rel_path[PATH_MAX]; - char meta_path[PATH_MAX]; if(path_sysarg == IGNORE_SYSARG) status = get_fd_path(tracee, path, fd_sysarg, CURRENT); @@ -53,38 +51,23 @@ int handle_chown_enter_end(Tracee *tracee, Reg path_sysarg, Reg owner_sysarg, return 0; } - status = get_meta_path(path, meta_path); - if(status < 0) - return status; - - if(path_exists(meta_path) != 0) - return 0; - - status = get_fd_path(tracee, rel_path, dirfd_sysarg, CURRENT); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'r', path, rel_path, config); - if(status < 0) - return status; - - read_meta_file(meta_path, &mode, &read_owner, &read_group, config); + read_meta_info(path, &mode, &read_owner, &read_group, config); owner = peek_reg(tracee, ORIGINAL, owner_sysarg); /** When chown is called without an owner specified, eg * chown :1000 'file', the owner argument to the system call is implicitly * set to -1. To avoid this, the owner argument is replaced with the owner - * according to the meta file if it exists, or the current euid. + * according to the meta info if it exists, or the current euid. */ if((int) owner == -1) owner = read_owner; group = peek_reg(tracee, ORIGINAL, group_sysarg); if(config->euid == 0) - write_meta_file(meta_path, mode, owner, group, 0, config); + write_meta_info(path, mode, owner, group, 0, config); //TODO Handle chown properly: owner can only change the group of // a file to another group they belong to. else if(config->euid == read_owner) { - write_meta_file(meta_path, mode, read_owner, group, 0, config); + write_meta_info(path, mode, read_owner, group, 0, config); poke_reg(tracee, owner_sysarg, read_owner); } diff --git a/src/extension/fake_id0/exec.c b/src/extension/fake_id0/exec.c index e3534f43..48f1405f 100644 --- a/src/extension/fake_id0/exec.c +++ b/src/extension/fake_id0/exec.c @@ -6,14 +6,13 @@ #include "extension/fake_id0/helper_functions.h" -/** Handles execve system calls. Checks permissions in a meta file if it exists +/** Handles execve system calls. Checks permissions from the meta info if it exists * and returns errors matching those in execve(2). */ int handle_exec_enter_end(Tracee *tracee, Reg filename_sysarg, Config *config) { int status, perms; char path[PATH_MAX]; - char meta_path[PATH_MAX]; uid_t uid; gid_t gid; mode_t mode; @@ -24,26 +23,13 @@ int handle_exec_enter_end(Tracee *tracee, Reg filename_sysarg, Config *config) if(status == 1) return 0; - status = get_meta_path(path, meta_path); - if(status < 0) - return status; - - /* If metafile doesn't exist, get out, but don't error. */ - if(path_exists(meta_path) != 0) - return 0; - - /* Check perms relative to / since there is no dirfd argument to execve */ - status = check_dir_perms(tracee, 'r', meta_path, "/", config); - if(status < 0) - return status; - /* Check whether the file has execute permission. */ - perms = get_permissions(meta_path, config, 0); + perms = get_permissions(path, config, 0); if((perms & 1) != 1) return -EACCES; /* If the setuid or setgid bits are on, change config accordingly. */ - read_meta_file(meta_path, &mode, &uid, &gid, config); + read_meta_info(path, &mode, &uid, &gid, config); if ((mode & S_ISUID) != 0) { config->ruid = 0; config->euid = 0; diff --git a/src/extension/fake_id0/fake_id0.c b/src/extension/fake_id0/fake_id0.c index b673aace..b7d3c709 100644 --- a/src/extension/fake_id0/fake_id0.c +++ b/src/extension/fake_id0/fake_id0.c @@ -269,12 +269,10 @@ static FilteredSysnum filtered_sysnums[] = { { PR_access, FILTER_SYSEXIT }, { PR_creat, FILTER_SYSEXIT }, { PR_faccessat, FILTER_SYSEXIT }, - { PR_link, FILTER_SYSEXIT }, - { PR_linkat, FILTER_SYSEXIT }, + { PR_open, FILTER_SYSEXIT }, + { PR_openat, FILTER_SYSEXIT }, { PR_mkdir, FILTER_SYSEXIT }, { PR_mkdirat, FILTER_SYSEXIT }, - { PR_symlink, FILTER_SYSEXIT }, - { PR_symlinkat, FILTER_SYSEXIT }, { PR_umask, FILTER_SYSEXIT }, { PR_unlink, FILTER_SYSEXIT }, { PR_unlinkat, FILTER_SYSEXIT }, @@ -350,6 +348,8 @@ static FilteredSysnum filtered_sysnums[] = { FILTERED_SYSNUM_END, }; +bool meta_initialized; + /** * Restore the @node->mode for the given @node->path. * @@ -503,7 +503,7 @@ static int handle_perm_err_exit_end(Tracee *tracee, Config *config) { #ifdef USERLAND /** If the call has been set to PR_void, it "succeeded" in - * altering a meta file correctly. + * altering a meta info correctly. */ if(get_sysnum(tracee, CURRENT) == PR_getuid && (int) result != 0) poke_reg(tracee, SYSARG_RESULT, 0); @@ -646,22 +646,6 @@ static int handle_sysenter_end(Tracee *tracee, Config *config) case PR_execve: return handle_exec_enter_end(tracee, SYSARG_1, config); - /* handle_link(tracee, olddirfd_sysarg, oldpath_sysarg, newdirfd_sysarg, newpath_sysarg, config) */ - /* int link(const char *oldpath, const char *newpath) */ - case PR_link: - return handle_link_enter_end(tracee, IGNORE_SYSARG, SYSARG_1, IGNORE_SYSARG, SYSARG_2, config); - /* int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) */ - case PR_linkat: - return handle_link_enter_end(tracee, SYSARG_1, SYSARG_2, SYSARG_3, SYSARG_4, config); - - /* handle_symlink(tracee, oldpath_sysarg, newdirfd_sysarg, newpath_sysarg, config) */ - /* int symlink(const char *target, const char *linkpath); */ - case PR_symlink: - return handle_symlink_enter_end(tracee, SYSARG_1, IGNORE_SYSARG, SYSARG_2, config); - /* int symlinkat(const char *target, int newdirfd, const char *linkpath); */ - case PR_symlinkat: - return handle_symlink_enter_end(tracee, SYSARG_1, SYSARG_2, SYSARG_3, config); - /* int fstat(int fd, struct stat *buf); */ case PR_fstat: case PR_fstat64: @@ -818,6 +802,35 @@ static int handle_sysexit_end(Tracee *tracee, Config *config) switch (sysnum) { +#ifdef USERLAND + /* handle_open(tracee, fd_sysarg, path_sysarg, flags_sysarg, mode_sysarg, config) */ + /* int openat(int dirfd, const char *pathname, int flags, mode_t mode) */ + case PR_openat: + return handle_open_exit_end(tracee, SYSARG_2, SYSARG_3, SYSARG_4, config); + /* int open(const char *pathname, int flags, mode_t mode) */ + case PR_open: + return handle_open_exit_end(tracee, SYSARG_1, SYSARG_2, SYSARG_3, config); + /* int creat(const char *pathname, mode_t mode) */ + case PR_creat: + return handle_open_exit_end(tracee, SYSARG_1, IGNORE_SYSARG, SYSARG_2, config); + + /* handle_mk(tracee, fd_sysarg, path_sysarg, mode_sysarg, config) */ + /* int mkdirat(int dirfd, const char *pathname, mode_t mode) */ + case PR_mkdirat: + return handle_mk_exit_end(tracee, SYSARG_2, SYSARG_3, config); + /* int mkdir(const char *pathname, mode_t mode) */ + case PR_mkdir: + return handle_mk_exit_end(tracee, SYSARG_1, SYSARG_2, config); + + /* handle_mk(tracee, fd_sysarg, path_sysarg, mode_sysarg, config) */ + /* int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev); */ + case PR_mknodat: + return handle_mk_exit_end(tracee, SYSARG_2, SYSARG_3, config); + /* int mknod(const char *pathname, mode_t mode, dev_t dev); */ + case PR_mknod: + return handle_mk_exit_end(tracee, SYSARG_1, SYSARG_2, config); +#endif + case PR_setuid: case PR_setuid32: SETXID(uid, ORIGINAL); @@ -898,9 +911,9 @@ static int handle_sysexit_end(Tracee *tracee, Config *config) #ifndef USERLAND case PR_setgroups: case PR_setgroups32: -#endif case PR_mknod: case PR_mknodat: +#endif case PR_capset: case PR_setxattr: case PR_lsetxattr: @@ -951,45 +964,6 @@ static int handle_sysexit_end(Tracee *tracee, Config *config) case PR_getsockopt: return handle_getsockopt_exit_end(tracee); -#ifdef USERLAND -/** Check to see if a meta was created for a file that no longer exists. - * If so, delete it. - */ - case PR_open: - case PR_openat: - case PR_creat: { - int status; - Reg sysarg; - char path[PATH_MAX]; - char meta_path[PATH_MAX]; - - if(sysnum == PR_open || sysnum == PR_creat) - sysarg = SYSARG_1; - else - sysarg = SYSARG_2; - - status = read_sysarg_path(tracee, path, sysarg, MODIFIED); - if(status < 0) - return status; - if(status == 1) - return 0; - - /* If the file exists, it doesn't matter if a metafile exists. */ - if(path_exists(path) == 0) - return 0; - - status = get_meta_path(path, meta_path); - if(status < 0) - return status; - - /* If the metafile exists and the original file does not, delete it. */ - if(path_exists(meta_path) == 0) - status = unlink(meta_path); - - return 0; - } -#endif - default: return 0; } @@ -1079,6 +1053,8 @@ int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t data1 Config *config; int uid, gid; + meta_initialized = false; + errno = 0; uid = strtol(uid_string, NULL, 10); if (errno != 0) @@ -1183,21 +1159,7 @@ int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t data1 } case LINK2SYMLINK_UNLINK: { - int status; - char meta_path[PATH_MAX]; - - status = get_meta_path((char *) data1, meta_path); - if(status < 0) - return status; - - /* If metafile doesn't already exist, get out */ - if(path_exists(meta_path) != 0) - return 0; - - status = unlink(meta_path); - if(status < 0) - return status; - + delete_meta_info((char *) data1); return 0; } #endif @@ -1206,6 +1168,13 @@ int fake_id0_callback(Extension *extension, ExtensionEvent event, intptr_t data1 Tracee *tracee = TRACEE(extension); Config *config = talloc_get_type_abort(extension->config, Config); +#ifdef USERLAND + if (!meta_initialized) { + init_meta_hash(tracee); + meta_initialized = true; + } +#endif + return handle_sysenter_end(tracee, config); } diff --git a/src/extension/fake_id0/helper_functions.c b/src/extension/fake_id0/helper_functions.c index 2b2758f3..961fc282 100644 --- a/src/extension/fake_id0/helper_functions.c +++ b/src/extension/fake_id0/helper_functions.c @@ -4,7 +4,11 @@ #include #include #include +#include +#include +#include +#include "cli/note.h" #include "syscall/syscall.h" #include "syscall/sysnum.h" #include "tracee/tracee.h" @@ -20,6 +24,15 @@ #define GROUP_PERMS 1 #define OTHER_PERMS 2 +#ifndef DB_PATH +#define DB_PATH "/support/meta_db" +#endif + +leveldb_t *db; +leveldb_options_t *options; +leveldb_readoptions_t *roptions; +leveldb_writeoptions_t *woptions; + /** Converts a decimal number to its octal representation. Used to convert * system returned modes to a more common form for humans. */ @@ -171,7 +184,7 @@ char * get_name(char path[PATH_MAX]) /** Returns the mode pertinent to the level of permissions the user has. Eg if * uid 1000 tries to access a file it owns with mode 751, this returns 7. */ -int get_permissions(char meta_path[PATH_MAX], Config *config, bool uses_real) +int get_permissions(char path[PATH_MAX], Config *config, bool uses_real) { int perms; int omode; @@ -179,17 +192,15 @@ int get_permissions(char meta_path[PATH_MAX], Config *config, bool uses_real) uid_t owner, emulated_uid; gid_t group, emulated_gid; - int status = read_meta_file(meta_path, &mode, &owner, &group, config); - if(status < 0) - return status; + read_meta_info(path, &mode, &owner, &group, config); - if(uses_real) { + if (uses_real) { emulated_uid = config->ruid; emulated_gid = config->rgid; - } - else + } else { emulated_uid = config->euid; emulated_gid = config->egid; + } if (emulated_uid == owner || emulated_uid == 0) perms = OWNER_PERMS; @@ -224,18 +235,14 @@ int get_permissions(char meta_path[PATH_MAX], Config *config, bool uses_real) */ int check_dir_perms(Tracee *tracee, char type, char path[PATH_MAX], char rel_path[PATH_MAX], Config *config) { - int status, perms; - char meta_path[PATH_MAX]; + int perms; char shorten_path[PATH_MAX]; int x = 1; int w = 2; get_dir_path(path, shorten_path); - status = get_meta_path(shorten_path, meta_path); - if(status < 0) - return status; - perms = get_permissions(meta_path, config, 0); + perms = get_permissions(shorten_path, config, 0); if(type == 'w' && (perms & w) != w) return -EACCES; @@ -248,14 +255,9 @@ int check_dir_perms(Tracee *tracee, char type, char path[PATH_MAX], char rel_pat if(!belongs_to_guestfs(tracee, shorten_path)) break; - status = get_meta_path(shorten_path, meta_path); - if(status < 0) - return status; - - perms = get_permissions(meta_path, config, 0); + perms = get_permissions(shorten_path, config, 0); if((perms & x) != x) return -EACCES; - } return 0; @@ -308,44 +310,102 @@ int get_meta_path(char orig_path[PATH_MAX], char meta_path[PATH_MAX]) return 0; } +void init_meta_hash(Tracee *tracee) { + char db_path[PATH_MAX]; + char *err = NULL; + int status; + + status = translate_path(tracee, db_path, AT_FDCWD, DB_PATH, false); + if (status < 0) + return; + + options = leveldb_options_create(); + leveldb_options_set_create_if_missing(options, 1); + db = leveldb_open(options, db_path, &err); + + if (err != NULL) { + VERBOSE(tracee, 2, "Failed to open Meta DB: %s", err); + } else { + VERBOSE(tracee, 9, "Succeeded to open Meta DB."); + } + + /* reset error var */ + leveldb_free(err); err = NULL; + + woptions = leveldb_writeoptions_create(); + roptions = leveldb_readoptions_create(); +} + /** Stores in mode, owner, and group the relative information found in the meta - * meta file. If the meta file doesn't exist, it reverts back to the original + * info. If the meta info doesn't exist, it reverts back to the original * functionality of PRoot, with the addition of setting the mode to 755. */ -int read_meta_file(char path[PATH_MAX], mode_t *mode, uid_t *owner, gid_t *group, Config *config) +int read_meta_info(char path[PATH_MAX], mode_t *mode, uid_t *owner, gid_t *group, Config *config) { FILE *fp; int lcl_mode; - fp = fopen(path, "r"); - if(!fp) { + int status; + char meta_path[PATH_MAX]; + struct stat statBuf; + size_t read_len; + struct stat *hash_read_value; + char* err = NULL; + ino_t addr; + Tracee *tracee = NULL; + + status = lstat(path, &statBuf); + + addr = statBuf.st_ino; + if ((status == 0) && (addr > 0)) { + hash_read_value = (struct stat *)leveldb_get(db, roptions, (char *)&addr, sizeof(ino_t), &read_len, &err); + + if (err != NULL) { + read_len = 0; + VERBOSE(tracee, 2, "Meta DB read failed: %s", err); + } + + leveldb_free(err); err = NULL; + } + + if ((status == 0) && (read_len > 0) && (addr > 0)) { + *mode = hash_read_value->st_mode; + *owner = hash_read_value->st_uid; + *group = hash_read_value->st_gid; + return 0; + } + + status = get_meta_path(path, meta_path); + fp = fopen(meta_path, "r"); + if(!fp || (status < 0)) { /* If the metafile doesn't exist, allow overly permissive behavior. */ *owner = config->euid; *group = config->egid; - *mode = otod(755); + *mode = otod(777); return 0; - } fscanf(fp, "%d %d %d ", &lcl_mode, owner, group); - lcl_mode = otod(lcl_mode); - *mode = (mode_t)lcl_mode; + *mode = otod(lcl_mode); + write_meta_info(path, *mode, *owner, *group, false, config); + unlink(meta_path); fclose(fp); + return 0; } -/** Writes mode, owner, and group to the meta file specified by path. If +/** Writes mode, owner, and group to the meta info specified by path. If * is_creat is set to true, the umask needs to be used since it would have * been by a real system call. */ - -int write_meta_file(char path[PATH_MAX], mode_t mode, uid_t owner, gid_t group, +int write_meta_info(char path[PATH_MAX], mode_t mode, uid_t owner, gid_t group, bool is_creat, Config *config) { - FILE *fp; - fp = fopen(path, "w"); - if(!fp) - //Errno is set - return -1; + struct stat statBuf; + int status; + struct stat *ht_value; + char* err = NULL; + ino_t addr; + Tracee *tracee = NULL; /** In syscalls that don't have the ability to create a file (chmod v open) * for example, the umask isn't used in determining the permissions of the @@ -354,8 +414,54 @@ int write_meta_file(char path[PATH_MAX], mode_t mode, uid_t owner, gid_t group, if(is_creat) mode = (mode & ~(config->umask) & 0777); - fprintf(fp, "%d\n%d\n%d\n", dtoo(mode), owner, group); - fclose(fp); + status = lstat(path, &statBuf); + addr = statBuf.st_ino; + + if ((status == 0) && (addr > 0)) { + ht_value = malloc(sizeof(struct stat)); + ht_value->st_mode = mode; + ht_value->st_uid = owner; + ht_value->st_gid = group; + leveldb_put(db, woptions, (char *)&addr, sizeof(ino_t), (char *)ht_value, sizeof(struct stat), &err); + if (err != NULL) { + VERBOSE(tracee, 2, "Meta DB write failed: %s", err); + } + leveldb_free(err); err = NULL; + } + + return 0; +} + +/* + * Deletes meta info based on path + */ +int delete_meta_info(char path[PATH_MAX]) { + int status; + char meta_path[PATH_MAX]; + char* err = NULL; + Tracee *tracee = NULL; + struct stat statBuf; + ino_t addr; + + status = stat(path, &statBuf); + addr = statBuf.st_ino; + + if ((status == 0) && (addr > 0)) { + leveldb_delete(db, woptions, (char *)&addr, sizeof(ino_t), &err); + if (err != NULL) { + VERBOSE(tracee, 2, "Meta DB delete failed."); + } + leveldb_free(err); err = NULL; + } + + status = get_meta_path(path, meta_path); + if(status < 0) + return 0; + + /* If metafile exists, delete it */ + if(path_exists(meta_path)) + unlink(meta_path); + return 0; } diff --git a/src/extension/fake_id0/helper_functions.h b/src/extension/fake_id0/helper_functions.h index a7dadda0..9fccd449 100644 --- a/src/extension/fake_id0/helper_functions.h +++ b/src/extension/fake_id0/helper_functions.h @@ -18,9 +18,13 @@ int otod(int n); int get_meta_path(char orig_path[PATH_MAX], char meta_path[PATH_MAX]); -int read_meta_file(char path[PATH_MAX], mode_t *mode, uid_t *owner, gid_t *group, Config *config); +void init_meta_hash(); -int write_meta_file(char path[PATH_MAX], mode_t mode, uid_t owner, gid_t group, bool is_creat, Config *config); +int read_meta_info(char path[PATH_MAX], mode_t *mode, uid_t *owner, gid_t *group, Config *config); + +int write_meta_info(char path[PATH_MAX], mode_t mode, uid_t owner, gid_t group, bool is_creat, Config *config); + +int delete_meta_info(char path[PATH_MAX]); char * get_name(char path[PATH_MAX]); diff --git a/src/extension/fake_id0/link.c b/src/extension/fake_id0/link.c deleted file mode 100644 index ef984691..00000000 --- a/src/extension/fake_id0/link.c +++ /dev/null @@ -1,49 +0,0 @@ -#include - -#include "extension/fake_id0/link.h" - -#include "extension/fake_id0/helper_functions.h" - -/** Handles link and linkat. Returns -EACCES if search permission is not - * given for the entire relative oldpath and the entire relative newpath - * except where write permission is needed (on the final directory component). - */ -int handle_link_enter_end(Tracee *tracee, Reg olddirfd_sysarg, Reg oldpath_sysarg, - Reg newdirfd_sysarg, Reg newpath_sysarg, Config *config) -{ - int status; - char oldpath[PATH_MAX]; - char rel_oldpath[PATH_MAX]; - char newpath[PATH_MAX]; - char rel_newpath[PATH_MAX]; - - status = read_sysarg_path(tracee, oldpath, oldpath_sysarg, ORIGINAL); - if(status < 0) - return status; - if(status == 1) - return 0; - - status = read_sysarg_path(tracee, newpath, newpath_sysarg, ORIGINAL); - if(status < 0) - return status; - if(status == 1) - return 0; - - status = get_fd_path(tracee, rel_oldpath, olddirfd_sysarg, ORIGINAL); - if(status < 0) - return status; - - status = get_fd_path(tracee, rel_newpath, newdirfd_sysarg, ORIGINAL); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'r', oldpath, rel_oldpath, config); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'w', newpath, rel_newpath, config); - if(status < 0) - return status; - - return 0; -} diff --git a/src/extension/fake_id0/mk.c b/src/extension/fake_id0/mk.c index 082aa060..c4cbb989 100644 --- a/src/extension/fake_id0/mk.c +++ b/src/extension/fake_id0/mk.c @@ -4,8 +4,8 @@ #include "extension/fake_id0/helper_functions.h" -/** Handles mkdir, mkdirat, mknod, and mknodat syscalls. Creates a matching - * meta file. See mkdir(2) and mknod(2) for returned permission errors. +/** Handles mkdir, mkdirat, mknod, and mknodat syscalls. Creates matching + * meta info. See mkdir(2) and mknod(2) for returned permission errors. */ int handle_mk_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, Reg mode_sysarg, Config *config) @@ -13,8 +13,6 @@ int handle_mk_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, int status; mode_t mode; char orig_path[PATH_MAX]; - char rel_path[PATH_MAX]; - char meta_path[PATH_MAX]; status = read_sysarg_path(tracee, orig_path, path_sysarg, CURRENT); if(status < 0) @@ -23,22 +21,45 @@ int handle_mk_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, return 0; /* If the path exists, get out. The syscall itself will return EEXIST. */ - if(path_exists(orig_path) == 0) + if(path_exists(orig_path)) { + tracee->already_exists = true; + } else { + tracee->already_exists = false; return 0; + } - status = get_meta_path(orig_path, meta_path); + mode = peek_reg(tracee, ORIGINAL, mode_sysarg); + poke_reg(tracee, mode_sysarg, (mode|0700)); + return 0; +} + +/** Handles mkdir, mkdirat, mknod, and mknodat syscalls. Creates matching + * meta info. See mkdir(2) and mknod(2) for returned permission errors. + */ +int handle_mk_exit_end(Tracee *tracee, Reg path_sysarg, + Reg mode_sysarg, Config *config) +{ + int status; + mode_t mode; + char orig_path[PATH_MAX]; + word_t result; + + //only matters if it succeeded + result = peek_reg(tracee, CURRENT, SYSARG_RESULT); + if (result != 0) + return 0; + + status = read_sysarg_path(tracee, orig_path, path_sysarg, CURRENT); if(status < 0) return status; + if(status == 1) + return 0; + + /* If the file already existed get out*/ + if(tracee->already_exists) + return 0; - status = get_fd_path(tracee, rel_path, fd_sysarg, CURRENT); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'w', orig_path, rel_path, config); - if(status < 0) - return status; - mode = peek_reg(tracee, ORIGINAL, mode_sysarg); poke_reg(tracee, mode_sysarg, (mode|0700)); - return write_meta_file(meta_path, mode, config->euid, config->egid, 1, config); + return write_meta_info(orig_path, mode, config->euid, config->egid, 1, config); } diff --git a/src/extension/fake_id0/mk.h b/src/extension/fake_id0/mk.h index cd426c0d..0a7b0c65 100644 --- a/src/extension/fake_id0/mk.h +++ b/src/extension/fake_id0/mk.h @@ -6,5 +6,6 @@ #include "extension/fake_id0/config.h" int handle_mk_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, Reg mode_sysarg, Config *config); +int handle_mk_exit_end(Tracee *tracee, Reg path_sysarg, Reg mode_sysarg, Config *config); #endif /* FAKE_ID0_MK_H */ diff --git a/src/extension/fake_id0/open.c b/src/extension/fake_id0/open.c index 066acf6a..faa73574 100644 --- a/src/extension/fake_id0/open.c +++ b/src/extension/fake_id0/open.c @@ -9,9 +9,9 @@ #include "extension/fake_id0/open.h" #include "extension/fake_id0/helper_functions.h" -/** Handles open, openat, and creat syscalls. Creates meta files to match the - * creation of new files, or checks the permissions of files that already - * exist given a matching meta file. See open(2) for returned permission +/** Handles open, openat, and creat syscalls. + * Checks the permissions of files that already + * exist given matching meta info. See open(2) for returned permission * errors. */ int handle_open_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, @@ -19,8 +19,6 @@ int handle_open_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, { int status, perms, access_mode; char orig_path[PATH_MAX]; - char rel_path[PATH_MAX]; - char meta_path[PATH_MAX]; word_t flags; mode_t mode; @@ -30,58 +28,32 @@ int handle_open_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, if(status == 1) return 0; - status = get_meta_path(orig_path, meta_path); - if(status < 0) - return status; - + if(path_exists(orig_path) == 0) + tracee->already_exists = true; + else + tracee->already_exists = false; + if(flags_sysarg != IGNORE_SYSARG) flags = peek_reg(tracee, ORIGINAL, flags_sysarg); else flags = O_CREAT; - /* If the metafile doesn't exist and we aren't creating a new file, get out. */ - if(path_exists(meta_path) != 0 && (flags & O_CREAT) != O_CREAT) + /* If the file doesn't exist and we aren't creating a new file, get out. */ + if(path_exists(orig_path) != 0 && (flags & O_CREAT) != O_CREAT) return 0; - status = get_fd_path(tracee, rel_path, fd_sysarg, CURRENT); - if(status < 0) - return status; - - /** If the open call is a creat call (flags is set to IGNORE_SYSARG in - * handle_sysenter_end) or an open call intended to create a new file - * then we write a new meta file to match. Note that flags is compared - * only to O_CREAT because some utilities (like touch) do not - * use O_TRUNC and O_WRONLY and instead incorporate other flags. - * A value in flags_sysarg of IGNORE_SYSARG signifies a creat(2) call. - */ if((flags & O_CREAT) == O_CREAT) { - - /** Many open calls include O_CREAT flags even if the file exists - * already. Probably because many things don't check existence and - * just tell open to create a file if it doesn't exist. In the cases - * a file does exist already, the permissions of it still need to be - * checked. - */ if(path_exists(orig_path) == 0) goto check; - status = check_dir_perms(tracee, 'w', meta_path, rel_path, config); - if(status < 0) - return status; - mode = peek_reg(tracee, ORIGINAL, mode_sysarg); poke_reg(tracee, mode_sysarg, (mode|0700)); - status = write_meta_file(meta_path, mode, config->euid, config->egid, 1, config); - return status; + return 0; } check: - - status = check_dir_perms(tracee, 'r', meta_path, rel_path, config); - if(status < 0) - return status; - perms = get_permissions(meta_path, config, 0); + perms = get_permissions(orig_path, config, 0); access_mode = (flags & O_ACCMODE); /* 0 = RDONLY, 1 = WRONLY, 2 = RDWR */ @@ -94,3 +66,39 @@ int handle_open_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, return 0; } +/** Handles open, openat, and creat syscalls. Creates meta info to match the + * creation of new files. + */ +int handle_open_exit_end(Tracee *tracee, Reg path_sysarg, + Reg flags_sysarg, Reg mode_sysarg, Config *config) +{ + int status; + char orig_path[PATH_MAX]; + word_t flags; + mode_t mode; + word_t result; + + //only matters if it succeeded + result = peek_reg(tracee, CURRENT, SYSARG_RESULT); + if (result & ((word_t)1 << (sizeof(word_t)*8 - 1))) + return 0; + + status = read_sysarg_path(tracee, orig_path, path_sysarg, MODIFIED); + if(status < 0) + return status; + if(status == 1) + return 0; + + if(flags_sysarg != IGNORE_SYSARG) + flags = peek_reg(tracee, ORIGINAL, flags_sysarg); + else + flags = O_CREAT; + + /* If the file already existed or we aren't creating a new file, get out. */ + if(tracee->already_exists || ((flags & O_CREAT) != O_CREAT)) + return 0; + + mode = peek_reg(tracee, ORIGINAL, mode_sysarg); + return write_meta_info(orig_path, mode, config->euid, config->egid, 1, config); +} + diff --git a/src/extension/fake_id0/open.h b/src/extension/fake_id0/open.h index abac2e34..d6af6377 100644 --- a/src/extension/fake_id0/open.h +++ b/src/extension/fake_id0/open.h @@ -6,5 +6,6 @@ #include "extension/fake_id0/config.h" int handle_open_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, Reg flags_sysarg, Reg mode_sysarg, Config *config); +int handle_open_exit_end(Tracee *tracee, Reg path_sysarg, Reg flags_sysarg, Reg mode_sysarg, Config *config); #endif /* FAKE_ID0_OPEN_H */ diff --git a/src/extension/fake_id0/rename.c b/src/extension/fake_id0/rename.c index 47b517c7..8833206c 100644 --- a/src/extension/fake_id0/rename.c +++ b/src/extension/fake_id0/rename.c @@ -5,8 +5,8 @@ #include "extension/fake_id0/rename.h" #include "extension/fake_id0/helper_functions.h" -/** Handles rename and renameat syscalls. If a meta file matching the file to - * to be renamed exists, renames the meta file as well. See rename(2) for +/** Handles rename and renameat syscalls. + * Check permissions of whether a rename is allowed. See rename(2) for * returned permission errors. */ int handle_rename_enter_end(Tracee *tracee, Reg oldfd_sysarg, Reg oldpath_sysarg, @@ -17,10 +17,6 @@ int handle_rename_enter_end(Tracee *tracee, Reg oldfd_sysarg, Reg oldpath_sysarg gid_t gid; mode_t mode; char oldpath[PATH_MAX]; - char newpath[PATH_MAX]; - char rel_oldpath[PATH_MAX]; - char rel_newpath[PATH_MAX]; - char meta_path[PATH_MAX]; status = read_sysarg_path(tracee, oldpath, oldpath_sysarg, CURRENT); if(status < 0) @@ -28,43 +24,9 @@ int handle_rename_enter_end(Tracee *tracee, Reg oldfd_sysarg, Reg oldpath_sysarg if(status == 1) return 0; - status = read_sysarg_path(tracee, newpath, newpath_sysarg, CURRENT); - if(status < 0) - return status; - if(status == 1) - return 0; - - status = get_fd_path(tracee, rel_oldpath, oldfd_sysarg, CURRENT); - if(status < 0) - return status; - - status = get_fd_path(tracee, rel_newpath, newfd_sysarg, CURRENT); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'w', oldpath, rel_oldpath, config); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'w', newpath, rel_newpath, config); - if(status < 0) - return status; - - // If a meta file exists, "copy" it to the new path. - status = get_meta_path(oldpath, meta_path); - if(status < 0) - return status; - - if(path_exists(meta_path) != 0) - return 0; - - read_meta_file(meta_path, &mode, &uid, &gid, config); - unlink(meta_path); + //only read the meta info, so it can delete the meta file if it exists + //TODO: Remove once there are no more meta files out there + read_meta_info(oldpath, &mode, &uid, &gid, config); - strcpy(meta_path, ""); - status = get_meta_path(newpath, meta_path); - if(status < 0) - return status; - - return write_meta_file(meta_path, mode, uid, gid, 0, config); + return 0; } diff --git a/src/extension/fake_id0/stat.c b/src/extension/fake_id0/stat.c index 42a16b01..bf7b2bc3 100644 --- a/src/extension/fake_id0/stat.c +++ b/src/extension/fake_id0/stat.c @@ -80,7 +80,6 @@ int handle_stat_exit_end(Tracee *tracee, Config *config, word_t sysnum) { mode_t mode; struct stat my_stat; char path[PATH_MAX]; - char meta_path[PATH_MAX]; word_t result; /* Override only if it succeed. */ @@ -107,26 +106,20 @@ int handle_stat_exit_end(Tracee *tracee, Config *config, word_t sysnum) { if(status == 1) goto fallback; - /** If the meta file exists, read the data from it and replace it the + /** If meta info exists, read the data from it and replace the * relevant data in the stat structure. */ - - status = get_meta_path(path, meta_path); - if(status == 0) { - status = path_exists(meta_path); - if(status == 0) { - read_meta_file(meta_path, &mode, &uid, &gid, config); - - /** Get the file type and sticky/set-id bits of the original - * file and add them to the mode found in the meta_file. - */ - read_data(tracee, &my_stat, peek_reg(tracee, ORIGINAL, sysarg), sizeof(struct stat)); - my_stat.st_mode = (mode | ((my_stat.st_mode & S_IFMT) | (my_stat.st_mode & 07000))); - my_stat.st_uid = uid; - my_stat.st_gid = gid; - write_data(tracee, peek_reg(tracee, ORIGINAL, sysarg), &my_stat, sizeof(struct stat)); - return 0; - } + status = read_meta_info(path, &mode, &uid, &gid, config); + if (status == 0) { + /** Get the file type and sticky/set-id bits of the original + * file and add them to the mode from the meta info. + */ + read_data(tracee, &my_stat, peek_reg(tracee, ORIGINAL, sysarg), sizeof(struct stat)); + my_stat.st_mode = (mode | ((my_stat.st_mode & S_IFMT) | (my_stat.st_mode & 07000))); + my_stat.st_uid = uid; + my_stat.st_gid = gid; + write_data(tracee, peek_reg(tracee, ORIGINAL, sysarg), &my_stat, sizeof(struct stat)); + return 0; } fallback: diff --git a/src/extension/fake_id0/symlink.c b/src/extension/fake_id0/symlink.c deleted file mode 100644 index 08e1e1d0..00000000 --- a/src/extension/fake_id0/symlink.c +++ /dev/null @@ -1,38 +0,0 @@ -#include - -#include "extension/fake_id0/rename.h" -#include "extension/fake_id0/helper_functions.h" - -/** Handles symlink and symlinkat syscalls. Returns -EACCES if search - * permission is not found for the directories except the final in newpath. - * Write permission is required for that directory. Unlike with link(2), - * symlink does not require permissions on the original path. - */ -int handle_symlink_enter_end(Tracee *tracee, Reg oldpath_sysarg, - Reg newdirfd_sysarg, Reg newpath_sysarg, Config *config) -{ - int status; - char oldpath[PATH_MAX]; - char newpath[PATH_MAX]; - char rel_newpath[PATH_MAX]; - - status = read_sysarg_path(tracee, oldpath, oldpath_sysarg, CURRENT); - if(status < 0) - return status; - - status = read_sysarg_path(tracee, newpath, newpath_sysarg, CURRENT); - if(status < 0) - return status; - if(status == 1) - return 0; - - status = get_fd_path(tracee, rel_newpath, newdirfd_sysarg, CURRENT); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'w', newpath, rel_newpath, config); - if(status < 0) - return status; - - return 0; -} diff --git a/src/extension/fake_id0/unlink.c b/src/extension/fake_id0/unlink.c index 5f0d0c8f..3d04c2b0 100644 --- a/src/extension/fake_id0/unlink.c +++ b/src/extension/fake_id0/unlink.c @@ -5,40 +5,22 @@ #include "extension/fake_id0/helper_functions.h" /** Handles unlink, unlinkat, and rmdir syscalls. Checks permissions in meta - * files matching the file to be unlinked if the meta file exists. Unlinks - * the meta file if the call would be successful. See unlink(2) and rmdir(2) + * files matching the file to be unlinked if meta info exists. Deletes + * the meta info if the call would be successful. See unlink(2) and rmdir(2) * for returned errors. */ int handle_unlink_enter_end(Tracee *tracee, Reg fd_sysarg, Reg path_sysarg, Config *config) { int status; char orig_path[PATH_MAX]; - char rel_path[PATH_MAX]; - char meta_path[PATH_MAX]; - + status = read_sysarg_path(tracee, orig_path, path_sysarg, CURRENT); if(status < 0) return status; if(status == 1) return 0; - status = get_meta_path(orig_path, meta_path); - if(status < 0) - return status; - - status = get_fd_path(tracee, rel_path, fd_sysarg, CURRENT); - if(status < 0) - return status; - - status = check_dir_perms(tracee, 'w', orig_path, rel_path, config); - if(status < 0) - return status; - - /** If the meta_file relating to the file being unlinked exists, - * unlink that as well. - */ - if(path_exists(meta_path) == 0) - unlink(meta_path); + delete_meta_info(orig_path); return 0; } diff --git a/src/extension/fake_id0/utimensat.c b/src/extension/fake_id0/utimensat.c index 288fe605..bd389bca 100644 --- a/src/extension/fake_id0/utimensat.c +++ b/src/extension/fake_id0/utimensat.c @@ -8,7 +8,7 @@ #include "extension/fake_id0/utimensat.h" #include "extension/fake_id0/helper_functions.h" -/** Handles the utimensat syscall. Checks permissions of the meta file if it +/** Handles the utimensat syscall. Checks permissions from the meta info if it * exists and returns an error if the call would not pass according to the * errors found in utimensat(2). */ @@ -21,7 +21,6 @@ int handle_utimensat_enter_end(Tracee *tracee, Reg dirfd_sysarg, uid_t owner; gid_t ignore_g; char path[PATH_MAX]; - char meta_path[PATH_MAX]; // Only care about calls that attempt to change something. status = peek_reg(tracee, ORIGINAL, times_sysarg); @@ -45,17 +44,13 @@ int handle_utimensat_enter_end(Tracee *tracee, Reg dirfd_sysarg, return status; } - status = get_meta_path(path, meta_path); - if(status < 0) - return status; - // Current user must be owner of file or root. - read_meta_file(meta_path, &ignore_m, &owner, &ignore_g, config); + read_meta_info(path, &ignore_m, &owner, &ignore_g, config); if(config->euid != owner && config->euid != 0) return -EACCES; // If write permissions are on the file, continue. - perms = get_permissions(meta_path, config, 0); + perms = get_permissions(path, config, 0); if((perms & 2) != 2) return -EACCES; diff --git a/src/tracee/tracee.h b/src/tracee/tracee.h index 0fc57696..1099103d 100644 --- a/src/tracee/tracee.h +++ b/src/tracee/tracee.h @@ -287,6 +287,9 @@ typedef struct tracee { /* For diagnostic purpose. */ const char *tool_name; + /*For knowing when to create a new meta entry*/ + bool already_exists; + } Tracee; #define HOST_ROOTFS "/host-rootfs"