From 12b29f34558b9b45a2c6eabd4f3c6be939a3980f Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 7 May 2008 13:03:20 -0400 Subject: selinux: support deferred mapping of contexts Introduce SELinux support for deferred mapping of security contexts in the SID table upon policy reload, and use this support for inode security contexts when the context is not yet valid under the current policy. Only processes with CAP_MAC_ADMIN + mac_admin permission in policy can set undefined security contexts on inodes. Inodes with such undefined contexts are treated as having the unlabeled context until the context becomes valid upon a policy reload that defines the context. Context invalidation upon policy reload also uses this support to save the context information in the SID table and later recover it upon a subsequent policy reload that defines the context again. This support is to enable package managers and similar programs to set down file contexts unknown to the system policy at the time the file is created in order to better support placing loadable policy modules in packages and to support build systems that need to create images of different distro releases with different policies w/o requiring all of the contexts to be defined or legal in the build host policy. With this patch applied, the following sequence is possible, although in practice it is recommended that this permission only be allowed to specific program domains such as the package manager. # rmdir baz # rm bar # touch bar # chcon -t foo_exec_t bar # foo_exec_t is not yet defined chcon: failed to change context of `bar' to `system_u:object_r:foo_exec_t': Invalid argument # mkdir -Z system_u:object_r:foo_exec_t baz mkdir: failed to set default file creation context to `system_u:object_r:foo_exec_t': Invalid argument # cat setundefined.te policy_module(setundefined, 1.0) require { type unconfined_t; type unlabeled_t; } files_type(unlabeled_t) allow unconfined_t self:capability2 mac_admin; # make -f /usr/share/selinux/devel/Makefile setundefined.pp # semodule -i setundefined.pp # chcon -t foo_exec_t bar # foo_exec_t is not yet defined # mkdir -Z system_u:object_r:foo_exec_t baz # ls -Zd bar baz -rw-r--r-- root root system_u:object_r:unlabeled_t bar drwxr-xr-x root root system_u:object_r:unlabeled_t baz # cat foo.te policy_module(foo, 1.0) type foo_exec_t; files_type(foo_exec_t) # make -f /usr/share/selinux/devel/Makefile foo.pp # semodule -i foo.pp # defines foo_exec_t # ls -Zd bar baz -rw-r--r-- root root user_u:object_r:foo_exec_t bar drwxr-xr-x root root system_u:object_r:foo_exec_t baz # semodule -r foo # ls -Zd bar baz -rw-r--r-- root root system_u:object_r:unlabeled_t bar drwxr-xr-x root root system_u:object_r:unlabeled_t baz # semodule -i foo.pp # ls -Zd bar baz -rw-r--r-- root root user_u:object_r:foo_exec_t bar drwxr-xr-x root root system_u:object_r:foo_exec_t baz # semodule -r setundefined foo # chcon -t foo_exec_t bar # no longer defined and not allowed chcon: failed to change context of `bar' to `system_u:object_r:foo_exec_t': Invalid argument # rmdir baz # mkdir -Z system_u:object_r:foo_exec_t baz mkdir: failed to set default file creation context to `system_u:object_r:foo_exec_t': Invalid argument Signed-off-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1c864c0efe2..59c6e98f7be 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2495,7 +2495,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, } if (value && len) { - rc = security_sid_to_context(newsid, &context, &clen); + rc = security_sid_to_context_force(newsid, &context, &clen); if (rc) { kfree(namep); return rc; @@ -2669,6 +2669,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, return rc; rc = security_context_to_sid(value, size, &newsid); + if (rc == -EINVAL) { + if (!capable(CAP_MAC_ADMIN)) + return rc; + rc = security_context_to_sid_force(value, size, &newsid); + } if (rc) return rc; @@ -2703,10 +2708,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, return; } - rc = security_context_to_sid(value, size, &newsid); + rc = security_context_to_sid_force(value, size, &newsid); if (rc) { - printk(KERN_WARNING "%s: unable to obtain SID for context " - "%s, rc=%d\n", __func__, (char *)value, -rc); + printk(KERN_ERR "SELinux: unable to map context to SID" + "for (%s, %lu), rc=%d\n", + inode->i_sb->s_id, inode->i_ino, -rc); return; } @@ -5153,6 +5159,12 @@ static int selinux_setprocattr(struct task_struct *p, size--; } error = security_context_to_sid(value, size, &sid); + if (error == -EINVAL && !strcmp(name, "fscreate")) { + if (!capable(CAP_MAC_ADMIN)) + return error; + error = security_context_to_sid_force(value, size, + &sid); + } if (error) return error; } -- cgit v1.2.3-70-g09d2 From f5269710789f666a65cf1132c4f1d14fbc8d3c29 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 14 May 2008 11:27:45 -0400 Subject: SELinux: keep the code clean formating and syntax Formatting and syntax changes whitespace, tabs to spaces, trailing space put open { on same line as struct def remove unneeded {} after if statements change printk("Lu") to printk("llu") convert asm/uaccess.h to linux/uaacess.h includes remove unnecessary asm/bug.h includes convert all users of simple_strtol to strict_strtol Signed-off-by: Eric Paris Signed-off-by: James Morris --- security/selinux/hooks.c | 18 +++++++++++------- security/selinux/include/audit.h | 4 ++-- security/selinux/include/avc.h | 15 +++++++-------- security/selinux/netnode.c | 1 - security/selinux/netport.c | 3 +-- security/selinux/selinuxfs.c | 10 +++++++--- security/selinux/ss/avtab.c | 2 +- security/selinux/ss/mls.c | 8 ++++---- security/selinux/ss/services.c | 4 ++-- 9 files changed, 35 insertions(+), 30 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 59c6e98f7be..eca70f42e67 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -53,7 +53,7 @@ #include /* struct or_callable used in sock_rcv_skb */ #include #include -#include +#include #include #include #include @@ -104,7 +104,9 @@ int selinux_enforcing; static int __init enforcing_setup(char *str) { - selinux_enforcing = simple_strtol(str, NULL, 0); + unsigned long enforcing; + if (!strict_strtoul(str, 0, &enforcing)) + selinux_enforcing = enforcing ? 1 : 0; return 1; } __setup("enforcing=", enforcing_setup); @@ -115,7 +117,9 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; static int __init selinux_enabled_setup(char *str) { - selinux_enabled = simple_strtol(str, NULL, 0); + unsigned long enabled; + if (!strict_strtoul(str, 0, &enabled)) + selinux_enabled = enabled ? 1 : 0; return 1; } __setup("selinux=", selinux_enabled_setup); @@ -594,7 +598,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, */ if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) && (num_opts == 0)) - goto out; + goto out; /* * parse the mount options, check if they are valid sids. @@ -2695,7 +2699,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, } static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, + const void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; @@ -5390,7 +5394,7 @@ static struct security_operations selinux_ops = { .inode_listsecurity = selinux_inode_listsecurity, .inode_need_killpriv = selinux_inode_need_killpriv, .inode_killpriv = selinux_inode_killpriv, - .inode_getsecid = selinux_inode_getsecid, + .inode_getsecid = selinux_inode_getsecid, .file_permission = selinux_file_permission, .file_alloc_security = selinux_file_alloc_security, @@ -5431,7 +5435,7 @@ static struct security_operations selinux_ops = { .task_to_inode = selinux_task_to_inode, .ipc_permission = selinux_ipc_permission, - .ipc_getsecid = selinux_ipc_getsecid, + .ipc_getsecid = selinux_ipc_getsecid, .msg_msg_alloc_security = selinux_msg_msg_alloc_security, .msg_msg_free_security = selinux_msg_msg_free_security, diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 6c8b9ef1557..1bdf973433c 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h @@ -1,7 +1,7 @@ /* * SELinux support for the Audit LSM hooks * - * Most of below header was moved from include/linux/selinux.h which + * Most of below header was moved from include/linux/selinux.h which * is released under below copyrights: * * Author: James Morris @@ -52,7 +52,7 @@ void selinux_audit_rule_free(void *rule); * -errno on failure. */ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, - struct audit_context *actx); + struct audit_context *actx); /** * selinux_audit_rule_known - check to see if rule contains selinux fields. diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 8e23d7a873a..7b9769f5e77 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -75,13 +75,12 @@ struct avc_audit_data { /* Initialize an AVC audit data structure. */ #define AVC_AUDIT_DATA_INIT(_d,_t) \ - { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } + { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } /* * AVC statistics */ -struct avc_cache_stats -{ +struct avc_cache_stats { unsigned int lookups; unsigned int hits; unsigned int misses; @@ -97,8 +96,8 @@ struct avc_cache_stats void __init avc_init(void); void avc_audit(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct av_decision *avd, int result, struct avc_audit_data *auditdata); + u16 tclass, u32 requested, + struct av_decision *avd, int result, struct avc_audit_data *auditdata); #define AVC_STRICT 1 /* Ignore permissive mode. */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, @@ -107,8 +106,8 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, struct av_decision *avd); int avc_has_perm(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct avc_audit_data *auditdata); + u16 tclass, u32 requested, + struct avc_audit_data *auditdata); u32 avc_policy_seqno(void); @@ -122,7 +121,7 @@ u32 avc_policy_seqno(void); #define AVC_CALLBACK_AUDITDENY_DISABLE 128 int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, - u16 tclass, u32 perms, + u16 tclass, u32 perms, u32 *out_retained), u32 events, u32 ssid, u32 tsid, u16 tclass, u32 perms); diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index b6ccd09379f..7100072bb1b 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -38,7 +38,6 @@ #include #include #include -#include #include "netnode.h" #include "objsec.h" diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 90b4cff7c35..fe7fba67f19 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "netport.h" #include "objsec.h" @@ -272,7 +271,7 @@ static __init int sel_netport_init(void) } ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, - SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); + SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); if (ret != 0) panic("avc_add_callback() failed, error %d\n", ret); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ac1ccc13a70..07a5db69571 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include /* selinuxfs pseudo filesystem for exporting the security policy API. Based on the proc code and the fs/nfsd/nfsctl.c code. */ @@ -57,14 +57,18 @@ int selinux_compat_net = SELINUX_COMPAT_NET_VALUE; static int __init checkreqprot_setup(char *str) { - selinux_checkreqprot = simple_strtoul(str, NULL, 0) ? 1 : 0; + unsigned long checkreqprot; + if (!strict_strtoul(str, 0, &checkreqprot)) + selinux_checkreqprot = checkreqprot ? 1 : 0; return 1; } __setup("checkreqprot=", checkreqprot_setup); static int __init selinux_compat_net_setup(char *str) { - selinux_compat_net = simple_strtoul(str, NULL, 0) ? 1 : 0; + unsigned long compat_net; + if (!strict_strtoul(str, 0, &compat_net)) + selinux_compat_net = compat_net ? 1 : 0; return 1; } __setup("selinux_compat_net=", selinux_compat_net_setup); diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 9e6626362bf..a1be97f8bee 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -311,7 +311,7 @@ void avtab_hash_eval(struct avtab *h, char *tag) } printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " - "longest chain length %d sum of chain length^2 %Lu\n", + "longest chain length %d sum of chain length^2 %llu\n", tag, h->nel, slots_used, h->nslot, max_chain_len, chain2_len_sum); } diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index a6ca0587e63..77d745da48b 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -437,13 +437,13 @@ int mls_setup_user_range(struct context *fromcon, struct user_datum *user, struct mls_level *usercon_clr = &(usercon->range.level[1]); /* Honor the user's default level if we can */ - if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { + if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) *usercon_sen = *user_def; - } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { + else if (mls_level_between(fromcon_sen, user_def, user_clr)) *usercon_sen = *fromcon_sen; - } else if (mls_level_between(fromcon_clr, user_low, user_def)) { + else if (mls_level_between(fromcon_clr, user_low, user_def)) *usercon_sen = *user_low; - } else + else return -EINVAL; /* Lower the clearance of available contexts diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2d5e5a3a8aa..0696aadcab6 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2531,7 +2531,7 @@ int selinux_audit_rule_known(struct audit_krule *rule) } int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, - struct audit_context *actx) + struct audit_context *actx) { struct context *ctxt; struct mls_level *level; @@ -2645,7 +2645,7 @@ out: static int (*aurule_callback)(void) = audit_update_lsm_rules; static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, - u16 class, u32 perms, u32 *retained) + u16 class, u32 perms, u32 *retained) { int err = 0; -- cgit v1.2.3-70-g09d2 From 006ebb40d3d65338bd74abb03b945f8d60e362bd Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 19 May 2008 08:32:49 -0400 Subject: Security: split proc ptrace checking into read vs. attach Enable security modules to distinguish reading of process state via proc from full ptrace access by renaming ptrace_may_attach to ptrace_may_access and adding a mode argument indicating whether only read access or full attach access is requested. This allows security modules to permit access to reading process state without granting full ptrace access. The base DAC/capability checking remains unchanged. Read access to /proc/pid/mem continues to apply a full ptrace attach check since check_mem_permission() already requires the current task to already be ptracing the target. The other ptrace checks within proc for elements like environ, maps, and fds are changed to pass the read mode instead of attach. In the SELinux case, we model such reading of process state as a reading of a proc file labeled with the target process' label. This enables SELinux policy to permit such reading of process state without permitting control or manipulation of the target process, as there are a number of cases where programs probe for such information via proc but do not need to be able to control the target (e.g. procps, lsof, PolicyKit, ConsoleKit). At present we have to choose between allowing full ptrace in policy (more permissive than required/desired) or breaking functionality (or in some cases just silencing the denials via dontaudit rules but this can hide genuine attacks). This version of the patch incorporates comments from Casey Schaufler (change/replace existing ptrace_may_attach interface, pass access mode), and Chris Wright (provide greater consistency in the checking). Note that like their predecessors __ptrace_may_attach and ptrace_may_attach, the __ptrace_may_access and ptrace_may_access interfaces use different return value conventions from each other (0 or -errno vs. 1 or 0). I retained this difference to avoid any changes to the caller logic but made the difference clearer by changing the latter interface to return a bool rather than an int and by adding a comment about it to ptrace.h for any future callers. Signed-off-by: Stephen Smalley Acked-by: Chris Wright Signed-off-by: James Morris --- fs/proc/base.c | 9 +++++---- fs/proc/task_mmu.c | 6 +++--- fs/proc/task_nommu.c | 2 +- include/linux/ptrace.h | 8 ++++++-- include/linux/security.h | 16 +++++++++++----- kernel/ptrace.c | 15 ++++++++------- security/commoncap.c | 3 ++- security/dummy.c | 3 ++- security/security.c | 5 +++-- security/selinux/hooks.c | 13 +++++++++++-- security/smack/smack_lsm.c | 5 +++-- 11 files changed, 55 insertions(+), 30 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/fs/proc/base.c b/fs/proc/base.c index 3b455371e7f..58c3e6a8e15 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -233,7 +233,7 @@ static int check_mem_permission(struct task_struct *task) */ if (task->parent == current && (task->ptrace & PT_PTRACED) && task_is_stopped_or_traced(task) && - ptrace_may_attach(task)) + ptrace_may_access(task, PTRACE_MODE_ATTACH)) return 0; /* @@ -251,7 +251,8 @@ struct mm_struct *mm_for_maps(struct task_struct *task) task_lock(task); if (task->mm != mm) goto out; - if (task->mm != current->mm && __ptrace_may_attach(task) < 0) + if (task->mm != current->mm && + __ptrace_may_access(task, PTRACE_MODE_READ) < 0) goto out; task_unlock(task); return mm; @@ -518,7 +519,7 @@ static int proc_fd_access_allowed(struct inode *inode) */ task = get_proc_task(inode); if (task) { - allowed = ptrace_may_attach(task); + allowed = ptrace_may_access(task, PTRACE_MODE_READ); put_task_struct(task); } return allowed; @@ -904,7 +905,7 @@ static ssize_t environ_read(struct file *file, char __user *buf, if (!task) goto out_no_task; - if (!ptrace_may_attach(task)) + if (!ptrace_may_access(task, PTRACE_MODE_READ)) goto out; ret = -ENOMEM; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index c492449f3b4..164bd9f9ede 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -210,7 +210,7 @@ static int show_map(struct seq_file *m, void *v) dev_t dev = 0; int len; - if (maps_protect && !ptrace_may_attach(task)) + if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) return -EACCES; if (file) { @@ -646,7 +646,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, goto out; ret = -EACCES; - if (!ptrace_may_attach(task)) + if (!ptrace_may_access(task, PTRACE_MODE_READ)) goto out_task; ret = -EINVAL; @@ -747,7 +747,7 @@ static int show_numa_map_checked(struct seq_file *m, void *v) struct proc_maps_private *priv = m->private; struct task_struct *task = priv->task; - if (maps_protect && !ptrace_may_attach(task)) + if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) return -EACCES; return show_numa_map(m, v); diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 4b4f9cc2f18..5d84e7121df 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -113,7 +113,7 @@ static int show_map(struct seq_file *m, void *_vml) struct proc_maps_private *priv = m->private; struct task_struct *task = priv->task; - if (maps_protect && !ptrace_may_attach(task)) + if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) return -EACCES; return nommu_vma_show(m, vml->vma); diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index f98501ba557..c6f5f9dd0ce 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -95,8 +95,12 @@ extern void __ptrace_link(struct task_struct *child, struct task_struct *new_parent); extern void __ptrace_unlink(struct task_struct *child); extern void ptrace_untrace(struct task_struct *child); -extern int ptrace_may_attach(struct task_struct *task); -extern int __ptrace_may_attach(struct task_struct *task); +#define PTRACE_MODE_READ 1 +#define PTRACE_MODE_ATTACH 2 +/* Returns 0 on success, -errno on denial. */ +extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); +/* Returns true on success, false on denial. */ +extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); static inline int ptrace_reparented(struct task_struct *child) { diff --git a/include/linux/security.h b/include/linux/security.h index 50737c70e78..62bd80cb7f8 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -46,7 +46,8 @@ struct audit_krule; */ extern int cap_capable(struct task_struct *tsk, int cap); extern int cap_settime(struct timespec *ts, struct timezone *tz); -extern int cap_ptrace(struct task_struct *parent, struct task_struct *child); +extern int cap_ptrace(struct task_struct *parent, struct task_struct *child, + unsigned int mode); extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); @@ -1170,6 +1171,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * attributes would be changed by the execve. * @parent contains the task_struct structure for parent process. * @child contains the task_struct structure for child process. + * @mode contains the PTRACE_MODE flags indicating the form of access. * Return 0 if permission is granted. * @capget: * Get the @effective, @inheritable, and @permitted capability sets for @@ -1295,7 +1297,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) struct security_operations { char name[SECURITY_NAME_MAX + 1]; - int (*ptrace) (struct task_struct *parent, struct task_struct *child); + int (*ptrace) (struct task_struct *parent, struct task_struct *child, + unsigned int mode); int (*capget) (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); @@ -1573,7 +1576,8 @@ extern struct dentry *securityfs_create_dir(const char *name, struct dentry *par extern void securityfs_remove(struct dentry *dentry); /* Security operations */ -int security_ptrace(struct task_struct *parent, struct task_struct *child); +int security_ptrace(struct task_struct *parent, struct task_struct *child, + unsigned int mode); int security_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, @@ -1755,9 +1759,11 @@ static inline int security_init(void) return 0; } -static inline int security_ptrace(struct task_struct *parent, struct task_struct *child) +static inline int security_ptrace(struct task_struct *parent, + struct task_struct *child, + unsigned int mode) { - return cap_ptrace(parent, child); + return cap_ptrace(parent, child, mode); } static inline int security_capget(struct task_struct *target, diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 6c19e94fd0a..e337390fce0 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -121,7 +121,7 @@ int ptrace_check_attach(struct task_struct *child, int kill) return ret; } -int __ptrace_may_attach(struct task_struct *task) +int __ptrace_may_access(struct task_struct *task, unsigned int mode) { /* May we inspect the given task? * This check is used both for attaching with ptrace @@ -148,16 +148,16 @@ int __ptrace_may_attach(struct task_struct *task) if (!dumpable && !capable(CAP_SYS_PTRACE)) return -EPERM; - return security_ptrace(current, task); + return security_ptrace(current, task, mode); } -int ptrace_may_attach(struct task_struct *task) +bool ptrace_may_access(struct task_struct *task, unsigned int mode) { int err; task_lock(task); - err = __ptrace_may_attach(task); + err = __ptrace_may_access(task, mode); task_unlock(task); - return !err; + return (!err ? true : false); } int ptrace_attach(struct task_struct *task) @@ -195,7 +195,7 @@ repeat: /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) goto bad; - retval = __ptrace_may_attach(task); + retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); if (retval) goto bad; @@ -494,7 +494,8 @@ int ptrace_traceme(void) */ task_lock(current); if (!(current->ptrace & PT_PTRACED)) { - ret = security_ptrace(current->parent, current); + ret = security_ptrace(current->parent, current, + PTRACE_MODE_ATTACH); /* * Set the ptrace bit in the process ptrace flags. */ diff --git a/security/commoncap.c b/security/commoncap.c index 33d34330841..0b6537a3672 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -63,7 +63,8 @@ int cap_settime(struct timespec *ts, struct timezone *tz) return 0; } -int cap_ptrace (struct task_struct *parent, struct task_struct *child) +int cap_ptrace (struct task_struct *parent, struct task_struct *child, + unsigned int mode) { /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ if (!cap_issubset(child->cap_permitted, parent->cap_permitted) && diff --git a/security/dummy.c b/security/dummy.c index b8916883b77..1db712d99dc 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -30,7 +30,8 @@ #include #include -static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) +static int dummy_ptrace (struct task_struct *parent, struct task_struct *child, + unsigned int mode) { return 0; } diff --git a/security/security.c b/security/security.c index 59838a99b80..c4507ce2a5a 100644 --- a/security/security.c +++ b/security/security.c @@ -161,9 +161,10 @@ int mod_reg_security(const char *name, struct security_operations *ops) /* Security operations */ -int security_ptrace(struct task_struct *parent, struct task_struct *child) +int security_ptrace(struct task_struct *parent, struct task_struct *child, + unsigned int mode) { - return security_ops->ptrace(parent, child); + return security_ops->ptrace(parent, child, mode); } int security_capget(struct task_struct *target, diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index eca70f42e67..4be156334b2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1686,14 +1686,23 @@ static inline u32 file_to_av(struct file *file) /* Hook functions begin here. */ -static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) +static int selinux_ptrace(struct task_struct *parent, + struct task_struct *child, + unsigned int mode) { int rc; - rc = secondary_ops->ptrace(parent, child); + rc = secondary_ops->ptrace(parent, child, mode); if (rc) return rc; + if (mode == PTRACE_MODE_READ) { + struct task_security_struct *tsec = parent->security; + struct task_security_struct *csec = child->security; + return avc_has_perm(tsec->sid, csec->sid, + SECCLASS_FILE, FILE__READ, NULL); + } + return task_has_perm(parent, child, PROCESS__PTRACE); } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 4a09293efa0..3c7150b3493 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -95,11 +95,12 @@ struct inode_smack *new_inode_smack(char *smack) * * Do the capability checks, and require read and write. */ -static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp) +static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp, + unsigned int mode) { int rc; - rc = cap_ptrace(ptp, ctp); + rc = cap_ptrace(ptp, ctp, mode); if (rc != 0) return rc; -- cgit v1.2.3-70-g09d2 From abc69bb633931bf54c6db798bcdc6fd1e0284742 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 21 May 2008 14:16:12 -0400 Subject: SELinux: enable processes with mac_admin to get the raw inode contexts Enable processes with CAP_MAC_ADMIN + mac_admin permission in policy to get undefined contexts on inodes. This extends the support for deferred mapping of security contexts in order to permit restorecon and similar programs to see the raw file contexts unknown to the system policy in order to check them. Signed-off-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4be156334b2..91b666aec45 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2754,9 +2754,7 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name) } /* - * Copy the in-core inode security context value to the user. If the - * getxattr() prior to this succeeded, check to see if we need to - * canonicalize the value to be finally returned to the user. + * Copy the inode security context value to the user. * * Permission check is handled by selinux_inode_getxattr hook. */ @@ -2765,12 +2763,33 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name u32 size; int error; char *context = NULL; + struct task_security_struct *tsec = current->security; struct inode_security_struct *isec = inode->i_security; if (strcmp(name, XATTR_SELINUX_SUFFIX)) return -EOPNOTSUPP; - error = security_sid_to_context(isec->sid, &context, &size); + /* + * If the caller has CAP_MAC_ADMIN, then get the raw context + * value even if it is not defined by current policy; otherwise, + * use the in-core value under current policy. + * Use the non-auditing forms of the permission checks since + * getxattr may be called by unprivileged processes commonly + * and lack of permission just means that we fall back to the + * in-core context value, not a denial. + */ + error = secondary_ops->capable(current, CAP_MAC_ADMIN); + if (!error) + error = avc_has_perm_noaudit(tsec->sid, tsec->sid, + SECCLASS_CAPABILITY2, + CAPABILITY2__MAC_ADMIN, + 0, + NULL); + if (!error) + error = security_sid_to_context_force(isec->sid, &context, + &size); + else + error = security_sid_to_context(isec->sid, &context, &size); if (error) return error; error = size; -- cgit v1.2.3-70-g09d2 From 242631c49d4cf39642741d6627750151b058233b Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Thu, 5 Jun 2008 09:21:28 -0400 Subject: selinux: simplify ioctl checking Simplify and improve the robustness of the SELinux ioctl checking by using the "access mode" bits of the ioctl command to determine the permission check rather than dealing with individual command values. This removes any knowledge of specific ioctl commands from SELinux and follows the same guidance we gave to Smack earlier. Signed-off-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 48 ++++++++---------------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 91b666aec45..f53000803a5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -42,9 +42,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -2903,46 +2901,16 @@ static void selinux_file_free_security(struct file *file) static int selinux_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int error = 0; - - switch (cmd) { - case FIONREAD: - /* fall through */ - case FIBMAP: - /* fall through */ - case FIGETBSZ: - /* fall through */ - case EXT2_IOC_GETFLAGS: - /* fall through */ - case EXT2_IOC_GETVERSION: - error = file_has_perm(current, file, FILE__GETATTR); - break; - - case EXT2_IOC_SETFLAGS: - /* fall through */ - case EXT2_IOC_SETVERSION: - error = file_has_perm(current, file, FILE__SETATTR); - break; - - /* sys_ioctl() checks */ - case FIONBIO: - /* fall through */ - case FIOASYNC: - error = file_has_perm(current, file, 0); - break; + u32 av = 0; - case KDSKBENT: - case KDSKBSENT: - error = task_has_capability(current, CAP_SYS_TTY_CONFIG); - break; + if (_IOC_DIR(cmd) & _IOC_WRITE) + av |= FILE__WRITE; + if (_IOC_DIR(cmd) & _IOC_READ) + av |= FILE__READ; + if (!av) + av = FILE__IOCTL; - /* default case assumes that the command will go - * to the file's ioctl() function. - */ - default: - error = file_has_perm(current, file, FILE__IOCTL); - } - return error; + return file_has_perm(current, file, av); } static int file_map_prot_check(struct file *file, unsigned long prot, int shared) -- cgit v1.2.3-70-g09d2 From e399f98224a03d2e85fb45eacba367c47173f6f9 Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 12 Jun 2008 01:39:58 +1000 Subject: SELinux: remove unused and shadowed addrlen variable Remove unused and shadowed addrlen variable. Picked up by sparse. Signed-off-by: James Morris Acked-by: Stephen Smalley Acked-by: Paul Moore --- security/selinux/hooks.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f53000803a5..6e8d0e91c0c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3669,7 +3669,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in struct sockaddr_in6 *addr6 = NULL; unsigned short snum; struct sock *sk = sock->sk; - u32 sid, node_perm, addrlen; + u32 sid, node_perm; tsec = current->security; isec = SOCK_INODE(sock)->i_security; @@ -3677,12 +3677,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in if (family == PF_INET) { addr4 = (struct sockaddr_in *)address; snum = ntohs(addr4->sin_port); - addrlen = sizeof(addr4->sin_addr.s_addr); addrp = (char *)&addr4->sin_addr.s_addr; } else { addr6 = (struct sockaddr_in6 *)address; snum = ntohs(addr6->sin6_port); - addrlen = sizeof(addr6->sin6_addr.s6_addr); addrp = (char *)&addr6->sin6_addr.s6_addr; } -- cgit v1.2.3-70-g09d2 From 2baf06df85b27c1d64867883a0692519594f1ef2 Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 12 Jun 2008 01:42:35 +1000 Subject: SELinux: use do_each_thread as a proper do/while block Use do_each_thread as a proper do/while block. Sparse complained. Signed-off-by: James Morris Acked-by: Stephen Smalley --- security/selinux/hooks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6e8d0e91c0c..4130d64359a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5196,12 +5196,12 @@ static int selinux_setprocattr(struct task_struct *p, struct task_struct *g, *t; struct mm_struct *mm = p->mm; read_lock(&tasklist_lock); - do_each_thread(g, t) + do_each_thread(g, t) { if (t->mm == mm && t != p) { read_unlock(&tasklist_lock); return -EPERM; } - while_each_thread(g, t); + } while_each_thread(g, t); read_unlock(&tasklist_lock); } -- cgit v1.2.3-70-g09d2 From 811f3799279e567aa354c649ce22688d949ac7a9 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 18 Jun 2008 09:50:04 -0400 Subject: SELinux: allow fstype unknown to policy to use xattrs if present Currently if a FS is mounted for which SELinux policy does not define an fs_use_* that FS will either be genfs labeled or not labeled at all. This decision is based on the existence of a genfscon rule in policy and is irrespective of the capabilities of the filesystem itself. This patch allows the kernel to check if the filesystem supports security xattrs and if so will use those if there is no fs_use_* rule in policy. An fstype with a no fs_use_* rule but with a genfs rule will use xattrs if available and will follow the genfs rule. This can be particularly interesting for things like ecryptfs which actually overlays a real underlying FS. If we define excryptfs in policy to use xattrs we will likely get this wrong at times, so with this path we just don't need to define it! Overlay ecryptfs on top of NFS with no xattr support: SELinux: initialized (dev ecryptfs, type ecryptfs), uses genfs_contexts Overlay ecryptfs on top of ext4 with xattr support: SELinux: initialized (dev ecryptfs, type ecryptfs), uses xattr It is also useful as the kernel adds new FS we don't need to add them in policy if they support xattrs and that is how we want to handle them. Signed-off-by: Eric Paris Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 22 +++++++++++++++++----- security/selinux/include/security.h | 2 +- security/selinux/ss/services.c | 27 +++++++++++++++++++-------- 3 files changed, 37 insertions(+), 14 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4130d64359a..85f74f66576 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -556,13 +556,15 @@ static int selinux_set_mnt_opts(struct super_block *sb, struct task_security_struct *tsec = current->security; struct superblock_security_struct *sbsec = sb->s_security; const char *name = sb->s_type->name; - struct inode *inode = sbsec->sb->s_root->d_inode; - struct inode_security_struct *root_isec = inode->i_security; + struct dentry *root = sb->s_root; + struct inode *root_inode = root->d_inode; + struct inode_security_struct *root_isec = root_inode->i_security; u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; u32 defcontext_sid = 0; char **mount_options = opts->mnt_opts; int *flags = opts->mnt_opts_flags; int num_opts = opts->num_mnt_opts; + bool can_xattr = false; mutex_lock(&sbsec->lock); @@ -666,14 +668,24 @@ static int selinux_set_mnt_opts(struct super_block *sb, goto out; } - if (strcmp(sb->s_type->name, "proc") == 0) + if (strcmp(name, "proc") == 0) sbsec->proc = 1; + /* + * test if the fs supports xattrs, fs_use might make use of this if the + * fs has no definition in policy. + */ + if (root_inode->i_op->getxattr) { + rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); + if (rc >= 0 || rc == -ENODATA) + can_xattr = true; + } + /* Determine the labeling behavior to use for this filesystem type. */ - rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); + rc = security_fs_use(name, &sbsec->behavior, &sbsec->sid, can_xattr); if (rc) { printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", - __func__, sb->s_type->name, rc); + __func__, name, rc); goto out; } diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 7c543003d65..44cba2e21dc 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -136,7 +136,7 @@ int security_get_allow_unknown(void); #define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */ int security_fs_use(const char *fstype, unsigned int *behavior, - u32 *sid); + u32 *sid, bool can_xattr); int security_genfs_sid(const char *fstype, char *name, u16 sclass, u32 *sid); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b52f923ce68..8e42da12010 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1934,7 +1934,8 @@ out: int security_fs_use( const char *fstype, unsigned int *behavior, - u32 *sid) + u32 *sid, + bool can_xattr) { int rc = 0; struct ocontext *c; @@ -1948,6 +1949,7 @@ int security_fs_use( c = c->next; } + /* look for labeling behavior defined in policy */ if (c) { *behavior = c->v.behavior; if (!c->sid[0]) { @@ -1958,14 +1960,23 @@ int security_fs_use( goto out; } *sid = c->sid[0]; + goto out; + } + + /* labeling behavior not in policy, use xattrs if possible */ + if (can_xattr) { + *behavior = SECURITY_FS_USE_XATTR; + *sid = SECINITSID_FS; + goto out; + } + + /* no behavior in policy and can't use xattrs, try GENFS */ + rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); + if (rc) { + *behavior = SECURITY_FS_USE_NONE; + rc = 0; } else { - rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); - if (rc) { - *behavior = SECURITY_FS_USE_NONE; - rc = 0; - } else { - *behavior = SECURITY_FS_USE_GENFS; - } + *behavior = SECURITY_FS_USE_GENFS; } out: -- cgit v1.2.3-70-g09d2 From 2069f457848f846cb31149c9aa29b330a6b66d1b Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 4 Jul 2008 09:47:13 +1000 Subject: LSM/SELinux: show LSM mount options in /proc/mounts This patch causes SELinux mount options to show up in /proc/mounts. As with other code in the area seq_put errors are ignored. Other LSM's will not have their mount options displayed until they fill in their own security_sb_show_options() function. Signed-off-by: Eric Paris Signed-off-by: Miklos Szeredi Signed-off-by: James Morris --- fs/namespace.c | 14 +++++++++--- include/linux/security.h | 9 ++++++++ security/dummy.c | 6 ++++++ security/security.c | 5 +++++ security/selinux/hooks.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 85 insertions(+), 4 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/fs/namespace.c b/fs/namespace.c index 4fc302c2a0e..4f6f7635b59 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -750,7 +750,7 @@ struct proc_fs_info { const char *str; }; -static void show_sb_opts(struct seq_file *m, struct super_block *sb) +static int show_sb_opts(struct seq_file *m, struct super_block *sb) { static const struct proc_fs_info fs_info[] = { { MS_SYNCHRONOUS, ",sync" }, @@ -764,6 +764,8 @@ static void show_sb_opts(struct seq_file *m, struct super_block *sb) if (sb->s_flags & fs_infop->flag) seq_puts(m, fs_infop->str); } + + return security_sb_show_options(m, sb); } static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) @@ -806,11 +808,14 @@ static int show_vfsmnt(struct seq_file *m, void *v) seq_putc(m, ' '); show_type(m, mnt->mnt_sb); seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); - show_sb_opts(m, mnt->mnt_sb); + err = show_sb_opts(m, mnt->mnt_sb); + if (err) + goto out; show_mnt_opts(m, mnt); if (mnt->mnt_sb->s_op->show_options) err = mnt->mnt_sb->s_op->show_options(m, mnt); seq_puts(m, " 0 0\n"); +out: return err; } @@ -865,10 +870,13 @@ static int show_mountinfo(struct seq_file *m, void *v) seq_putc(m, ' '); mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); - show_sb_opts(m, sb); + err = show_sb_opts(m, sb); + if (err) + goto out; if (sb->s_op->show_options) err = sb->s_op->show_options(m, mnt); seq_putc(m, '\n'); +out: return err; } diff --git a/include/linux/security.h b/include/linux/security.h index 62bd80cb7f8..c8ad8ec684b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -80,6 +80,7 @@ struct xfrm_selector; struct xfrm_policy; struct xfrm_state; struct xfrm_user_sec_ctx; +struct seq_file; extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); extern int cap_netlink_recv(struct sk_buff *skb, int cap); @@ -1331,6 +1332,7 @@ struct security_operations { void (*sb_free_security) (struct super_block *sb); int (*sb_copy_data) (char *orig, char *copy); int (*sb_kern_mount) (struct super_block *sb, void *data); + int (*sb_show_options) (struct seq_file *m, struct super_block *sb); int (*sb_statfs) (struct dentry *dentry); int (*sb_mount) (char *dev_name, struct path *path, char *type, unsigned long flags, void *data); @@ -1610,6 +1612,7 @@ int security_sb_alloc(struct super_block *sb); void security_sb_free(struct super_block *sb); int security_sb_copy_data(char *orig, char *copy); int security_sb_kern_mount(struct super_block *sb, void *data); +int security_sb_show_options(struct seq_file *m, struct super_block *sb); int security_sb_statfs(struct dentry *dentry); int security_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data); @@ -1887,6 +1890,12 @@ static inline int security_sb_kern_mount(struct super_block *sb, void *data) return 0; } +static inline int security_sb_show_options(struct seq_file *m, + struct super_block *sb) +{ + return 0; +} + static inline int security_sb_statfs(struct dentry *dentry) { return 0; diff --git a/security/dummy.c b/security/dummy.c index 1db712d99dc..c155f08e9dd 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -194,6 +194,11 @@ static int dummy_sb_kern_mount (struct super_block *sb, void *data) return 0; } +static int dummy_sb_show_options(struct seq_file *m, struct super_block *sb) +{ + return 0; +} + static int dummy_sb_statfs (struct dentry *dentry) { return 0; @@ -1088,6 +1093,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, sb_free_security); set_to_dummy_if_null(ops, sb_copy_data); set_to_dummy_if_null(ops, sb_kern_mount); + set_to_dummy_if_null(ops, sb_show_options); set_to_dummy_if_null(ops, sb_statfs); set_to_dummy_if_null(ops, sb_mount); set_to_dummy_if_null(ops, sb_check_sb); diff --git a/security/security.c b/security/security.c index 2c0a5876b93..de74fdccde2 100644 --- a/security/security.c +++ b/security/security.c @@ -292,6 +292,11 @@ int security_sb_kern_mount(struct super_block *sb, void *data) return security_ops->sb_kern_mount(sb, data); } +int security_sb_show_options(struct seq_file *m, struct super_block *sb) +{ + return security_ops->sb_show_options(m, sb); +} + int security_sb_statfs(struct dentry *dentry) { return security_ops->sb_statfs(dentry); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 85f74f66576..33dee83fdd2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -9,7 +9,8 @@ * James Morris * * Copyright (C) 2001,2002 Networks Associates Technology, Inc. - * Copyright (C) 2003 Red Hat, Inc., James Morris + * Copyright (C) 2003-2008 Red Hat, Inc., James Morris + * Eric Paris * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. @@ -970,6 +971,57 @@ out_err: return rc; } +void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts) +{ + int i; + char *prefix; + + for (i = 0; i < opts->num_mnt_opts; i++) { + char *has_comma = strchr(opts->mnt_opts[i], ','); + + switch (opts->mnt_opts_flags[i]) { + case CONTEXT_MNT: + prefix = CONTEXT_STR; + break; + case FSCONTEXT_MNT: + prefix = FSCONTEXT_STR; + break; + case ROOTCONTEXT_MNT: + prefix = ROOTCONTEXT_STR; + break; + case DEFCONTEXT_MNT: + prefix = DEFCONTEXT_STR; + break; + default: + BUG(); + }; + /* we need a comma before each option */ + seq_putc(m, ','); + seq_puts(m, prefix); + if (has_comma) + seq_putc(m, '\"'); + seq_puts(m, opts->mnt_opts[i]); + if (has_comma) + seq_putc(m, '\"'); + } +} + +static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) +{ + struct security_mnt_opts opts; + int rc; + + rc = selinux_get_mnt_opts(sb, &opts); + if (rc) + return rc; + + selinux_write_opts(m, &opts); + + security_free_mnt_opts(&opts); + + return rc; +} + static inline u16 inode_mode_to_security_class(umode_t mode) { switch (mode & S_IFMT) { @@ -5365,6 +5417,7 @@ static struct security_operations selinux_ops = { .sb_free_security = selinux_sb_free_security, .sb_copy_data = selinux_sb_copy_data, .sb_kern_mount = selinux_sb_kern_mount, + .sb_show_options = selinux_sb_show_options, .sb_statfs = selinux_sb_statfs, .sb_mount = selinux_mount, .sb_umount = selinux_umount, -- cgit v1.2.3-70-g09d2 From b478a9f9889c81e88077d1495daadee64c0af541 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 3 Jul 2008 20:56:04 +0200 Subject: security: remove unused sb_get_mnt_opts hook The sb_get_mnt_opts() hook is unused, and is superseded by the sb_show_options() hook. Signed-off-by: Miklos Szeredi Acked-by: James Morris --- include/linux/security.h | 14 -------------- security/dummy.c | 8 -------- security/security.c | 6 ------ security/selinux/hooks.c | 1 - 4 files changed, 29 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/include/linux/security.h b/include/linux/security.h index c8ad8ec684b..43c6357568a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -291,10 +291,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Update module state after a successful pivot. * @old_path contains the path for the old root. * @new_path contains the path for the new root. - * @sb_get_mnt_opts: - * Get the security relevant mount options used for a superblock - * @sb the superblock to get security mount options from - * @opts binary data structure containing all lsm mount data * @sb_set_mnt_opts: * Set the security relevant mount options used for a superblock * @sb the superblock to set security mount options for @@ -1348,8 +1344,6 @@ struct security_operations { struct path *new_path); void (*sb_post_pivotroot) (struct path *old_path, struct path *new_path); - int (*sb_get_mnt_opts) (const struct super_block *sb, - struct security_mnt_opts *opts); int (*sb_set_mnt_opts) (struct super_block *sb, struct security_mnt_opts *opts); void (*sb_clone_mnt_opts) (const struct super_block *oldsb, @@ -1624,8 +1618,6 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint); int security_sb_pivotroot(struct path *old_path, struct path *new_path); void security_sb_post_pivotroot(struct path *old_path, struct path *new_path); -int security_sb_get_mnt_opts(const struct super_block *sb, - struct security_mnt_opts *opts); int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts); void security_sb_clone_mnt_opts(const struct super_block *oldsb, struct super_block *newsb); @@ -1942,12 +1934,6 @@ static inline int security_sb_pivotroot(struct path *old_path, static inline void security_sb_post_pivotroot(struct path *old_path, struct path *new_path) { } -static inline int security_sb_get_mnt_opts(const struct super_block *sb, - struct security_mnt_opts *opts) -{ - security_init_mnt_opts(opts); - return 0; -} static inline int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts) diff --git a/security/dummy.c b/security/dummy.c index c155f08e9dd..79385669164 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -252,13 +252,6 @@ static void dummy_sb_post_pivotroot (struct path *old_path, struct path *new_pat return; } -static int dummy_sb_get_mnt_opts(const struct super_block *sb, - struct security_mnt_opts *opts) -{ - security_init_mnt_opts(opts); - return 0; -} - static int dummy_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts) { @@ -1104,7 +1097,6 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, sb_post_addmount); set_to_dummy_if_null(ops, sb_pivotroot); set_to_dummy_if_null(ops, sb_post_pivotroot); - set_to_dummy_if_null(ops, sb_get_mnt_opts); set_to_dummy_if_null(ops, sb_set_mnt_opts); set_to_dummy_if_null(ops, sb_clone_mnt_opts); set_to_dummy_if_null(ops, sb_parse_opts_str); diff --git a/security/security.c b/security/security.c index de74fdccde2..28b2860c112 100644 --- a/security/security.c +++ b/security/security.c @@ -348,12 +348,6 @@ void security_sb_post_pivotroot(struct path *old_path, struct path *new_path) security_ops->sb_post_pivotroot(old_path, new_path); } -int security_sb_get_mnt_opts(const struct super_block *sb, - struct security_mnt_opts *opts) -{ - return security_ops->sb_get_mnt_opts(sb, opts); -} - int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 33dee83fdd2..745a69e74e3 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5421,7 +5421,6 @@ static struct security_operations selinux_ops = { .sb_statfs = selinux_sb_statfs, .sb_mount = selinux_mount, .sb_umount = selinux_umount, - .sb_get_mnt_opts = selinux_get_mnt_opts, .sb_set_mnt_opts = selinux_set_mnt_opts, .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, .sb_parse_opts_str = selinux_parse_opts_str, -- cgit v1.2.3-70-g09d2 From 6f0f0fd496333777d53daff21a4e3b28c4d03a6d Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 10 Jul 2008 17:02:07 +0900 Subject: security: remove register_security hook The register security hook is no longer required, as the capability module is always registered. LSMs wishing to stack capability as a secondary module should do so explicitly. Signed-off-by: James Morris Acked-by: Stephen Smalley Acked-by: Greg Kroah-Hartman --- include/linux/security.h | 10 ---------- security/capability.c | 7 ------- security/root_plug.c | 9 --------- security/security.c | 29 ----------------------------- security/selinux/hooks.c | 32 +++++--------------------------- security/smack/smack_lsm.c | 23 ----------------------- 6 files changed, 5 insertions(+), 105 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/include/linux/security.h b/include/linux/security.h index 43c6357568a..31c8851ec5d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1239,11 +1239,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @pages contains the number of pages. * Return 0 if permission is granted. * - * @register_security: - * allow module stacking. - * @name contains the name of the security module being stacked. - * @ops contains a pointer to the struct security_operations of the module to stack. - * * @secid_to_secctx: * Convert secid to security context. * @secid contains the security ID. @@ -1471,10 +1466,6 @@ struct security_operations { int (*netlink_send) (struct sock *sk, struct sk_buff *skb); int (*netlink_recv) (struct sk_buff *skb, int cap); - /* allow module stacking */ - int (*register_security) (const char *name, - struct security_operations *ops); - void (*d_instantiate) (struct dentry *dentry, struct inode *inode); int (*getprocattr) (struct task_struct *p, char *name, char **value); @@ -1564,7 +1555,6 @@ struct security_operations { extern int security_init(void); extern int security_module_enable(struct security_operations *ops); extern int register_security(struct security_operations *ops); -extern int mod_reg_security(const char *name, struct security_operations *ops); extern struct dentry *securityfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); diff --git a/security/capability.c b/security/capability.c index 6e0671c8201..5b01c0b0242 100644 --- a/security/capability.c +++ b/security/capability.c @@ -721,12 +721,6 @@ static int cap_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall) } #endif /* CONFIG_SECURITY_NETWORK_XFRM */ -static int cap_register_security(const char *name, - struct security_operations *ops) -{ - return -EINVAL; -} - static void cap_d_instantiate(struct dentry *dentry, struct inode *inode) { } @@ -940,7 +934,6 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, sem_semop); set_to_cap_if_null(ops, netlink_send); set_to_cap_if_null(ops, netlink_recv); - set_to_cap_if_null(ops, register_security); set_to_cap_if_null(ops, d_instantiate); set_to_cap_if_null(ops, getprocattr); set_to_cap_if_null(ops, setprocattr); diff --git a/security/root_plug.c b/security/root_plug.c index a41cf42a4fa..be0ebec2580 100644 --- a/security/root_plug.c +++ b/security/root_plug.c @@ -28,9 +28,6 @@ #include #include -/* flag to keep track of how we were registered */ -static int secondary; - /* default is a generic type of usb to serial converter */ static int vendor_id = 0x0557; static int product_id = 0x2008; @@ -97,13 +94,7 @@ static int __init rootplug_init (void) if (register_security (&rootplug_security_ops)) { printk (KERN_INFO "Failure registering Root Plug module with the kernel\n"); - /* try registering with primary module */ - if (mod_reg_security (MY_NAME, &rootplug_security_ops)) { - printk (KERN_INFO "Failure registering Root Plug " - " module with primary security module.\n"); return -EINVAL; - } - secondary = 1; } printk (KERN_INFO "Root Plug module initialized, " "vendor_id = %4.4x, product id = %4.4x\n", vendor_id, product_id); diff --git a/security/security.c b/security/security.c index 30b0278de39..59f23b5918b 100644 --- a/security/security.c +++ b/security/security.c @@ -125,35 +125,6 @@ int register_security(struct security_operations *ops) return 0; } -/** - * mod_reg_security - allows security modules to be "stacked" - * @name: a pointer to a string with the name of the security_options to be registered - * @ops: a pointer to the struct security_options that is to be registered - * - * This function allows security modules to be stacked if the currently loaded - * security module allows this to happen. It passes the @name and @ops to the - * register_security function of the currently loaded security module. - * - * The return value depends on the currently loaded security module, with 0 as - * success. - */ -int mod_reg_security(const char *name, struct security_operations *ops) -{ - if (verify(ops)) { - printk(KERN_INFO "%s could not verify " - "security operations.\n", __func__); - return -EINVAL; - } - - if (ops == security_ops) { - printk(KERN_INFO "%s security operations " - "already registered.\n", __func__); - return -EINVAL; - } - - return security_ops->register_security(name, ops); -} - /* Security operations */ int security_ptrace(struct task_struct *parent, struct task_struct *child, diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 745a69e74e3..91200feb3f9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -126,13 +126,11 @@ __setup("selinux=", selinux_enabled_setup); int selinux_enabled = 1; #endif -/* Original (dummy) security module. */ -static struct security_operations *original_ops; -/* Minimal support for a secondary security module, - just to allow the use of the dummy or capability modules. - The owlsm module can alternatively be used as a secondary - module as long as CONFIG_OWLSM_FD is not enabled. */ +/* + * Minimal support for a secondary security module, + * just to allow the use of the capability module. + */ static struct security_operations *secondary_ops; /* Lists of inode and superblock security structures initialized @@ -5115,24 +5113,6 @@ static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) *secid = isec->sid; } -/* module stacking operations */ -static int selinux_register_security(const char *name, struct security_operations *ops) -{ - if (secondary_ops != original_ops) { - printk(KERN_ERR "%s: There is already a secondary security " - "module registered.\n", __func__); - return -EINVAL; - } - - secondary_ops = ops; - - printk(KERN_INFO "%s: Registering secondary module %s\n", - __func__, - name); - - return 0; -} - static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) { if (inode) @@ -5517,8 +5497,6 @@ static struct security_operations selinux_ops = { .sem_semctl = selinux_sem_semctl, .sem_semop = selinux_sem_semop, - .register_security = selinux_register_security, - .d_instantiate = selinux_d_instantiate, .getprocattr = selinux_getprocattr, @@ -5612,7 +5590,7 @@ static __init int selinux_init(void) 0, SLAB_PANIC, NULL); avc_init(); - original_ops = secondary_ops = security_ops; + secondary_ops = security_ops; if (!secondary_ops) panic("SELinux: No initial security operations\n"); if (register_security(&selinux_ops)) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 3c7150b3493..ee5a51cbc5e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1822,27 +1822,6 @@ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) *secid = smack_to_secid(smack); } -/* module stacking operations */ - -/** - * smack_register_security - stack capability module - * @name: module name - * @ops: module operations - ignored - * - * Allow the capability module to register. - */ -static int smack_register_security(const char *name, - struct security_operations *ops) -{ - if (strcmp(name, "capability") != 0) - return -EINVAL; - - printk(KERN_INFO "%s: Registering secondary module %s\n", - __func__, name); - - return 0; -} - /** * smack_d_instantiate - Make sure the blob is correct on an inode * @opt_dentry: unused @@ -2673,8 +2652,6 @@ struct security_operations smack_ops = { .netlink_send = cap_netlink_send, .netlink_recv = cap_netlink_recv, - .register_security = smack_register_security, - .d_instantiate = smack_d_instantiate, .getprocattr = smack_getprocattr, -- cgit v1.2.3-70-g09d2 From 089be43e403a78cd6889cde2fba164fefe9dfd89 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 15 Jul 2008 18:32:49 +1000 Subject: Revert "SELinux: allow fstype unknown to policy to use xattrs if present" This reverts commit 811f3799279e567aa354c649ce22688d949ac7a9. From Eric Paris: "Please drop this patch for now. It deadlocks on ntfs-3g. I need to rework it to handle fuse filesystems better. (casey was right)" --- security/selinux/hooks.c | 22 +++++----------------- security/selinux/include/security.h | 2 +- security/selinux/ss/services.c | 27 ++++++++------------------- 3 files changed, 14 insertions(+), 37 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 91200feb3f9..63f131fc42e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -555,15 +555,13 @@ static int selinux_set_mnt_opts(struct super_block *sb, struct task_security_struct *tsec = current->security; struct superblock_security_struct *sbsec = sb->s_security; const char *name = sb->s_type->name; - struct dentry *root = sb->s_root; - struct inode *root_inode = root->d_inode; - struct inode_security_struct *root_isec = root_inode->i_security; + struct inode *inode = sbsec->sb->s_root->d_inode; + struct inode_security_struct *root_isec = inode->i_security; u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; u32 defcontext_sid = 0; char **mount_options = opts->mnt_opts; int *flags = opts->mnt_opts_flags; int num_opts = opts->num_mnt_opts; - bool can_xattr = false; mutex_lock(&sbsec->lock); @@ -667,24 +665,14 @@ static int selinux_set_mnt_opts(struct super_block *sb, goto out; } - if (strcmp(name, "proc") == 0) + if (strcmp(sb->s_type->name, "proc") == 0) sbsec->proc = 1; - /* - * test if the fs supports xattrs, fs_use might make use of this if the - * fs has no definition in policy. - */ - if (root_inode->i_op->getxattr) { - rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); - if (rc >= 0 || rc == -ENODATA) - can_xattr = true; - } - /* Determine the labeling behavior to use for this filesystem type. */ - rc = security_fs_use(name, &sbsec->behavior, &sbsec->sid, can_xattr); + rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); if (rc) { printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", - __func__, name, rc); + __func__, sb->s_type->name, rc); goto out; } diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 44cba2e21dc..7c543003d65 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -136,7 +136,7 @@ int security_get_allow_unknown(void); #define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */ int security_fs_use(const char *fstype, unsigned int *behavior, - u32 *sid, bool can_xattr); + u32 *sid); int security_genfs_sid(const char *fstype, char *name, u16 sclass, u32 *sid); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 8e42da12010..b52f923ce68 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1934,8 +1934,7 @@ out: int security_fs_use( const char *fstype, unsigned int *behavior, - u32 *sid, - bool can_xattr) + u32 *sid) { int rc = 0; struct ocontext *c; @@ -1949,7 +1948,6 @@ int security_fs_use( c = c->next; } - /* look for labeling behavior defined in policy */ if (c) { *behavior = c->v.behavior; if (!c->sid[0]) { @@ -1960,23 +1958,14 @@ int security_fs_use( goto out; } *sid = c->sid[0]; - goto out; - } - - /* labeling behavior not in policy, use xattrs if possible */ - if (can_xattr) { - *behavior = SECURITY_FS_USE_XATTR; - *sid = SECINITSID_FS; - goto out; - } - - /* no behavior in policy and can't use xattrs, try GENFS */ - rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); - if (rc) { - *behavior = SECURITY_FS_USE_NONE; - rc = 0; } else { - *behavior = SECURITY_FS_USE_GENFS; + rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); + if (rc) { + *behavior = SECURITY_FS_USE_NONE; + rc = 0; + } else { + *behavior = SECURITY_FS_USE_GENFS; + } } out: -- cgit v1.2.3-70-g09d2