From: Kay Sievers Date: Tue, 17 Apr 2012 14:05:03 +0000 (+0200) Subject: selinux: unify systemd and udev code X-Git-Tag: v183~272 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=e9a5ef7cddcfcdb29b5aef3896931132b6fd5165 selinux: unify systemd and udev code --- diff --git a/Makefile.am b/Makefile.am index 1371a7753..13c4ed169 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1340,19 +1340,12 @@ libudev_private_la_SOURCES =\ src/libudev/libudev-device-private.c \ src/libudev/libudev-queue-private.c -if HAVE_SELINUX -libudev_private_la_SOURCES +=\ - src/libudev/libudev-selinux-private.c -endif - libudev_private_la_CFLAGS = \ $(AM_CFLAGS) \ - $(SELINUX_CFLAGS) -fvisibility=default libudev_private_la_LIBADD = \ - libsystemd-shared.la \ - $(SELINUX_LIBS) + libsystemd-shared.la # ------------------------------------------------------------------------------ MANPAGES += \ diff --git a/src/core/main.c b/src/core/main.c index 9bcedbe71..e3ea868da 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1222,7 +1222,7 @@ int main(int argc, char *argv[]) { log_open(); - if (label_init() < 0) + if (label_init(NULL) < 0) goto finish; if (!is_reexec) diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 52fe52367..30046a51b 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -329,13 +329,14 @@ static int symlink_and_label(const char *old_path, const char *new_path) { assert(old_path); assert(new_path); - if ((r = label_symlinkfile_set(new_path)) < 0) + r = label_context_set(new_path, S_IFLNK); + if (r < 0) return r; if (symlink(old_path, new_path) < 0) r = -errno; - label_file_clear(); + label_context_clear(); return r; } diff --git a/src/core/socket.c b/src/core/socket.c index a43971765..31aff5bce 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -762,7 +762,8 @@ static int fifo_address_create( mkdir_parents(path, directory_mode); - if ((r = label_fifofile_set(path)) < 0) + r = label_context_set(path, S_IFIFO); + if (r < 0) goto fail; /* Enforce the right access mode for the fifo */ @@ -784,7 +785,7 @@ static int fifo_address_create( goto fail; } - label_file_clear(); + label_context_clear(); if (fstat(fd, &st) < 0) { r = -errno; @@ -804,7 +805,7 @@ static int fifo_address_create( return 0; fail: - label_file_clear(); + label_context_clear(); if (fd >= 0) close_nointr_nofail(fd); diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 4bdbb0aa2..eb2657a74 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -173,20 +173,4 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); unsigned long long ts_usec(const struct timespec *ts); unsigned long long now_usec(void); - -/* libudev-selinux-private.c */ -#ifndef HAVE_SELINUX -static inline void udev_selinux_init(struct udev *udev) {} -static inline void udev_selinux_exit(struct udev *udev) {} -static inline void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) {} -static inline void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) {} -static inline void udev_selinux_resetfscreatecon(struct udev *udev) {} -#else -void udev_selinux_init(struct udev *udev); -void udev_selinux_exit(struct udev *udev); -void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode); -void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode); -void udev_selinux_resetfscreatecon(struct udev *udev); -#endif - #endif diff --git a/src/libudev/libudev-selinux-private.c b/src/libudev/libudev-selinux-private.c deleted file mode 100644 index 03ca168b0..000000000 --- a/src/libudev/libudev-selinux-private.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -#include "libudev.h" -#include "libudev-private.h" - -static int selinux_enabled; -security_context_t selinux_prev_scontext; - -void udev_selinux_init(struct udev *udev) -{ - /* record the present security context */ - selinux_enabled = (is_selinux_enabled() > 0); - dbg(udev, "selinux=%i\n", selinux_enabled); - if (!selinux_enabled) - return; - matchpathcon_init_prefix(NULL, TEST_PREFIX "/dev"); - if (getfscreatecon(&selinux_prev_scontext) < 0) { - err(udev, "getfscreatecon failed\n"); - selinux_prev_scontext = NULL; - } -} - -void udev_selinux_exit(struct udev *udev) -{ - if (!selinux_enabled) - return; - freecon(selinux_prev_scontext); - selinux_prev_scontext = NULL; -} - -void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) -{ - security_context_t scontext = NULL; - - if (!selinux_enabled) - return; - if (matchpathcon(file, mode, &scontext) < 0) { - err(udev, "matchpathcon(%s) failed\n", file); - return; - } - if (lsetfilecon(file, scontext) < 0) - err(udev, "setfilecon %s failed: %m\n", file); - freecon(scontext); -} - -void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) -{ - security_context_t scontext = NULL; - - if (!selinux_enabled) - return; - - if (matchpathcon(file, mode, &scontext) < 0) { - err(udev, "matchpathcon(%s) failed\n", file); - return; - } - if (setfscreatecon(scontext) < 0) - err(udev, "setfscreatecon %s failed: %m\n", file); - freecon(scontext); -} - -void udev_selinux_resetfscreatecon(struct udev *udev) -{ - if (!selinux_enabled) - return; - if (setfscreatecon(selinux_prev_scontext) < 0) - err(udev, "setfscreatecon failed: %m\n"); -} diff --git a/src/shared/label.c b/src/shared/label.c index dce6f45c8..bd38f0ba6 100644 --- a/src/shared/label.c +++ b/src/shared/label.c @@ -51,7 +51,7 @@ void label_retest_selinux(void) { #endif -int label_init(void) { +int label_init(const char *prefix) { int r = 0; #ifdef HAVE_SELINUX @@ -67,7 +67,15 @@ int label_init(void) { before_mallinfo = mallinfo(); before_timestamp = now(CLOCK_MONOTONIC); - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); + if (prefix) { + struct selinux_opt options[] = { + { .type = SELABEL_OPT_SUBSET, .value = prefix }, + }; + + label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); + } else + 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"); @@ -177,36 +185,7 @@ fail: return r; } -int label_fifofile_set(const char *path) { - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t filecon = NULL; - - if (!use_selinux() || !label_hnd) - return 0; - - r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFIFO); - if (r < 0) - r = -errno; - else if (r == 0) { - r = setfscreatecon(filecon); - if (r < 0) { - log_error("Failed to set SELinux file context on %s: %m", path); - r = -errno; - } - - freecon(filecon); - } - - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif - - return r; -} - -int label_symlinkfile_set(const char *path) { +int label_context_set(const char *path, mode_t mode) { int r = 0; #ifdef HAVE_SELINUX @@ -215,7 +194,7 @@ int label_symlinkfile_set(const char *path) { if (!use_selinux() || !label_hnd) return 0; - r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFLNK); + r = selabel_lookup_raw(label_hnd, &filecon, path, mode); if (r < 0) r = -errno; else if (r == 0) { @@ -253,7 +232,7 @@ int label_socket_set(const char *label) { return 0; } -void label_file_clear(void) { +void label_context_clear(void) { #ifdef HAVE_SELINUX if (!use_selinux()) diff --git a/src/shared/label.h b/src/shared/label.h index ccf405bbe..3f880e363 100644 --- a/src/shared/label.h +++ b/src/shared/label.h @@ -26,7 +26,7 @@ #include #include -int label_init(void); +int label_init(const char *prefix); void label_finish(void); int label_fix(const char *path, bool ignore_enoent); @@ -34,9 +34,8 @@ int label_fix(const char *path, bool ignore_enoent); int label_socket_set(const char *label); void label_socket_clear(void); -int label_fifofile_set(const char *path); -int label_symlinkfile_set(const char *path); -void label_file_clear(void); +int label_context_set(const char *path, mode_t mode); +void label_context_clear(void); void label_free(const char *label); diff --git a/src/test/test-udev.c b/src/test/test-udev.c index a39ba7211..64bb5cbc3 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) if (udev == NULL) exit(EXIT_FAILURE); log_debug("version %s\n", VERSION); - udev_selinux_init(udev); + label_init("/dev"); sigprocmask(SIG_SETMASK, NULL, &sigmask_orig); @@ -113,7 +113,7 @@ out: udev_event_unref(event); udev_device_unref(dev); udev_rules_unref(rules); - udev_selinux_exit(udev); + label_finish(); udev_unref(udev); if (err != 0) return EXIT_FAILURE; diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 15913089b..5db827eca 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -562,7 +562,7 @@ static int glob_item(Item *i, int (*action)(Item *, const char *)) { } static int create_item(Item *i) { - int r; + int r, e; mode_t u; struct stat st; @@ -584,8 +584,12 @@ static int create_item(Item *i) { i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0; u = umask(0); + label_context_set(i->path, S_IFREG); fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode); + e = errno; + label_context_clear(); umask(u); + errno = e; if (fd < 0) { if (i->type == WRITE_FILE && errno == ENOENT) @@ -696,7 +700,12 @@ static int create_item(Item *i) { case CREATE_SYMLINK: { char *x; + label_context_set(i->path, S_IFLNK); r = symlink(i->argument, i->path); + e = errno; + label_context_clear(); + errno = e; + if (r < 0 && errno != EEXIST) { log_error("symlink(%s, %s) failed: %m", i->argument, i->path); return -errno; @@ -722,8 +731,12 @@ static int create_item(Item *i) { case CREATE_CHAR_DEVICE: { u = umask(0); + label_context_set(i->path, CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR); r = mknod(i->path, i->mode | (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR), i->major_minor); + e = errno; + label_context_clear(); umask(u); + errno = e; if (r < 0 && errno != EEXIST) { log_error("Failed to create device node %s: %m", i->path); @@ -1248,7 +1261,7 @@ int main(int argc, char *argv[]) { umask(0022); - label_init(); + label_init(NULL); items = hashmap_new(string_hash_func, string_compare_func); globs = hashmap_new(string_hash_func, string_compare_func); diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 20aa7c865..3c9846f15 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -91,7 +91,7 @@ static int node_symlink(struct udev *udev, const char *node, const char *slink) buf[len] = '\0'; if (strcmp(target, buf) == 0) { log_debug("preserve already existing symlink '%s' to '%s'\n", slink, target); - udev_selinux_lsetfilecon(udev, slink, S_IFLNK); + label_fix(slink, true); utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); goto exit; } @@ -103,11 +103,11 @@ static int node_symlink(struct udev *udev, const char *node, const char *slink) err = mkdir_parents(slink, 0755); if (err != 0 && err != -ENOENT) break; - udev_selinux_setfscreatecon(udev, slink, S_IFLNK); + label_context_set(slink, S_IFLNK); err = symlink(target, slink); if (err != 0) err = -errno; - udev_selinux_resetfscreatecon(udev); + label_context_clear(); } while (err == -ENOENT); if (err == 0) goto exit; @@ -120,11 +120,11 @@ static int node_symlink(struct udev *udev, const char *node, const char *slink) err = mkdir_parents(slink_tmp, 0755); if (err != 0 && err != -ENOENT) break; - udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK); + label_context_set(slink_tmp, S_IFLNK); err = symlink(target, slink_tmp); if (err != 0) err = -errno; - udev_selinux_resetfscreatecon(udev); + label_context_clear(); } while (err == -ENOENT); if (err != 0) { log_error("symlink '%s' '%s' failed: %m\n", target, slink_tmp); @@ -269,7 +269,6 @@ void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev static int node_fixup(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid) { - struct udev *udev = udev_device_get_udev(dev); const char *devnode = udev_device_get_devnode(dev); dev_t devnum = udev_device_get_devnum(dev); struct stat stats; @@ -308,7 +307,7 @@ static int node_fixup(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid * something else has set a custom context in the meantime. */ if (strcmp(udev_device_get_action(dev), "add") == 0) - udev_selinux_lsetfilecon(udev, devnode, mode); + label_fix(devnode, true); /* always update timestamp when we re-use the node, like on media change events */ utimensat(AT_FDCWD, devnode, NULL, 0); diff --git a/src/udev/udev.h b/src/udev/udev.h index e229faaa4..aaaf63220 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -26,6 +26,7 @@ #include "libudev.h" #include "libudev-private.h" #include "util.h" +#include "label.h" struct udev_event { struct udev *udev; diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 2b4a845d7..5217d7f9d 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) log_open(); log_parse_environment(); udev_set_log_fn(udev, udev_main_log); - udev_selinux_init(udev); + label_init("/dev"); for (;;) { int option; @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) adm_help(udev, argc, argv); rc = 2; out: - udev_selinux_exit(udev); + label_finish(); udev_unref(udev); log_close(); return rc; diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 20de5cfc2..16751144b 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -858,11 +858,11 @@ static void static_dev_create_from_modules(struct udev *udev) util_strscpyl(filename, sizeof(filename), "/dev/", devname, NULL); mkdir_parents(filename, 0755); - udev_selinux_setfscreatecon(udev, filename, mode); + label_context_set(filename, mode); log_debug("mknod '%s' %c%u:%u\n", filename, type, maj, min); if (mknod(filename, mode, makedev(maj, min)) < 0 && errno == EEXIST) utimensat(AT_FDCWD, filename, NULL, 0); - udev_selinux_resetfscreatecon(udev); + label_context_clear(); } fclose(f); @@ -888,10 +888,10 @@ static void static_dev_create_links(struct udev *udev) struct stat sb; if (stat(stdlinks[i].target, &sb) == 0) { - udev_selinux_setfscreatecon(udev, stdlinks[i].link, S_IFLNK); + label_context_set(stdlinks[i].link, S_IFLNK); if (symlink(stdlinks[i].target, stdlinks[i].link) < 0 && errno == EEXIST) utimensat(AT_FDCWD, stdlinks[i].link, NULL, AT_SYMLINK_NOFOLLOW); - udev_selinux_resetfscreatecon(udev); + label_context_clear(); } } } @@ -1077,7 +1077,7 @@ int main(int argc, char *argv[]) log_parse_environment(); udev_set_log_fn(udev, udev_main_log); log_debug("version %s\n", VERSION); - udev_selinux_init(udev); + label_init("/dev"); for (;;) { int option; @@ -1607,7 +1607,7 @@ exit_daemonize: udev_queue_export_unref(udev_queue_export); udev_ctrl_connection_unref(ctrl_conn); udev_ctrl_unref(udev_ctrl); - udev_selinux_exit(udev); + label_finish(); udev_unref(udev); log_close(); return rc;