KaiGai Kohei wrote: > If we have an entry something like "/selinux/permissive" to return > whether the given domain is permissive or not, I think we don't need > to have the flags field on security_compute_av(). It can be checked > on the creation of userspace avc entry, and checked it on later access > controls. The attached patch exposes a new entry in selinuxfs, which enables userspace stuff to make a query whether the given context is permissive domain, or not. If the given context is permissive domain, userspace stuffs can mark its entry as a permissive one on creation of avc entries, to avoid policy enforcement on permissive domains. It now checks security:{check_context} permission, but it should be discussed what permission to be checked here. The attached check_permissive.c is an example to use the interface. [kaigai@saba ~]$ ./check_permissive staff_u:staff_r:staff_t:s0 staff_u:staff_r:staff_t:s0 is a permissive domain [kaigai@saba ~]$ ./check_permissive user_u:user_r:user_t:s0 user_u:user_r:user_t:s0 is NOT a permissive domain Thanks, -- OSS Platform Development Division, NEC KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
Signed-off-by: KaiGai Kohei <kaigai@xxxxxxxxxxxxx> -- security/selinux/selinuxfs.c | 24 ++++++++++++++++++++++++ 1 files changed, 24 insertions(+), 0 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d3c8b98..10accc0 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -122,6 +122,7 @@ enum sel_inos { SEL_COMPAT_NET, /* whether to use old compat network packet controls */ SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ + SEL_PERMISSIVE, /* check whether permissive domain or not */ SEL_INO_NEXT, /* The next inode number to use */ }; @@ -513,6 +514,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size); static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size); static ssize_t sel_write_user(struct file *file, char *buf, size_t size); static ssize_t sel_write_member(struct file *file, char *buf, size_t size); +static ssize_t sel_write_permissive(struct file *file, char *buf, size_t size); static ssize_t (*write_op[])(struct file *, char *, size_t) = { [SEL_ACCESS] = sel_write_access, @@ -521,6 +523,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { [SEL_USER] = sel_write_user, [SEL_MEMBER] = sel_write_member, [SEL_CONTEXT] = sel_write_context, + [SEL_PERMISSIVE] = sel_write_permissive, }; static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) @@ -841,6 +844,26 @@ out: return length; } +static ssize_t sel_write_permissive(struct file *file, char *buf, size_t size) +{ + u32 sid; + ssize_t rc; + + /* + * MEMO: Is it correct to check security:{check_context} here? + * Or, we should add something like security:{check_permissive}? + */ + rc = task_has_security(current, SECURITY__CHECK_CONTEXT); + if (rc) + return rc; + + rc = security_context_to_sid(buf, size, &sid); + if (rc < 0) + return rc; + + return security_permissive_sid(sid); +} + static struct inode *sel_make_inode(struct super_block *sb, int mode) { struct inode *ret = new_inode(sb); @@ -1668,6 +1691,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR}, [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, + [SEL_PERMISSIVE] = {"permissive", &transaction_ops, S_IRUGO|S_IWUGO}, /* last one */ {""} }; ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <selinux/selinux.h> int main(int argc, char *argv[]) { const char *path = "/selinux/permissive"; int fd, rc; if (argv[1] == NULL) { fprintf(stderr, "usage: %s <context>\n", argv[0]); return -1; } fd = open(path, O_RDWR); if (fd < 0) { fprintf(stderr, "could not open %s (%s)\n", path, strerror(errno)); return -1; } rc = write(fd, argv[1], strlen(argv[1])); if (rc < 0) { fprintf(stderr, "error: write('%s', '%s') (%s)\n", path, argv[1], strerror(errno)); return -1; } printf("%s is %s permissive domain\n", argv[1], rc ? "a" : "NOT a"); close(fd); return 0; }