From 60b6c79cedc1023732ff0935aa85b5d0d1c2bcbf Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 20 Dec 2011 18:01:10 -0500 Subject: [PATCH] librarize run_as still TODO: finish open_run_as -- need to pass the file descriptor back to the parent. Currently using a racy open+fchown work-around. Signed-off-by: Mathieu Desnoyers --- Makefile.am | 1 + configure.ac | 1 + include/Makefile.am | 3 +- include/runas.h | 29 +++ liblttng-kconsumer/lttng-kconsumer.c | 12 +- liblttng-ustconsumer/Makefile.am | 1 + liblttng-ustconsumer/lttng-ustconsumer.c | 12 +- librunas/Makefile.am | 5 + librunas/runas.c | 226 +++++++++++++++++++++++ lttng-consumerd/Makefile.am | 3 +- lttng-sessiond/Makefile.am | 3 +- lttng-sessiond/main.c | 1 + lttng-sessiond/ust-app.c | 3 +- lttng-sessiond/utils.c | 180 ------------------ lttng-sessiond/utils.h | 6 - 15 files changed, 282 insertions(+), 204 deletions(-) create mode 100644 include/runas.h create mode 100644 librunas/Makefile.am create mode 100644 librunas/runas.c diff --git a/Makefile.am b/Makefile.am index fa5beea9a..4d203b55c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,6 +2,7 @@ ACLOCAL_AMFLAGS = -I config SUBDIRS = liblttng-sessiond-comm \ libkernelctl \ + librunas \ liblttng-kconsumer \ liblttng-ustconsumer \ liblttng-consumer \ diff --git a/configure.ac b/configure.ac index 65b352c7d..1c4bc1620 100644 --- a/configure.ac +++ b/configure.ac @@ -138,6 +138,7 @@ AC_CONFIG_FILES([ liblttng-ustconsumer/Makefile liblttngctl/Makefile liblttng-sessiond-comm/Makefile + librunas/Makefile lttng-consumerd/Makefile lttng-sessiond/Makefile lttng/Makefile diff --git a/include/Makefile.am b/include/Makefile.am index d53444f4e..10caa6958 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,4 +2,5 @@ lttnginclude_HEADERS = lttng/lttng.h lttng/lttng-kconsumer.h \ lttng/lttng-ustconsumer.h lttng/lttng-consumer.h noinst_HEADERS = lttngerr.h lttng-kernel.h lttng-consumerd.h lttng-share.h \ - lttng-sessiond-comm.h lttng-kernel-ctl.h + lttng-sessiond-comm.h lttng-kernel-ctl.h \ + runas.h diff --git a/include/runas.h b/include/runas.h new file mode 100644 index 000000000..544653d65 --- /dev/null +++ b/include/runas.h @@ -0,0 +1,29 @@ +#ifndef _RUNAS_H +#define _RUNAS_H + +/* + * 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 verion 2 + * of the License. + * + * 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 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. + */ + +#include + +int mkdir_recursive_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid); +int mkdir_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid); +int open_run_as(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid); + +#endif /* _RUNAS_H */ diff --git a/liblttng-kconsumer/lttng-kconsumer.c b/liblttng-kconsumer/lttng-kconsumer.c index 242047ef0..388cc5b20 100644 --- a/liblttng-kconsumer/lttng-kconsumer.c +++ b/liblttng-kconsumer/lttng-kconsumer.c @@ -33,6 +33,7 @@ #include #include #include +#include extern struct lttng_consumer_global_data consumer_data; extern int consumer_poll_timeout; @@ -395,19 +396,16 @@ int lttng_kconsumer_on_recv_stream(struct lttng_consumer_stream *stream) /* Opening the tracefile in write mode */ if (stream->path_name != NULL) { - ret = open(stream->path_name, - O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO); + ret = open_run_as(stream->path_name, + O_WRONLY|O_CREAT|O_TRUNC, + S_IRWXU|S_IRWXG|S_IRWXO, + stream->uid, stream->gid); if (ret < 0) { ERR("Opening %s", stream->path_name); perror("open"); goto error; } stream->out_fd = ret; - ret = chown(stream->path_name, stream->uid, stream->gid); - if (ret < 0) { - ERR("Changing ownership of %s", stream->path_name); - perror("chown"); - } } if (stream->output == LTTNG_EVENT_MMAP) { diff --git a/liblttng-ustconsumer/Makefile.am b/liblttng-ustconsumer/Makefile.am index 284eccf97..e01064fd7 100644 --- a/liblttng-ustconsumer/Makefile.am +++ b/liblttng-ustconsumer/Makefile.am @@ -6,4 +6,5 @@ noinst_LTLIBRARIES = liblttng-ustconsumer.la liblttng_ustconsumer_la_SOURCES = lttng-ustconsumer.c liblttng_ustconsumer_la_LIBADD = -llttng-ust-ctl + endif diff --git a/liblttng-ustconsumer/lttng-ustconsumer.c b/liblttng-ustconsumer/lttng-ustconsumer.c index efb6be424..26e680a9c 100644 --- a/liblttng-ustconsumer/lttng-ustconsumer.c +++ b/liblttng-ustconsumer/lttng-ustconsumer.c @@ -33,6 +33,7 @@ #include #include #include +#include extern struct lttng_consumer_global_data consumer_data; extern int consumer_poll_timeout; @@ -397,19 +398,16 @@ int lttng_ustconsumer_on_recv_stream(struct lttng_consumer_stream *stream) /* Opening the tracefile in write mode */ if (stream->path_name != NULL) { - ret = open(stream->path_name, - O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO); + ret = open_run_as(stream->path_name, + O_WRONLY|O_CREAT|O_TRUNC, + S_IRWXU|S_IRWXG|S_IRWXO, + stream->uid, stream->gid); if (ret < 0) { ERR("Opening %s", stream->path_name); perror("open"); goto error; } stream->out_fd = ret; - ret = chown(stream->path_name, stream->uid, stream->gid); - if (ret < 0) { - ERR("Changing ownership of %s", stream->path_name); - perror("chown"); - } } /* we return 0 to let the library handle the FD internally */ diff --git a/librunas/Makefile.am b/librunas/Makefile.am new file mode 100644 index 000000000..92ec27242 --- /dev/null +++ b/librunas/Makefile.am @@ -0,0 +1,5 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include + +noinst_LTLIBRARIES = librunas.la + +librunas_la_SOURCES = runas.c diff --git a/librunas/runas.c b/librunas/runas.c new file mode 100644 index 000000000..24a772ccf --- /dev/null +++ b/librunas/runas.c @@ -0,0 +1,226 @@ +/* + * 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 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 + * 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. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct mkdir_data { + const char *path; + mode_t mode; +}; + +struct open_data { + const char *path; + int flags; + mode_t mode; +}; + +/* + * Create recursively directory using the FULL path. + */ +static +int _mkdir_recursive(void *_data) +{ + struct 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; + } + + 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 = '/'; + } + } + + ret = mkdir(tmp, mode); + if (ret < 0) { + if (!(errno == EEXIST)) { + PERROR("mkdir recursive last piece"); + ret = -errno; + } else { + ret = 0; + } + } + +error: + return ret; +} + +static +int _mkdir(void *_data) +{ + struct mkdir_data *data = _data; + return mkdir(data->path, data->mode); +} + +static +int _open(void *_data) +{ + struct open_data *data = _data; + return open(data->path, data->flags, data->mode); +} + +static +int run_as(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) +{ + int ret = 0; + pid_t pid; + + /* + * If we are non-root, we can only deal with our own uid. + */ + if (geteuid() != 0) { + if (uid != geteuid()) { + ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)", + uid, geteuid()); + return -EPERM; + } + return (*cmd)(data); + } + + pid = fork(); + if (pid > 0) { + int status; + + /* + * Parent: wait for child to return, in which case the + * shared memory map will have been created. + */ + pid = wait(&status); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + ret = -1; + goto end; + } + goto end; + } else if (pid == 0) { + /* Child */ + setegid(gid); + if (ret < 0) { + perror("setegid"); + exit(EXIT_FAILURE); + } + ret = seteuid(uid); + if (ret < 0) { + perror("seteuid"); + exit(EXIT_FAILURE); + } + umask(0); + ret = (*cmd)(data); + if (!ret) + exit(EXIT_SUCCESS); + else + exit(EXIT_FAILURE); + } else { + return -1; + } +end: + return ret; +} + +int mkdir_recursive_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid) +{ + struct mkdir_data data; + + DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d", + path, mode, uid, gid); + data.path = path; + data.mode = mode; + return run_as(_mkdir_recursive, &data, uid, gid); +} + +int mkdir_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid) +{ + struct mkdir_data data; + + DBG3("mkdir() %s with mode %d for uid %d and gid %d", + path, mode, uid, gid); + data.path = path; + data.mode = mode; + return run_as(_mkdir, &data, uid, gid); +} + +/* + * Note: open_run_as is currently not working. We'd need to pass the fd + * opened in the child to the parent. + */ +int open_run_as(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) +{ + //struct open_data data; + int fd, ret; + + DBG3("open() %s with flags %d mode %d for uid %d and gid %d", + path, flags, mode, uid, gid); + fd = open(path, flags, mode); + if (fd < 0) { + perror("open"); + return fd; + } + ret = fchown(fd, uid, gid); + if (ret < 0) { + perror("fchown"); + close(fd); + return ret; + } + return fd; +#if 0 + data.path = path; + data.flags = flags; + data.mode = mode; + return run_as(_open, &data, uid, gid); +#endif +} diff --git a/lttng-consumerd/Makefile.am b/lttng-consumerd/Makefile.am index 70ebc5035..a808e3ca8 100644 --- a/lttng-consumerd/Makefile.am +++ b/lttng-consumerd/Makefile.am @@ -7,7 +7,8 @@ lttng_consumerd_SOURCES = lttng-consumerd.c lttng_consumerd_LDADD = \ $(top_builddir)/libkernelctl/libkernelctl.la \ $(top_builddir)/liblttng-consumer/liblttng-consumer.la \ - $(top_builddir)/liblttng-sessiond-comm/liblttng-sessiond-comm.la + $(top_builddir)/liblttng-sessiond-comm/liblttng-sessiond-comm.la \ + $(top_builddir)/librunas/librunas.la if HAVE_LIBLTTNG_UST_CTL lttng_consumerd_LDADD += -llttng-ust-ctl diff --git a/lttng-sessiond/Makefile.am b/lttng-sessiond/Makefile.am index 592d55a13..d3900d22d 100644 --- a/lttng-sessiond/Makefile.am +++ b/lttng-sessiond/Makefile.am @@ -40,7 +40,8 @@ lttng_sessiond_SOURCES += lttng-sessiond.h main.c lttng_sessiond_LDADD = -lrt -lurcu-common -lurcu \ $(top_builddir)/liblttng-sessiond-comm/liblttng-sessiond-comm.la \ $(top_builddir)/libkernelctl/libkernelctl.la \ - $(top_builddir)/liblttngctl/liblttngctl.la + $(top_builddir)/liblttngctl/liblttngctl.la \ + $(top_builddir)/librunas/librunas.la if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_LDADD += -llttng-ust-ctl diff --git a/lttng-sessiond/main.c b/lttng-sessiond/main.c index 80505b3ca..10139448a 100644 --- a/lttng-sessiond/main.c +++ b/lttng-sessiond/main.c @@ -43,6 +43,7 @@ #include #include +#include #include "channel.h" #include "compat/poll.h" diff --git a/lttng-sessiond/ust-app.c b/lttng-sessiond/ust-app.c index 09989ff49..384d85e23 100644 --- a/lttng-sessiond/ust-app.c +++ b/lttng-sessiond/ust-app.c @@ -25,16 +25,17 @@ #include #include #include +#include #include #include #include +#include #include "hashtable.h" #include "ust-app.h" #include "ust-consumer.h" #include "ust-ctl.h" -#include "utils.h" /* * Delete ust context safely. RCU read lock must be held before calling diff --git a/lttng-sessiond/utils.c b/lttng-sessiond/utils.c index 1e08de77d..22a07ffae 100644 --- a/lttng-sessiond/utils.c +++ b/lttng-sessiond/utils.c @@ -22,27 +22,12 @@ #include #include #include -#include -#include -#include #include -#include #include #include "utils.h" -struct mkdir_data { - const char *path; - mode_t mode; -}; - -struct open_data { - const char *path; - int flags; - mode_t mode; -}; - /* * Write to writable pipe used to notify a thread. */ @@ -67,168 +52,3 @@ const char *get_home_dir(void) { return ((const char *) getenv("HOME")); } - -/* - * Create recursively directory using the FULL path. - */ -static -int _mkdir_recursive(void *_data) -{ - struct 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; - } - - 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 = '/'; - } - } - - ret = mkdir(tmp, mode); - if (ret < 0) { - if (!(errno == EEXIST)) { - PERROR("mkdir recursive last piece"); - ret = -errno; - } else { - ret = 0; - } - } - -error: - return ret; -} - -static -int _mkdir(void *_data) -{ - struct mkdir_data *data = _data; - return mkdir(data->path, data->mode); -} - -static -int _open(void *_data) -{ - struct open_data *data = _data; - return open(data->path, data->flags, data->mode); -} - -static -int run_as(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid) -{ - int ret = 0; - pid_t pid; - - /* - * If we are non-root, we can only deal with our own uid. - */ - if (geteuid() != 0) { - if (uid != geteuid()) { - ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)", - uid, geteuid()); - return -EPERM; - } - return (*cmd)(data); - } - - pid = fork(); - if (pid > 0) { - int status; - - /* - * Parent: wait for child to return, in which case the - * shared memory map will have been created. - */ - pid = wait(&status); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - ret = -1; - goto end; - } - goto end; - } else if (pid == 0) { - /* Child */ - setegid(gid); - if (ret < 0) { - perror("setegid"); - exit(EXIT_FAILURE); - } - ret = seteuid(uid); - if (ret < 0) { - perror("seteuid"); - exit(EXIT_FAILURE); - } - umask(0); - ret = (*cmd)(data); - if (!ret) - exit(EXIT_SUCCESS); - else - exit(EXIT_FAILURE); - } else { - return -1; - } -end: - return ret; -} - -int mkdir_recursive_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid) -{ - struct mkdir_data data; - - DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d", - path, mode, uid, gid); - data.path = path; - data.mode = mode; - return run_as(_mkdir_recursive, &data, uid, gid); -} - -int mkdir_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid) -{ - struct mkdir_data data; - - DBG3("mkdir() %s with mode %d for uid %d and gid %d", - path, mode, uid, gid); - data.path = path; - data.mode = mode; - return run_as(_mkdir, &data, uid, gid); -} - -int open_run_as(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) -{ - struct open_data data; - - DBG3("open() %s with flags %d mode %d for uid %d and gid %d", - path, flags, mode, uid, gid); - data.path = path; - data.flags = flags; - data.mode = mode; - return run_as(_open, &data, uid, gid); -} diff --git a/lttng-sessiond/utils.h b/lttng-sessiond/utils.h index b6c57c7e2..7bcd1a87e 100644 --- a/lttng-sessiond/utils.h +++ b/lttng-sessiond/utils.h @@ -18,17 +18,11 @@ #ifndef _LTT_UTILS_H #define _LTT_UTILS_H -#include - #ifndef __stringify #define __stringify1(x) #x #define __stringify(x) __stringify1(x) #endif -int mkdir_recursive_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid); -int mkdir_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid); -int open_run_as(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid); - const char *get_home_dir(void); int notify_thread_pipe(int wpipe); -- 2.34.1