selinux: unify systemd and udev code

This commit is contained in:
Kay Sievers 2012-04-17 16:05:03 +02:00
parent 75e37ac5b1
commit e9a5ef7cdd
14 changed files with 57 additions and 171 deletions

View File

@ -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 += \

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -1,84 +0,0 @@
/*
* libudev - interface to udev device information
*
* Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <selinux/selinux.h>
#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");
}

View File

@ -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,7 +185,7 @@ fail:
return r;
}
int label_fifofile_set(const char *path) {
int label_context_set(const char *path, mode_t mode) {
int r = 0;
#ifdef HAVE_SELINUX
@ -186,36 +194,7 @@ int label_fifofile_set(const char *path) {
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 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_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())

View File

@ -26,7 +26,7 @@
#include <stdbool.h>
#include <sys/socket.h>
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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -26,6 +26,7 @@
#include "libudev.h"
#include "libudev-private.h"
#include "util.h"
#include "label.h"
struct udev_event {
struct udev *udev;

View File

@ -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;

View File

@ -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;