X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Frunas.c;h=36be188fafb54036688930689d1d23781cbe000d;hp=e0c317c4e40347fb7001b74fb9900e9bcfafe32f;hb=d77dded285b058e4242c8a3d2233f80e725ceefc;hpb=ca2eb7f43cf00d12f563905d741a6789c3d130ee diff --git a/src/common/runas.c b/src/common/runas.c index e0c317c4e..36be188fa 100644 --- a/src/common/runas.c +++ b/src/common/runas.c @@ -2,21 +2,22 @@ * Copyright (C) 2011 - David Goulet * Mathieu Desnoyers * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; only version 2 of the License. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -30,14 +31,20 @@ #include #include -#include +#include +#include #include #include +#include #include "runas.h" #define RUNAS_CHILD_STACK_SIZE 10485760 +#ifndef MAP_STACK +#define MAP_STACK 0 +#endif + #ifdef __FreeBSD__ /* FreeBSD MAP_STACK always return -ENOMEM */ #define LTTNG_MAP_STACK 0 @@ -72,6 +79,31 @@ struct run_as_open_data { mode_t mode; }; +struct run_as_unlink_data { + const char *path; +}; + +struct run_as_recursive_rmdir_data { + const char *path; +}; + +#ifdef VALGRIND +static +int use_clone(void) +{ + return 0; +} +#else +static +int use_clone(void) +{ + return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE"); +} +#endif + +LTTNG_HIDDEN +int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode); + /* * Create recursively directory using the FULL path. */ @@ -80,82 +112,71 @@ int _mkdir_recursive(void *_data) { struct run_as_mkdir_data *data = _data; const char *path; - char *p, tmp[PATH_MAX]; - struct stat statbuf; mode_t mode; - size_t len; - int ret; path = data->path; mode = data->mode; - ret = snprintf(tmp, sizeof(tmp), "%s", path); - if (ret < 0) { - PERROR("snprintf mkdir"); - goto error; - } - - len = ret; - if (tmp[len - 1] == '/') { - tmp[len - 1] = 0; - } + /* Safe to call as we have transitioned to the requested uid/gid. */ + return _utils_mkdir_recursive_unsafe(path, mode); +} - for (p = tmp + 1; *p; p++) { - if (*p == '/') { - *p = 0; - ret = stat(tmp, &statbuf); - if (ret < 0) { - ret = mkdir(tmp, mode); - if (ret < 0) { - if (!(errno == EEXIST)) { - PERROR("mkdir recursive"); - ret = -errno; - goto error; - } - } - } - *p = '/'; - } - } +static +int _mkdir(void *_data) +{ + int ret; + struct run_as_mkdir_data *data = _data; - ret = mkdir(tmp, mode); + ret = mkdir(data->path, data->mode); if (ret < 0) { - if (!(errno == EEXIST)) { - PERROR("mkdir recursive last piece"); - ret = -errno; - } else { - ret = 0; - } + ret = -errno; } -error: return ret; } static -int _mkdir(void *_data) +int _open(void *_data) { - struct run_as_mkdir_data *data = _data; - return mkdir(data->path, data->mode); + struct run_as_open_data *data = _data; + return open(data->path, data->flags, data->mode); } static -int _open(void *_data) +int _unlink(void *_data) { - struct run_as_open_data *data = _data; - return open(data->path, data->flags, data->mode); + int ret; + struct run_as_unlink_data *data = _data; + + ret = unlink(data->path); + if (ret < 0) { + ret = -errno; + } + + return ret; +} + +static +int _recursive_rmdir(void *_data) +{ + int ret; + struct run_as_recursive_rmdir_data *data = _data; + + ret = utils_recursive_rmdir(data->path); + if (ret < 0) { + ret = -errno; + } + + return ret; } static int child_run_as(void *_data) { - struct run_as_data *data = _data; - size_t writelen, writeleft, index; - union { - int i; - char c[sizeof(int)]; - } sendret; int ret; + struct run_as_data *data = _data; + ssize_t writelen; + int sendret; /* * Child: it is safe to drop egid and euid while sharing the @@ -168,35 +189,33 @@ int child_run_as(void *_data) ret = setegid(data->gid); if (ret < 0) { PERROR("setegid"); - return EXIT_FAILURE; + sendret = -1; + goto write_return; } } if (data->uid != geteuid()) { ret = seteuid(data->uid); if (ret < 0) { PERROR("seteuid"); - return EXIT_FAILURE; + sendret = -1; + goto write_return; } } /* * Also set umask to 0 for mkdir executable bit. */ umask(0); - sendret.i = (*data->cmd)(data->data); + sendret = (*data->cmd)(data->data); + +write_return: /* send back return value */ - writeleft = sizeof(sendret); - index = 0; - do { - writelen = write(data->retval_pipe, &sendret.c[index], - writeleft); - if (writelen < 0) { - PERROR("write"); - return EXIT_FAILURE; - } - writeleft -= writelen; - index += writelen; - } while (writeleft > 0); - return EXIT_SUCCESS; + writelen = lttng_write(data->retval_pipe, &sendret, sizeof(sendret)); + if (writelen < sizeof(sendret)) { + PERROR("lttng_write error"); + return EXIT_FAILURE; + } else { + return EXIT_SUCCESS; + } } static @@ -204,15 +223,12 @@ int run_as_clone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) { struct run_as_data run_as_data; int ret = 0; + ssize_t readlen; int status; pid_t pid; int retval_pipe[2]; - ssize_t readlen, readleft, index; void *child_stack; - union { - int i; - char c[sizeof(int)]; - } retval; + int retval; /* * If we are non-root, we can only deal with our own uid. @@ -228,7 +244,7 @@ int run_as_clone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) ret = pipe(retval_pipe); if (ret < 0) { PERROR("pipe"); - retval.i = ret; + retval = ret; goto end; } run_as_data.data = data; @@ -242,7 +258,7 @@ int run_as_clone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) -1, 0); if (child_stack == MAP_FAILED) { PERROR("mmap"); - retval.i = -ENOMEM; + retval = -ENOMEM; goto close_pipe; } /* @@ -253,22 +269,14 @@ int run_as_clone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) &run_as_data); if (pid < 0) { PERROR("clone"); - retval.i = pid; + retval = pid; goto unmap_stack; } /* receive return value */ - readleft = sizeof(retval); - index = 0; - do { - readlen = read(retval_pipe[0], &retval.c[index], readleft); - if (readlen < 0) { - PERROR("read"); - ret = -1; - break; - } - readleft -= readlen; - index += readlen; - } while (readleft > 0); + readlen = lttng_read(retval_pipe[0], &retval, sizeof(retval)); + if (readlen < sizeof(retval)) { + ret = -1; + } /* * Parent: wait for child to return, in which case the @@ -277,13 +285,13 @@ int run_as_clone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) pid = waitpid(pid, &status, 0); if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { PERROR("wait"); - retval.i = -1; + retval = -1; } unmap_stack: ret = munmap(child_stack, RUNAS_CHILD_STACK_SIZE); if (ret < 0) { PERROR("munmap"); - retval.i = ret; + retval = ret; } close_pipe: ret = close(retval_pipe[0]); @@ -295,7 +303,7 @@ close_pipe: PERROR("close"); } end: - return retval.i; + return retval; } /* @@ -306,21 +314,34 @@ end: static int run_as_noclone(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) { - return cmd(data); + int ret; + mode_t old_mask; + + old_mask = umask(0); + ret = cmd(data); + umask(old_mask); + + return ret; } static int run_as(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) { - if (!getenv("LTTNG_DEBUG_NOCLONE")) { + if (use_clone()) { + int ret; + DBG("Using run_as_clone"); - return run_as_clone(cmd, data, uid, gid); + pthread_mutex_lock(<tng_libc_state_lock); + ret = run_as_clone(cmd, data, uid, gid); + pthread_mutex_unlock(<tng_libc_state_lock); + return ret; } else { DBG("Using run_as_noclone"); return run_as_noclone(cmd, data, uid, gid); } } +LTTNG_HIDDEN int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid) { struct run_as_mkdir_data data; @@ -332,6 +353,7 @@ int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid) return run_as(_mkdir_recursive, &data, uid, gid); } +LTTNG_HIDDEN int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { struct run_as_mkdir_data data; @@ -347,6 +369,7 @@ int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) * Note: open_run_as is currently not working. We'd need to pass the fd * opened in the child to the parent. */ +LTTNG_HIDDEN int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) { struct run_as_open_data data; @@ -358,3 +381,25 @@ int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) data.mode = mode; return run_as(_open, &data, uid, gid); } + +LTTNG_HIDDEN +int run_as_unlink(const char *path, uid_t uid, gid_t gid) +{ + struct run_as_unlink_data data; + + DBG3("unlink() %s with for uid %d and gid %d", + path, uid, gid); + data.path = path; + return run_as(_unlink, &data, uid, gid); +} + +LTTNG_HIDDEN +int run_as_recursive_rmdir(const char *path, uid_t uid, gid_t gid) +{ + struct run_as_recursive_rmdir_data data; + + DBG3("recursive_rmdir() %s with for uid %d and gid %d", + path, uid, gid); + data.path = path; + return run_as(_recursive_rmdir, &data, uid, gid); +}