From 2912cead42803e75e41157418d264d7b5ff6c69f Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Thu, 9 May 2019 14:10:58 -0400 Subject: [PATCH] Add file creation/unlinking utils to directory handle MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This commit adds file creation and unlinking functions to the directory handle interface and corresponding run_as wrappers. This allows the creation and unlinking of files relative to an existing directory handle using either openat/unlinkat when directory file descriptors are supported or open/unlink when they are not. Signed-off-by: Jérémie Galarneau --- src/common/compat/directory-handle.c | 183 ++++++++++++++++++++++++++- src/common/compat/directory-handle.h | 24 ++++ src/common/runas.c | 48 ++++++- src/common/runas.h | 7 + 4 files changed, 254 insertions(+), 8 deletions(-) diff --git a/src/common/compat/directory-handle.c b/src/common/compat/directory-handle.c index 5bfdd699d..80e9e118b 100644 --- a/src/common/compat/directory-handle.c +++ b/src/common/compat/directory-handle.c @@ -28,6 +28,11 @@ #include #include +/* + * This compatibility layer shares a common "base" that is implemented + * in terms of an internal API. This file contains two implementations + * of the internal API below. + */ static int lttng_directory_handle_stat(const struct lttng_directory_handle *handle, const char *path, struct stat *st); @@ -42,6 +47,20 @@ static int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle, const char *path, mode_t mode, uid_t uid, gid_t gid); static +int lttng_directory_handle_open(const struct lttng_directory_handle *handle, + const char *filename, int flags, mode_t mode); +static +int _run_as_open(const struct lttng_directory_handle *handle, + const char *filename, + int flags, mode_t mode, uid_t uid, gid_t gid); +static +int lttng_directory_handle_unlink( + const struct lttng_directory_handle *handle, + const char *filename); +static +int _run_as_unlink(const struct lttng_directory_handle *handle, + const char *filename, uid_t uid, gid_t gid); +static void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle); #ifdef COMPAT_DIRFD @@ -151,8 +170,38 @@ int lttng_directory_handle_mkdir( } static -int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path, - mode_t mode, uid_t uid, gid_t gid) +int lttng_directory_handle_open(const struct lttng_directory_handle *handle, + const char *filename, int flags, mode_t mode) +{ + return openat(handle->dirfd, filename, flags, mode); +} + +static +int _run_as_open(const struct lttng_directory_handle *handle, + const char *filename, + int flags, mode_t mode, uid_t uid, gid_t gid) +{ + return run_as_openat(handle->dirfd, filename, flags, mode, uid, gid); +} + +static +int _run_as_unlink(const struct lttng_directory_handle *handle, + const char *filename, uid_t uid, gid_t gid) +{ + return run_as_unlinkat(handle->dirfd, filename, uid, gid); +} + +static +int lttng_directory_handle_unlink( + const struct lttng_directory_handle *handle, + const char *filename) +{ + return unlinkat(handle->dirfd, filename, 0); +} + +static +int _run_as_mkdir(const struct lttng_directory_handle *handle, + const char *path, mode_t mode, uid_t uid, gid_t gid) { return run_as_mkdirat(handle->dirfd, path, mode, uid, gid); } @@ -386,6 +435,43 @@ end: return ret; } +static +int lttng_directory_handle_open(const struct lttng_directory_handle *handle, + const char *filename, int flags, mode_t mode) +{ + int ret; + char fullpath[LTTNG_PATH_MAX]; + + ret = get_full_path(handle, filename, fullpath, sizeof(fullpath)); + if (ret) { + errno = ENOMEM; + goto end; + } + + ret = open(fullpath, flags, mode); +end: + return ret; +} + +static +int lttng_directory_handle_unlink( + const struct lttng_directory_handle *handle, + const char *filename) +{ + int ret; + char fullpath[LTTNG_PATH_MAX]; + + ret = get_full_path(handle, filename, fullpath, sizeof(fullpath)); + if (ret) { + errno = ENOMEM; + goto end; + } + + ret = unlink(fullpath); +end: + return ret; +} + static int _run_as_mkdir(const struct lttng_directory_handle *handle, const char *path, mode_t mode, uid_t uid, gid_t gid) @@ -404,6 +490,43 @@ end: return ret; } +static +int _run_as_open(const struct lttng_directory_handle *handle, + const char *filename, + int flags, mode_t mode, uid_t uid, gid_t gid) +{ + int ret; + char fullpath[LTTNG_PATH_MAX]; + + ret = get_full_path(handle, filename, fullpath, sizeof(fullpath)); + if (ret) { + errno = ENOMEM; + goto end; + } + + ret = run_as_open(fullpath, flags, mode, uid, gid); +end: + return ret; +} + +static +int _run_as_unlink(const struct lttng_directory_handle *handle, + const char *filename, uid_t uid, gid_t gid) +{ + int ret; + char fullpath[LTTNG_PATH_MAX]; + + ret = get_full_path(handle, filename, fullpath, sizeof(fullpath)); + if (ret) { + errno = ENOMEM; + goto end; + } + + ret = run_as_unlink(fullpath, uid, gid); +end: + return ret; +} + static int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle, const char *path, mode_t mode, uid_t uid, gid_t gid) @@ -587,3 +710,59 @@ int lttng_directory_handle_create_subdirectory_recursive( return lttng_directory_handle_create_subdirectory_recursive_as_user( handle, subdirectory_path, mode, NULL); } + +LTTNG_HIDDEN +int lttng_directory_handle_open_file_as_user( + const struct lttng_directory_handle *handle, + const char *filename, + int flags, mode_t mode, + const struct lttng_credentials *creds) +{ + int ret; + + if (!creds) { + /* Run as current user. */ + ret = lttng_directory_handle_open(handle, filename, flags, + mode); + } else { + ret = _run_as_open(handle, filename, flags, mode, + creds->uid, creds->gid); + } + return ret; +} + +LTTNG_HIDDEN +int lttng_directory_handle_open_file( + const struct lttng_directory_handle *handle, + const char *filename, + int flags, mode_t mode) +{ + return lttng_directory_handle_open_file_as_user(handle, filename, flags, + mode, NULL); +} + +LTTNG_HIDDEN +int lttng_directory_handle_unlink_file_as_user( + const struct lttng_directory_handle *handle, + const char *filename, + const struct lttng_credentials *creds) +{ + int ret; + + if (!creds) { + /* Run as current user. */ + ret = lttng_directory_handle_unlink(handle, filename); + } else { + ret = _run_as_unlink(handle, filename, creds->uid, creds->gid); + } + return ret; +} + +LTTNG_HIDDEN +int lttng_directory_handle_unlink_file( + const struct lttng_directory_handle *handle, + const char *filename) +{ + return lttng_directory_handle_unlink_file_as_user(handle, + filename, NULL); +} diff --git a/src/common/compat/directory-handle.h b/src/common/compat/directory-handle.h index 605c3dc81..bdf216200 100644 --- a/src/common/compat/directory-handle.h +++ b/src/common/compat/directory-handle.h @@ -153,4 +153,28 @@ int lttng_directory_handle_create_subdirectory_recursive_as_user( const char *subdirectory_path, mode_t mode, const struct lttng_credentials *creds); +LTTNG_HIDDEN +int lttng_directory_handle_open_file( + const struct lttng_directory_handle *handle, + const char *filename, + int flags, mode_t mode); + +LTTNG_HIDDEN +int lttng_directory_handle_open_file_as_user( + const struct lttng_directory_handle *handle, + const char *filename, + int flags, mode_t mode, + const struct lttng_credentials *creds); + +LTTNG_HIDDEN +int lttng_directory_handle_unlink_file( + const struct lttng_directory_handle *handle, + const char *filename); + +LTTNG_HIDDEN +int lttng_directory_handle_unlink_file_as_user( + const struct lttng_directory_handle *handle, + const char *filename, + const struct lttng_credentials *creds); + #endif /* _COMPAT_PATH_HANDLE_H */ diff --git a/src/common/runas.c b/src/common/runas.c index bba0aa49d..c77f198c4 100644 --- a/src/common/runas.c +++ b/src/common/runas.c @@ -108,7 +108,9 @@ enum run_as_cmd { RUN_AS_MKDIR_RECURSIVE, RUN_AS_MKDIRAT_RECURSIVE, RUN_AS_OPEN, + RUN_AS_OPENAT, RUN_AS_UNLINK, + RUN_AS_UNLINKAT, RUN_AS_RMDIR_RECURSIVE, RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET, RUN_AS_EXTRACT_SDT_PROBE_OFFSETS, @@ -231,7 +233,8 @@ int _mkdirat(struct run_as_data *data, struct run_as_ret *ret_value) static 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->u.open.ret = openat(data->fd, 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 < 0; @@ -241,7 +244,7 @@ int _open(struct run_as_data *data, struct run_as_ret *ret_value) static int _unlink(struct run_as_data *data, struct run_as_ret *ret_value) { - ret_value->u.unlink.ret = unlink(data->u.unlink.path); + ret_value->u.unlink.ret = unlinkat(data->fd, data->u.unlink.path, 0); ret_value->_errno = errno; ret_value->_error = (ret_value->u.unlink.ret) ? true : false; return ret_value->u.unlink.ret; @@ -344,8 +347,10 @@ run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd) case RUN_AS_MKDIRAT_RECURSIVE: return _mkdirat_recursive; case RUN_AS_OPEN: + case RUN_AS_OPENAT: return _open; case RUN_AS_UNLINK: + case RUN_AS_UNLINKAT: return _unlink; case RUN_AS_RMDIR_RECURSIVE: return _rmdir_recursive; @@ -410,6 +415,8 @@ int send_fd_to_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int fd) case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS: case RUN_AS_MKDIRAT: case RUN_AS_MKDIRAT_RECURSIVE: + case RUN_AS_OPENAT: + case RUN_AS_UNLINKAT: break; default: return 0; @@ -436,6 +443,7 @@ int send_fd_to_master(struct run_as_worker *worker, enum run_as_cmd cmd, int fd) switch (cmd) { case RUN_AS_OPEN: + case RUN_AS_OPENAT: break; default: return 0; @@ -466,6 +474,7 @@ int recv_fd_from_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int * switch (cmd) { case RUN_AS_OPEN: + case RUN_AS_OPENAT: break; default: return 0; @@ -490,9 +499,13 @@ int recv_fd_from_master(struct run_as_worker *worker, enum run_as_cmd cmd, int * case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS: case RUN_AS_MKDIRAT: case RUN_AS_MKDIRAT_RECURSIVE: + case RUN_AS_OPENAT: + case RUN_AS_UNLINKAT: break; case RUN_AS_MKDIR: case RUN_AS_MKDIR_RECURSIVE: + case RUN_AS_OPEN: + case RUN_AS_UNLINK: *fd = AT_FDCWD; /* fall-through */ default: @@ -518,6 +531,10 @@ int cleanup_received_fd(enum run_as_cmd cmd, int fd) case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS: case RUN_AS_MKDIRAT: case RUN_AS_MKDIRAT_RECURSIVE: + case RUN_AS_OPEN: + case RUN_AS_OPENAT: + case RUN_AS_UNLINK: + case RUN_AS_UNLINKAT: break; default: return 0; @@ -1200,7 +1217,15 @@ error: } LTTNG_HIDDEN -int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) +int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, + gid_t gid) +{ + return run_as_openat(AT_FDCWD, path, flags, mode, uid, gid); +} + +LTTNG_HIDDEN +int run_as_openat(int dirfd, const char *path, int flags, mode_t mode, + uid_t uid, gid_t gid) { struct run_as_data data; struct run_as_ret ret; @@ -1208,13 +1233,16 @@ int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) memset(&data, 0, sizeof(data)); memset(&ret, 0, sizeof(ret)); - DBG3("open() %s with flags %X mode %d for uid %d and gid %d", + DBG3("openat() fd = %d%s, path = %s, flags = %X, mode = %d, uid %d, gid %d", + dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "", path, flags, (int) mode, (int) uid, (int) gid); strncpy(data.u.open.path, path, PATH_MAX - 1); data.u.open.path[PATH_MAX - 1] = '\0'; data.u.open.flags = flags; data.u.open.mode = mode; - run_as(RUN_AS_OPEN, &data, &ret, uid, gid); + data.fd = dirfd; + run_as(dirfd == AT_FDCWD ? RUN_AS_OPEN : RUN_AS_OPENAT, + &data, &ret, uid, gid); errno = ret._errno; ret.u.open.ret = ret.fd; return ret.u.open.ret; @@ -1222,6 +1250,12 @@ int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) LTTNG_HIDDEN int run_as_unlink(const char *path, uid_t uid, gid_t gid) +{ + return run_as_unlinkat(AT_FDCWD, path, uid, gid); +} + +LTTNG_HIDDEN +int run_as_unlinkat(int dirfd, const char *path, uid_t uid, gid_t gid) { struct run_as_data data; struct run_as_ret ret; @@ -1229,10 +1263,12 @@ int run_as_unlink(const char *path, uid_t uid, gid_t gid) memset(&data, 0, sizeof(data)); memset(&ret, 0, sizeof(ret)); - DBG3("unlink() %s with for uid %d and gid %d", + DBG3("unlinkat() fd = %d%s, path = %s, uid = %d, gid = %d", + dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "", path, (int) uid, (int) gid); strncpy(data.u.unlink.path, path, PATH_MAX - 1); data.u.unlink.path[PATH_MAX - 1] = '\0'; + data.fd = dirfd; run_as(RUN_AS_UNLINK, &data, &ret, uid, gid); errno = ret._errno; return ret.u.unlink.ret; diff --git a/src/common/runas.h b/src/common/runas.h index 827371774..55734eb41 100644 --- a/src/common/runas.h +++ b/src/common/runas.h @@ -23,6 +23,8 @@ #include #include +#include + /* * The run-as process is launched by forking without an exec*() call. This means * that any resource allocated before the run-as worker is launched should be @@ -51,8 +53,13 @@ int run_as_mkdirat(int dirfd, const char *path, mode_t mode, LTTNG_HIDDEN int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid); LTTNG_HIDDEN +int run_as_openat(int dirfd, const char *filename, int flags, mode_t mode, + uid_t uid, gid_t gid); +LTTNG_HIDDEN int run_as_unlink(const char *path, uid_t uid, gid_t gid); LTTNG_HIDDEN +int run_as_unlinkat(int dirfd, const char *filename, uid_t uid, gid_t gid); +LTTNG_HIDDEN int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid); LTTNG_HIDDEN int run_as_extract_elf_symbol_offset(int fd, const char* function, -- 2.34.1