From 56cf987fe74270bde4e16c7ec9e0414a9030723b Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Wed, 28 Jul 2010 09:39:54 -0400 Subject: Systemd is causing mislabeled devices to be created and then attempting to read them. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 07/28/2010 05:57 AM, Kay Sievers wrote: > On Wed, Jul 28, 2010 at 11:43, Lennart Poettering > wrote: >> On Mon, 26.07.10 16:42, Daniel J Walsh (dwalsh@redhat.com) wrote: >>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file >>> type=1400 audit(1280174589.476:7): avc: denied { read } for pid=1 >>> comm="systemd" name="autofs" dev=devtmpfs ino=9482 >>> scontext=system_u:system_r:init_t:s0 >>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file >>> type=1400 audit(1280174589.476:8): avc: denied { read } for pid=1 >>> comm="systemd" name="autofs" dev=devtmpfs ino=9482 >>> scontext=system_u:system_r:init_t:s0 >>> tcontext=system_u:object_r:device_t:s0 tclass=chr_file >>> >>> Lennart, we talked about this earlier. I think this is caused by the >>> modprobe calls to create /dev/autofs. Since udev is not created at the >>> point that init loads the kernel modules, the devices get created with >>> the wrong label. Once udev starts the labels get fixed. >>> >>> I can allow init_t to read device_t chr_files. >> >> Hmm, I think a cleaner fix would be to make systemd relabel this device >> properly before accessing it? Given that this is only one device this >> should not be a problem for us to maintain, I think? How would the >> fixing of the label work? Would we have to spawn restorecon for this, or >> can we actually do this in C without too much work? > > I guess we can just do what udev is doing, and call setfilecon(), with > a context of an earlier matchpathcon(). > > Kay > _______________________________________________ > systemd-devel mailing list > systemd-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/systemd-devel Here is the updated patch with a fix for the labeling of /dev/autofs -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/ iEYEARECAAYFAkxQMyoACgkQrlYvE4MpobNviACfWgxsjW2xzz1qznFex8RVAQHf gIEAmwRmRcLvGqYtwQaZ3WKIg8wmrwNk =pC2e --- configure.ac | 21 +++-- src/automount.c | 2 + src/main.c | 5 ++ src/socket-util.c | 13 ++- src/socket-util.h | 3 +- src/socket.c | 94 +++------------------ src/util.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/util.h | 10 +++ 8 files changed, 293 insertions(+), 99 deletions(-) diff --git a/configure.ac b/configure.ac index 14622e47a0..65c8af0115 100644 --- a/configure.ac +++ b/configure.ac @@ -105,15 +105,26 @@ PKG_CHECK_MODULES(DBUS, [ dbus-1 >= 1.3.2 ]) AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) -PKG_CHECK_MODULES(SELINUX, [ libselinux ]) -AC_SUBST(SELINUX_CFLAGS) -AC_SUBST(SELINUX_LIBS) -AC_SEARCH_LIBS([is_selinux_enabled], [selinux], [], [AC_MSG_ERROR([*** libselinux library not found])]) - PKG_CHECK_MODULES(DBUSGLIB, [ dbus-glib-1 ]) AC_SUBST(DBUSGLIB_CFLAGS) AC_SUBST(DBUSGLIB_LIBS) +have_selinux=no +AC_ARG_ENABLE(selinux, AS_HELP_STRING([--disable-selinux], [Disable optional SELINUX support])) +if test "x$enable_selinux" != "xno"; then + # not using PKG_CHECK_MODULES as for some reason libselinux didn't + # install any pkg-config modules here + AC_SEARCH_LIBS([getcon], [selinux], + [AC_DEFINE(HAVE_SELINUX, 1, [Define if SELINUX is available]) have_selinux=yes], + have_selinux=no) + AC_SUBST(SELINUX_CFLAGS) + AC_SUBST(SELINUX_LIBS) + if test "x$have_selinux" = xno -a "x$enable_selinux" = xyes; then + AC_MSG_ERROR([*** selinux support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_SELINUX, [test "$have_selinux" = "yes"]) + AC_ARG_ENABLE([tcpwrap], AS_HELP_STRING([--disable-tcpwrap],[Disable optional TCP wrappers support]), [case "${enableval}" in diff --git a/src/automount.c b/src/automount.c index 213b178eae..3a69cf9b4c 100644 --- a/src/automount.c +++ b/src/automount.c @@ -304,6 +304,8 @@ static int open_dev_autofs(Manager *m) { if (m->dev_autofs_fd >= 0) return m->dev_autofs_fd; + label_fix("/dev/autofs"); + if ((m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY)) < 0) { log_error("Failed to open /dev/autofs: %s", strerror(errno)); return -errno; diff --git a/src/main.c b/src/main.c index e67d2225bd..36dea9b3c6 100644 --- a/src/main.c +++ b/src/main.c @@ -836,6 +836,9 @@ int main(int argc, char *argv[]) { return 1; } + if (label_init() < 0) + goto finish; + log_show_color(isatty(STDERR_FILENO) > 0); log_show_location(false); log_set_max_level(LOG_INFO); @@ -1113,5 +1116,7 @@ finish: if (getpid() == 1) freeze(); + label_finish(); + return retval; } diff --git a/src/socket-util.c b/src/socket-util.c index 3a00fcf43f..2af8563965 100644 --- a/src/socket-util.c +++ b/src/socket-util.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "macro.h" #include "util.h" @@ -306,7 +305,7 @@ int socket_address_listen( bool free_bind, mode_t directory_mode, mode_t socket_mode, - security_context_t scon, + const char *label, int *ret) { int r, fd, one; @@ -316,16 +315,14 @@ int socket_address_listen( if ((r = socket_address_verify(a)) < 0) return r; - if (setsockcreatecon(scon) < 0) { - log_error("Failed to set SELinux context (%s) on socket: %m", scon); - if (security_getenforce() == 1) - return -errno; - } + r = label_socket_set(label); + if (r < 0) + return r; fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); r = fd < 0 ? -errno : 0; - setsockcreatecon(NULL); + label_socket_clear(); if (r < 0) return r; diff --git a/src/socket-util.h b/src/socket-util.h index 841570f002..86c9e47809 100644 --- a/src/socket-util.h +++ b/src/socket-util.h @@ -26,7 +26,6 @@ #include #include #include -#include #include "macro.h" #include "util.h" @@ -72,7 +71,7 @@ int socket_address_listen( bool free_bind, mode_t directory_mode, mode_t socket_mode, - security_context_t scon, + const char *label, int *ret); bool socket_address_is(const SocketAddress *a, const char *s, int type); diff --git a/src/socket.c b/src/socket.c index 2da3215a3d..2a5270f336 100644 --- a/src/socket.c +++ b/src/socket.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "unit.h" #include "socket.h" @@ -653,89 +652,25 @@ static void socket_apply_fifo_options(Socket *s, int fd) { log_warning("F_SETPIPE_SZ: %m"); } -static int selinux_getconfromexe( - const char *exe, - security_context_t *newcon) { - - security_context_t mycon = NULL, fcon = NULL; - security_class_t sclass; - int r = 0; - - r = getcon(&mycon); - if (r < 0) - goto fail; - - r = getfilecon(exe, &fcon); - if (r < 0) - goto fail; - - sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, newcon); - -fail: - if (r < 0) - r = -errno; - - freecon(mycon); - freecon(fcon); - return r; -} - -static int selinux_getfileconfrompath( - const security_context_t scon, - const char *path, - const char *class, - security_context_t *fcon) { - - security_context_t dir_con = NULL; - security_class_t sclass; - int r = 0; - - r = getfilecon(path, &dir_con); - if (r >= 0) { - r = -1; - if ((sclass = string_to_security_class(class)) != 0) - r = security_compute_create(scon, dir_con, sclass, fcon); - } - if (r < 0) - r = -errno; - - freecon(dir_con); - return r; -} static int fifo_address_create( const char *path, mode_t directory_mode, mode_t socket_mode, - security_context_t scon, + const char *label, int *_fd) { int fd = -1, r = 0; struct stat st; mode_t old_mask; - security_context_t filecon = NULL; assert(path); assert(_fd); mkdir_parents(path, directory_mode); - if (scon) { - if (scon && ((r = selinux_getfileconfrompath(scon, path, "fifo_file", &filecon)) == 0)) { - r = setfscreatecon(filecon); - - if (r < 0) { - log_error("Failed to set SELinux file context (%s) on %s: %m", scon, path); - r = -errno; - } - - freecon(filecon); - } - - if (r < 0 && security_getenforce() == 1) - goto fail; - } + if ((r = label_fifofile_set(label, path)) < 0) + goto fail; /* Enforce the right access mode for the fifo */ old_mask = umask(~ socket_mode); @@ -756,7 +691,7 @@ static int fifo_address_create( goto fail; } - setfscreatecon(NULL); + label_file_clear(); if (fstat(fd, &st) < 0) { r = -errno; @@ -776,7 +711,8 @@ static int fifo_address_create( return 0; fail: - setfscreatecon(NULL); + label_file_clear(); + if (fd >= 0) close_nointr_nofail(fd); @@ -786,20 +722,16 @@ fail: static int socket_open_fds(Socket *s) { SocketPort *p; int r; - security_context_t scon = NULL; + char *label = NULL; assert(s); if ((r = socket_instantiate_service(s)) < 0) return r; - if (selinux_getconfromexe(s->service->exec_command[SERVICE_EXEC_START]->path, &scon) < 0) { - log_error("Failed to get SELinux exec context for %s \n", s->service->exec_command[SERVICE_EXEC_START]->path); - if (security_getenforce() == 1) - return -errno; - } + if ((r = label_get_socket_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label)) < 0) + return r; - log_debug("SELinux Socket context for %s set to %s\n", s->service->exec_command[SERVICE_EXEC_START]->path, scon); LIST_FOREACH(port, p, s->ports) { if (p->fd >= 0) @@ -815,7 +747,7 @@ static int socket_open_fds(Socket *s) { s->free_bind, s->directory_mode, s->socket_mode, - scon, + label, &p->fd)) < 0) goto rollback; @@ -827,7 +759,7 @@ static int socket_open_fds(Socket *s) { p->path, s->directory_mode, s->socket_mode, - scon, + label, &p->fd)) < 0) goto rollback; @@ -837,12 +769,12 @@ static int socket_open_fds(Socket *s) { assert_not_reached("Unknown port type"); } - freecon(scon); + label_free(label); return 0; rollback: socket_close_fds(s); - freecon(scon); + label_free(label); return r; } diff --git a/src/util.c b/src/util.c index da8a6c3336..2279efac49 100644 --- a/src/util.c +++ b/src/util.c @@ -56,6 +56,244 @@ #include "log.h" #include "strv.h" +#if HAVE_SELINUX +#include +#include + +static struct selabel_handle *label_hnd = NULL; + +static inline int use_selinux(void) { + static int use_selinux_ind = -1; + + if (use_selinux_ind == -1) + use_selinux_ind = (is_selinux_enabled() == 1); + + return use_selinux_ind; +} + +static int label_get_file_label_from_path( + const char *label, + const char *path, + const char *class, + security_context_t *fcon) { + + security_context_t dir_con = NULL; + security_class_t sclass; + int r = 0; + + r = getfilecon(path, &dir_con); + if (r >= 0) { + r = -1; + if ((sclass = string_to_security_class(class)) != 0) + r = security_compute_create((security_context_t) label, dir_con, sclass, fcon); + } + if (r < 0) + r = -errno; + + freecon(dir_con); + return r; +} + +#endif + +int label_init(void) { + int r = 0; + +#if HAVE_SELINUX + if (use_selinux()) { + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + if (!label_hnd) { + log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, "Failed to initialize SELinux context: %m"); + r = (security_getenforce() == 1) ? -errno : 0; + } + } +#endif + + return r; +} + +int label_fix(const char *path) { + int r = 0; +#if HAVE_SELINUX + struct stat st; + security_context_t fcon; + if (use_selinux()) { + r = lstat(path, &st); + + if (r == 0) { + r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); + + if (r == 0) { + r = setfilecon(path, fcon); + freecon(fcon); + } + } + if (r < 0) { + log_error("Unable to fix label of %s: %m", path); + r = (security_getenforce() == 1) ? -errno : 0; + } + } +#endif + return r; +} + +void label_finish(void) { + +#if HAVE_SELINUX + if (use_selinux()) + selabel_close(label_hnd); +#endif + +} + +int label_get_socket_label_from_exe( + const char *exe, + char **label) { + int r = 0; + +#if HAVE_SELINUX + security_context_t mycon = NULL, fcon = NULL; + security_class_t sclass; + + r = getcon(&mycon); + if (r < 0) + goto fail; + + r = getfilecon(exe, &fcon); + if (r < 0) + goto fail; + + sclass = string_to_security_class("process"); + r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + if (r == 0) + log_debug("SELinux Socket context for %s will be set to %s", exe, *label); + +fail: + if (r< 0 && security_getenforce() == 1) + r = -errno; + + freecon(mycon); + freecon(fcon); +#endif + + return r; +} + +int label_fifofile_set(const char *label, const char *path) { + int r = 0; + +#if HAVE_SELINUX + security_context_t filecon = NULL; + if (use_selinux() && label) { + if (((r = label_get_file_label_from_path(label, path, "fifo_file", &filecon)) == 0)) { + if ((r = setfscreatecon(filecon)) < 0) { + log_error("Failed to set SELinux file context (%s) on %s: %m", label, path); + r = -errno; + } + + freecon(filecon); + } + + if (r < 0 && security_getenforce() == 0) + r = 0; + } +#endif + + return r; +} + +int label_socket_set(const char *label) { + +#if HAVE_SELINUX + if (use_selinux() && setsockcreatecon((security_context_t) label) < 0) { + log_error("Failed to set SELinux context (%s) on socket: %m", label); + if (security_getenforce() == 1) + return -errno; + } +#endif + + return 0; +} + +void label_file_clear(void) { + +#if HAVE_SELINUX + if (use_selinux()) + setfscreatecon(NULL); +#endif + + return; +} + +void label_free(const char *label) { + +#if HAVE_SELINUX + if (use_selinux()) + freecon((security_context_t) label); +#endif + + return; +} + +void label_socket_clear(void) { + +#if HAVE_SELINUX + if (use_selinux()) + setsockcreatecon(NULL); +#endif + + return; +} + +static int label_mkdir( + const char *path, + mode_t mode) { + +#if HAVE_SELINUX + int r; + security_context_t fcon = NULL; + + if (use_selinux()) { + if (path[0] == '/') { + r = selabel_lookup_raw(label_hnd, &fcon, path, mode); + } + else { + char *cwd = NULL; + char *newpath = NULL; + cwd = getcwd(NULL,0); + if ((! cwd) || (asprintf(&newpath, "%s/%s",cwd,path) < 0)) { + free(cwd); + return -errno; + } + r = selabel_lookup_raw(label_hnd, &fcon, newpath, mode); + free(cwd); + free(newpath); + } + + if (r == 0) + r = setfscreatecon(fcon); + + if ((r < 0) && (errno != ENOENT)) { + log_error("Failed to set security context %s for %s", fcon, path); + + if (security_getenforce() == 1) + goto finish; + } + } + r = mkdir(path, mode); + +finish: + if (use_selinux()) { + setfscreatecon(NULL); + freecon(fcon); + } + + return r; +#else + return mkdir(path, mode); +#endif +} + bool streq_ptr(const char *a, const char *b) { /* Like streq(), but tries to make sense of NULL pointers */ @@ -969,7 +1207,7 @@ char *file_in_same_dir(const char *path, const char *filename) { int safe_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { struct stat st; - if (mkdir(path, mode) >= 0) + if (label_mkdir(path, mode) >= 0) if (chmod_and_chown(path, mode, uid, gid) < 0) return -errno; @@ -1012,7 +1250,7 @@ int mkdir_parents(const char *path, mode_t mode) { if (!(t = strndup(path, e - path))) return -ENOMEM; - r = mkdir(t, mode); + r = label_mkdir(t, mode); free(t); if (r < 0 && errno != EEXIST) @@ -1028,7 +1266,7 @@ int mkdir_p(const char *path, mode_t mode) { if ((r = mkdir_parents(path, mode)) < 0) return r; - if (mkdir(path, mode) < 0 && errno != EEXIST) + if (label_mkdir(path, mode) < 0 && errno != EEXIST) return -errno; return 0; diff --git a/src/util.h b/src/util.h index 782adb8348..b097dc9b7b 100644 --- a/src/util.h +++ b/src/util.h @@ -360,4 +360,14 @@ int ip_tos_from_string(const char *s); const char *signal_to_string(int i); int signal_from_string(const char *s); +int label_init(void); +int label_fix(const char *path); +void label_finish(void); +int label_socket_set(const char *label); +void label_socket_clear(void); +int label_fifofile_set(const char *label, const char *path); +void label_file_clear(void); +void label_free(const char *label); +int label_get_socket_label_from_exe(const char *exe, char **label); + #endif -- cgit v1.2.3-54-g00ecf