X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fcommon%2Frunas.c;h=bba0aa49d47292d383dd7e09b968779168bc8d44;hb=0731b11e5e0022379ca462b574743197c48cfa25;hp=33462958f2e4b85b66976495b17873c2ce71ef1a;hpb=8fec83ea731aa3b4d279d51c378a931fe48f6a23;p=lttng-tools.git diff --git a/src/common/runas.c b/src/common/runas.c index 33462958f..bba0aa49d 100644 --- a/src/common/runas.c +++ b/src/common/runas.c @@ -49,7 +49,7 @@ struct run_as_data; struct run_as_ret; typedef int (*run_as_fct)(struct run_as_data *data, struct run_as_ret *ret_value); -struct run_as_mkdir_data { +struct run_as_mkdirat_data { char path[PATH_MAX]; mode_t mode; }; @@ -77,7 +77,7 @@ struct run_as_extract_sdt_probe_offsets_data { char provider_name[LTTNG_SYMBOL_NAME_LEN]; }; -struct run_as_mkdir_ret { +struct run_as_mkdirat_ret { int ret; }; @@ -104,10 +104,12 @@ struct run_as_extract_sdt_probe_offsets_ret { enum run_as_cmd { RUN_AS_MKDIR, + RUN_AS_MKDIRAT, + RUN_AS_MKDIR_RECURSIVE, + RUN_AS_MKDIRAT_RECURSIVE, RUN_AS_OPEN, RUN_AS_UNLINK, RUN_AS_RMDIR_RECURSIVE, - RUN_AS_MKDIR_RECURSIVE, RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET, RUN_AS_EXTRACT_SDT_PROBE_OFFSETS, }; @@ -116,7 +118,7 @@ struct run_as_data { enum run_as_cmd cmd; int fd; union { - struct run_as_mkdir_data mkdir; + struct run_as_mkdirat_data mkdirat; struct run_as_open_data open; struct run_as_unlink_data unlink; struct run_as_rmdir_recursive_data rmdir_recursive; @@ -145,7 +147,7 @@ struct run_as_data { struct run_as_ret { int fd; union { - struct run_as_mkdir_ret mkdir; + struct run_as_mkdirat_ret mkdirat; struct run_as_open_ret open; struct run_as_unlink_ret unlink; struct run_as_rmdir_recursive_ret rmdir_recursive; @@ -181,35 +183,49 @@ int use_clone(void) } #endif -LTTNG_HIDDEN -int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode); - /* * Create recursively directory using the FULL path. */ static -int _mkdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value) +int _mkdirat_recursive(struct run_as_data *data, struct run_as_ret *ret_value) { const char *path; mode_t mode; + struct lttng_directory_handle handle; - path = data->u.mkdir.path; - mode = data->u.mkdir.mode; + path = data->u.mkdirat.path; + mode = data->u.mkdirat.mode; + (void) lttng_directory_handle_init_from_dirfd(&handle, data->fd); /* Safe to call as we have transitioned to the requested uid/gid. */ - ret_value->u.mkdir.ret = _utils_mkdir_recursive_unsafe(path, mode); + ret_value->u.mkdirat.ret = + lttng_directory_handle_create_subdirectory_recursive( + &handle, path, mode); ret_value->_errno = errno; - ret_value->_error = (ret_value->u.mkdir.ret) ? true : false; - return ret_value->u.mkdir.ret; + ret_value->_error = (ret_value->u.mkdirat.ret) ? true : false; + lttng_directory_handle_fini(&handle); + return ret_value->u.mkdirat.ret; } static -int _mkdir(struct run_as_data *data, struct run_as_ret *ret_value) +int _mkdirat(struct run_as_data *data, struct run_as_ret *ret_value) { - ret_value->u.mkdir.ret = mkdir(data->u.mkdir.path, data->u.mkdir.mode); + const char *path; + mode_t mode; + struct lttng_directory_handle handle; + + path = data->u.mkdirat.path; + mode = data->u.mkdirat.mode; + + (void) lttng_directory_handle_init_from_dirfd(&handle, data->fd); + /* Safe to call as we have transitioned to the requested uid/gid. */ + ret_value->u.mkdirat.ret = + lttng_directory_handle_create_subdirectory( + &handle, path, mode); ret_value->_errno = errno; - ret_value->_error = (ret_value->u.mkdir.ret) ? true : false; - return ret_value->u.mkdir.ret; + ret_value->_error = (ret_value->u.mkdirat.ret) ? true : false; + lttng_directory_handle_fini(&handle); + return ret_value->u.mkdirat.ret; } static @@ -218,7 +234,7 @@ int _open(struct run_as_data *data, struct run_as_ret *ret_value) ret_value->u.open.ret = open(data->u.open.path, data->u.open.flags, data->u.open.mode); ret_value->fd = ret_value->u.open.ret; ret_value->_errno = errno; - ret_value->_error = (ret_value->u.open.ret) ? true : false; + ret_value->_error = ret_value->u.open.ret < 0; return ret_value->u.open.ret; } @@ -240,6 +256,7 @@ int _rmdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value) return ret_value->u.rmdir_recursive.ret; } +#ifdef HAVE_ELF_H static int _extract_elf_symbol_offset(struct run_as_data *data, struct run_as_ret *ret_value) @@ -298,21 +315,40 @@ free_offset: end: return ret; } +#else +static +int _extract_elf_symbol_offset(struct run_as_data *data, + struct run_as_ret *ret_value) +{ + ERR("Unimplemented runas command RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET"); + return -1; +} + +static +int _extract_sdt_probe_offsets(struct run_as_data *data, + struct run_as_ret *ret_value) +{ + ERR("Unimplemented runas command RUN_AS_EXTRACT_SDT_PROBE_OFFSETS"); + return -1; +} +#endif static run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd) { switch (cmd) { case RUN_AS_MKDIR: - return _mkdir; + case RUN_AS_MKDIRAT: + return _mkdirat; + case RUN_AS_MKDIR_RECURSIVE: + case RUN_AS_MKDIRAT_RECURSIVE: + return _mkdirat_recursive; case RUN_AS_OPEN: return _open; case RUN_AS_UNLINK: return _unlink; case RUN_AS_RMDIR_RECURSIVE: return _rmdir_recursive; - case RUN_AS_MKDIR_RECURSIVE: - return _mkdir_recursive; case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET: return _extract_elf_symbol_offset; case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS: @@ -372,6 +408,8 @@ int send_fd_to_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int fd) switch (cmd) { case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET: case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS: + case RUN_AS_MKDIRAT: + case RUN_AS_MKDIRAT_RECURSIVE: break; default: return 0; @@ -450,7 +488,13 @@ int recv_fd_from_master(struct run_as_worker *worker, enum run_as_cmd cmd, int * switch (cmd) { case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET: case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS: + case RUN_AS_MKDIRAT: + case RUN_AS_MKDIRAT_RECURSIVE: break; + case RUN_AS_MKDIR: + case RUN_AS_MKDIR_RECURSIVE: + *fd = AT_FDCWD; + /* fall-through */ default: return 0; } @@ -472,6 +516,8 @@ int cleanup_received_fd(enum run_as_cmd cmd, int fd) switch (cmd) { case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET: case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS: + case RUN_AS_MKDIRAT: + case RUN_AS_MKDIRAT_RECURSIVE: break; default: return 0; @@ -852,7 +898,9 @@ end: } static -int run_as_create_worker_no_lock(const char *procname) +int run_as_create_worker_no_lock(const char *procname, + post_fork_cleanup_cb clean_up_func, + void *clean_up_user_data) { pid_t pid; int i, ret = 0; @@ -877,7 +925,7 @@ int run_as_create_worker_no_lock(const char *procname) worker->procname = strdup(procname); if (!worker->procname) { ret = -ENOMEM; - goto end; + goto error_procname_alloc; } /* Create unix socket. */ if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) { @@ -897,6 +945,12 @@ int run_as_create_worker_no_lock(const char *procname) reset_sighandler(); set_worker_sighandlers(); + if (clean_up_func) { + if (clean_up_func(clean_up_user_data) < 0) { + ERR("Run-as post-fork clean-up failed, exiting."); + exit(EXIT_FAILURE); + } + } /* Just close, no shutdown. */ if (close(worker->sockpair[0])) { @@ -921,6 +975,8 @@ int run_as_create_worker_no_lock(const char *procname) ret = -1; } worker->sockpair[1] = -1; + free(worker->procname); + free(worker); LOG(ret ? PRINT_ERR : PRINT_DBG, "run_as worker exiting (ret = %d)", ret); exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } else { @@ -960,10 +1016,57 @@ error_fork: worker->sockpair[i] = -1; } error_sock: + free(worker->procname); +error_procname_alloc: free(worker); return ret; } +static +void run_as_destroy_worker_no_lock(void) +{ + struct run_as_worker *worker = global_worker; + + DBG("Destroying run_as worker"); + if (!worker) { + return; + } + /* Close unix socket */ + DBG("Closing run_as worker socket"); + if (lttcomm_close_unix_sock(worker->sockpair[0])) { + PERROR("close"); + } + worker->sockpair[0] = -1; + /* Wait for worker. */ + for (;;) { + int status; + pid_t wait_ret; + + wait_ret = waitpid(worker->pid, &status, 0); + if (wait_ret < 0) { + if (errno == EINTR) { + continue; + } + PERROR("waitpid"); + break; + } + + if (WIFEXITED(status)) { + LOG(WEXITSTATUS(status) == 0 ? PRINT_DBG : PRINT_ERR, + DEFAULT_RUN_AS_WORKER_NAME " terminated with status code %d", + WEXITSTATUS(status)); + break; + } else if (WIFSIGNALED(status)) { + ERR(DEFAULT_RUN_AS_WORKER_NAME " was killed by signal %d", + WTERMSIG(status)); + break; + } + } + free(worker->procname); + free(worker); + global_worker = NULL; +} + static int run_as_restart_worker(struct run_as_worker *worker) { @@ -973,10 +1076,10 @@ int run_as_restart_worker(struct run_as_worker *worker) procname = worker->procname; /* Close socket to run_as worker process and clean up the zombie process */ - run_as_destroy_worker(); + run_as_destroy_worker_no_lock(); /* Create a new run_as worker process*/ - ret = run_as_create_worker_no_lock(procname); + ret = run_as_create_worker_no_lock(procname, NULL, NULL); if (ret < 0 ) { ERR("Restarting the worker process failed"); ret = -1; @@ -1026,39 +1129,74 @@ err: LTTNG_HIDDEN int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid) { + return run_as_mkdirat_recursive(AT_FDCWD, path, mode, uid, gid); +} + +LTTNG_HIDDEN +int run_as_mkdirat_recursive(int dirfd, const char *path, mode_t mode, + uid_t uid, gid_t gid) +{ + int ret; struct run_as_data data; - struct run_as_ret ret; + struct run_as_ret run_as_ret; memset(&data, 0, sizeof(data)); - memset(&ret, 0, sizeof(ret)); - DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d", + memset(&run_as_ret, 0, sizeof(run_as_ret)); + DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d", + dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "", path, (int) mode, (int) uid, (int) gid); - strncpy(data.u.mkdir.path, path, PATH_MAX - 1); - data.u.mkdir.path[PATH_MAX - 1] = '\0'; - data.u.mkdir.mode = mode; - - run_as(RUN_AS_MKDIR_RECURSIVE, &data, &ret, uid, gid); - errno = ret._errno; - return ret.u.mkdir.ret; + ret = lttng_strncpy(data.u.mkdirat.path, path, + sizeof(data.u.mkdirat.path)); + if (ret) { + ERR("Failed to copy path argument of mkdirat recursive command"); + goto error; + } + data.u.mkdirat.path[PATH_MAX - 1] = '\0'; + data.u.mkdirat.mode = mode; + data.fd = dirfd; + run_as(dirfd == AT_FDCWD ? RUN_AS_MKDIR_RECURSIVE : RUN_AS_MKDIRAT_RECURSIVE, + &data, &run_as_ret, uid, gid); + errno = run_as_ret._errno; + ret = run_as_ret.u.mkdirat.ret; +error: + return ret; } LTTNG_HIDDEN int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { + return run_as_mkdirat(AT_FDCWD, path, mode, uid, gid); +} + +LTTNG_HIDDEN +int run_as_mkdirat(int dirfd, const char *path, mode_t mode, + uid_t uid, gid_t gid) +{ + int ret; struct run_as_data data; - struct run_as_ret ret; + struct run_as_ret run_as_ret; memset(&data, 0, sizeof(data)); - memset(&ret, 0, sizeof(ret)); + memset(&run_as_ret, 0, sizeof(run_as_ret)); - DBG3("mkdir() %s with mode %d for uid %d and gid %d", + DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d", + dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "", path, (int) mode, (int) uid, (int) gid); - strncpy(data.u.mkdir.path, path, PATH_MAX - 1); - data.u.mkdir.path[PATH_MAX - 1] = '\0'; - data.u.mkdir.mode = mode; - run_as(RUN_AS_MKDIR, &data, &ret, uid, gid); - errno = ret._errno; - return ret.u.mkdir.ret; + ret = lttng_strncpy(data.u.mkdirat.path, path, + sizeof(data.u.mkdirat.path)); + if (ret) { + ERR("Failed to copy path argument of mkdirat command"); + goto error; + } + data.u.mkdirat.path[PATH_MAX - 1] = '\0'; + data.u.mkdirat.mode = mode; + data.fd = dirfd; + run_as(dirfd == AT_FDCWD ? RUN_AS_MKDIR : RUN_AS_MKDIRAT, + &data, &run_as_ret, uid, gid); + errno = run_as_ret._errno; + ret = run_as_ret._errno; +error: + return ret; } LTTNG_HIDDEN @@ -1192,12 +1330,15 @@ int run_as_extract_sdt_probe_offsets(int fd, const char* provider_name, } LTTNG_HIDDEN -int run_as_create_worker(const char *procname) +int run_as_create_worker(const char *procname, + post_fork_cleanup_cb clean_up_func, + void *clean_up_user_data) { int ret; pthread_mutex_lock(&worker_lock); - ret = run_as_create_worker_no_lock(procname); + ret = run_as_create_worker_no_lock(procname, clean_up_func, + clean_up_user_data); pthread_mutex_unlock(&worker_lock); return ret; } @@ -1205,47 +1346,7 @@ int run_as_create_worker(const char *procname) LTTNG_HIDDEN void run_as_destroy_worker(void) { - struct run_as_worker *worker = global_worker; - - DBG("Destroying run_as worker"); pthread_mutex_lock(&worker_lock); - if (!worker) { - goto end; - } - /* Close unix socket */ - DBG("Closing run_as worker socket"); - if (lttcomm_close_unix_sock(worker->sockpair[0])) { - PERROR("close"); - } - worker->sockpair[0] = -1; - /* Wait for worker. */ - for (;;) { - int status; - pid_t wait_ret; - - wait_ret = waitpid(worker->pid, &status, 0); - if (wait_ret < 0) { - if (errno == EINTR) { - continue; - } - PERROR("waitpid"); - break; - } - - if (WIFEXITED(status)) { - LOG(WEXITSTATUS(status) == 0 ? PRINT_DBG : PRINT_ERR, - DEFAULT_RUN_AS_WORKER_NAME " terminated with status code %d", - WEXITSTATUS(status)); - break; - } else if (WIFSIGNALED(status)) { - ERR(DEFAULT_RUN_AS_WORKER_NAME " was killed by signal %d", - WTERMSIG(status)); - break; - } - } - free(worker->procname); - free(worker); - global_worker = NULL; -end: + run_as_destroy_worker_no_lock(); pthread_mutex_unlock(&worker_lock); }