diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | selinux.h | 131 | ||||
-rw-r--r-- | udev-add.c | 10 |
3 files changed, 149 insertions, 0 deletions
@@ -25,6 +25,8 @@ USE_LOG = true # Leave this set to `false' for production use. DEBUG = false +# Set this to compile with Security-Enhanced Linux support. +USE_SELINUX = false ROOT = udev DAEMON = udevd @@ -170,6 +172,11 @@ else LDFLAGS = endif +ifeq ($(strip $(USE_SELINUX)),true) + CFLAGS += -DUSE_SELINUX + LIB_OBJS += -lselinux +endif + CFLAGS += -I$(PWD)/libsysfs # config files automatically generated @@ -222,6 +229,7 @@ HEADERS = udev.h \ udevdb.h \ klibc_fixups.h \ logging.h \ + selinux.h \ list.h ifeq ($(strip $(USE_KLIBC)),true) diff --git a/selinux.h b/selinux.h new file mode 100644 index 0000000000..475a60d6d2 --- /dev/null +++ b/selinux.h @@ -0,0 +1,131 @@ +#ifndef SELINUX_H +#define SELINUX_H + +#ifndef USE_SELINUX + +static inline void selinux_setfilecon(char *file, unsigned int mode) { } +static inline void selinux_setfscreatecon(char *file, unsigned int mode) {} +static inline void selinux_init(void) {} +static inline void selinux_restore(void) {} + +#else + +#include <selinux/selinux.h> +#include <stdio.h> +#include <limits.h> +#include <ctype.h> + + +static int selinux_enabled=-1; +static security_context_t prev_scontext=NULL; + +static inline int is_selinux_running(void) { + if ( selinux_enabled==-1 ) + return selinux_enabled=is_selinux_enabled()>0; + return selinux_enabled; +} + +static inline int selinux_get_media(char *path, int mode, char **media) +{ + FILE *fp; + char buf[PATH_MAX]; + char mediabuf[PATH_MAX]; + *media=NULL; + if (!( mode && S_IFBLK )) { + return -1; + } + snprintf(buf,sizeof(buf), "/proc/ide/%s/media", basename(path)); + fp=fopen(buf,"r"); + if (fp) { + if (fgets(mediabuf,sizeof(mediabuf), fp)) { + int size=strlen(mediabuf); + while (size-- > 0) { + if (isspace(mediabuf[size])) { + mediabuf[size]='\0'; + } else { + break; + } + } + *media=strdup(mediabuf); + info("selinux_get_media(%s)->%s \n", path, *media); + } + fclose(fp); + return 0; + } else { + return -1; + } +} + +static inline void selinux_setfilecon(char *file, unsigned int mode) { + if (is_selinux_running()) { + security_context_t scontext=NULL; + char *media; + int ret=selinux_get_media(file, mode, &media); + if ( ret== 0) { + ret = matchmediacon(media, &scontext); + free(media); + } + if (ret==-1) + if (matchpathcon(file, mode, &scontext) < 0) { + dbg("matchpathcon(%s) failed\n", file); + return; + } + if (setfilecon(file, scontext) < 0) + dbg("setfiles %s failed with error '%s'", + file, strerror(errno)); + freecon(scontext); + } +} + +static inline void selinux_setfscreatecon(char *file, unsigned int mode) { + int retval = 0; + security_context_t scontext=NULL; + + if (is_selinux_running()) { + char *media; + int ret=selinux_get_media(file, mode, &media); + if ( ret== 0) { + ret = matchmediacon(media, &scontext); + free(media); + } + + if (ret==-1) + if (matchpathcon(file, mode, &scontext) < 0) { + dbg("matchpathcon(%s) failed\n", file); + return; + } + + retval=setfscreatecon(scontext); + if (retval < 0) + dbg("setfiles %s failed with error '%s'", + file, strerror(errno)); + freecon(scontext); + } +} +static inline void selinux_init(void) { + /* record the present security context, for file-creation + * restoration creation purposes. + * + */ + + if (is_selinux_running()) + { + if (getfscreatecon(&prev_scontext) < 0) { + dbg("getfscreatecon failed\n"); + } + prev_scontext=NULL; + } +} +static inline void selinux_restore(void) { + if (is_selinux_running()) { + /* reset the file create context to its former glory */ + if ( setfscreatecon(prev_scontext) < 0 ) + dbg("setfscreatecon failed\n"); + if (prev_scontext) { + freecon(prev_scontext); + prev_scontext=NULL; + } + } +} +#endif /* USE_SELINUX */ +#endif /* SELINUX_H */ diff --git a/udev-add.c b/udev-add.c index 1f69329788..e1e145de8a 100644 --- a/udev-add.c +++ b/udev-add.c @@ -50,6 +50,8 @@ #define LOCAL_USER "$local" +#include "selinux.h" + /* * Right now the major/minor of a device is stored in a file called * "dev" in sysfs. @@ -92,6 +94,7 @@ static int create_path(char *file) break; *pos = 0x00; if (stat(p, &stats)) { + selinux_setfscreatecon(p, S_IFDIR); retval = mkdir(p, 0755); if (retval != 0) { dbg("mkdir(%s) failed with error '%s'", @@ -99,6 +102,8 @@ static int create_path(char *file) return retval; } dbg("created '%s'", p); + } else { + selinux_setfilecon(p, S_IFDIR); } *pos = '/'; } @@ -117,6 +122,7 @@ static int make_node(char *file, int major, int minor, unsigned int mode, uid_t if (((stats.st_mode & S_IFMT) == S_IFBLK || (stats.st_mode & S_IFMT) == S_IFCHR) && (stats.st_rdev == makedev(major, minor))) { dbg("preserve file '%s', cause it has correct dev_t", file); + selinux_setfilecon(file,stats.st_mode); goto perms; } @@ -126,6 +132,7 @@ static int make_node(char *file, int major, int minor, unsigned int mode, uid_t dbg("already present file '%s' unlinked", file); create: + selinux_setfscreatecon(file, mode); retval = mknod(file, mode, makedev(major, minor)); if (retval != 0) { dbg("mknod(%s, %#o, %u, %u) failed with error '%s'", @@ -304,6 +311,7 @@ static int create_node(struct udevice *dev, int fake) dbg("symlink(%s, %s)", linktarget, filename); if (!fake) { + selinux_setfscreatecon(filename, S_IFLNK); unlink(filename); if (symlink(linktarget, filename) != 0) dbg("symlink(%s, %s) failed with error '%s'", @@ -438,6 +446,7 @@ int udev_add_device(const char *path, const char *subsystem, int fake) dbg("name='%s'", dev.name); + selinux_init(); switch (dev.type) { case 'b': case 'c': @@ -475,6 +484,7 @@ int udev_add_device(const char *path, const char *subsystem, int fake) } exit: + selinux_restore(); sysfs_close_class_device(class_dev); return retval; |