From e97dcb0eadbb821eccd549d4987b653cf61e2374 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Mon, 2 Jun 2008 10:04:32 -0700 Subject: Smack: fuse mount hang fix The d_instantiate hook for Smack can hang on the root inode of a filesystem if the file system code has not really done all the set-up. Fuse is known to encounter this problem. This change detects an attempt to instantiate a root inode and addresses it early in the processing, before any attempt is made to do something that might hang. Signed-off-by: Casey Schaufler Tested-by: Luiz Fernando N. Capitulino Signed-off-by: Linus Torvalds --- security/smack/smack_lsm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'security') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index b5c8f923700..4a09293efa0 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1880,6 +1880,18 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ final = sbsp->smk_default; + /* + * If this is the root inode the superblock + * may be in the process of initialization. + * If that is the case use the root value out + * of the superblock. + */ + if (opt_dentry->d_parent == opt_dentry) { + isp->smk_inode = sbsp->smk_root; + isp->smk_flags |= SMK_INODE_INSTANT; + goto unlockandout; + } + /* * This is pretty hackish. * Casey says that we shouldn't have to do -- cgit v1.2.3 From b66862f7663332aa1ecb3ebda4086360ddb8befc Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 5 Jun 2008 22:46:24 -0700 Subject: devcgroup: make a helper to convert cgroup_subsys_state to devs_cgroup This is just picking the container_of out of cgroup_to_devcgroup into a separate function. This new css_to_devcgroup will be used in the 2nd patch. Signed-off-by: Pavel Emelyanov Acked-by: Serge Hallyn Cc: Paul Menage Cc: Balbir Singh Cc: James Morris Cc: Chris Wright Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/device_cgroup.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 4ea583689ee..15f2f8003ba 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -49,10 +49,14 @@ struct dev_cgroup { spinlock_t lock; }; +static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) +{ + return container_of(s, struct dev_cgroup, css); +} + static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup) { - return container_of(cgroup_subsys_state(cgroup, devices_subsys_id), - struct dev_cgroup, css); + return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id)); } struct cgroup_subsys devices_subsys; -- cgit v1.2.3 From cc9cb219aac24ffc711566c8f372c2b3a3bf840f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 5 Jun 2008 22:46:26 -0700 Subject: devscgroup: relax task to dev_cgroup conversion Two functions, that need to get a device_cgroup from a task (they are devcgroup_inode_permission and devcgroup_inode_mknod) make it in a strange way: They get a css_set from task, then a subsys_state from css_set, then a cgroup from the state and then a subsys_state again from the cgroup. Besides, the devices_subsys_id is read from memory, whilst there's a enum-ed constant for it. Optimize this part a bit: 1. Get the subsys_stats form the task and be done - no 2 extra dereferences, 2. Use the device_subsys_id constant, not the value from memory (i.e. one less dereference). Found while preparing 2.6.26 OpenVZ port. Signed-off-by: Pavel Emelyanov Acked-by: Serge Hallyn Acked-by: Paul Menage Cc: Balbir Singh Cc: James Morris Cc: Chris Wright Cc: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/device_cgroup.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'security') diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 15f2f8003ba..f9941a76973 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -506,7 +506,6 @@ struct cgroup_subsys devices_subsys = { int devcgroup_inode_permission(struct inode *inode, int mask) { - struct cgroup *cgroup; struct dev_cgroup *dev_cgroup; struct dev_whitelist_item *wh; @@ -515,8 +514,8 @@ int devcgroup_inode_permission(struct inode *inode, int mask) return 0; if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)) return 0; - cgroup = task_cgroup(current, devices_subsys.subsys_id); - dev_cgroup = cgroup_to_devcgroup(cgroup); + dev_cgroup = css_to_devcgroup(task_subsys_state(current, + devices_subsys_id)); if (!dev_cgroup) return 0; @@ -547,12 +546,11 @@ acc_check: int devcgroup_inode_mknod(int mode, dev_t dev) { - struct cgroup *cgroup; struct dev_cgroup *dev_cgroup; struct dev_whitelist_item *wh; - cgroup = task_cgroup(current, devices_subsys.subsys_id); - dev_cgroup = cgroup_to_devcgroup(cgroup); + dev_cgroup = css_to_devcgroup(task_subsys_state(current, + devices_subsys_id)); if (!dev_cgroup) return 0; -- cgit v1.2.3 From d1ee2971f5bd8a16bc5ecfe1b00e14b4fe407c4f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 5 Jun 2008 22:46:28 -0700 Subject: devscgroup: make white list more compact in some cases Consider you added a 'c foo:bar r' permission to some cgroup and then (a bit later) 'c'foo:bar w' for it. After this you'll see the c foo:bar r c foo:bar w lines in a devices.list file. Another example - consider you added 10 'c foo:bar r' permissions to some cgroup (e.g. by mistake). After this you'll see 10 c foo:bar r lines in a list file. This is weird. This situation also has one more annoying consequence. Having many items in a white list makes permissions checking slower, sine it has to walk a longer list. The proposal is to merge permissions for items, that correspond to the same device. Signed-off-by: Pavel Emelyanov Acked-by: Serge Hallyn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/device_cgroup.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/device_cgroup.c b/security/device_cgroup.c index f9941a76973..baf348834b6 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -106,7 +106,7 @@ free_and_exit: static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, struct dev_whitelist_item *wh) { - struct dev_whitelist_item *whcopy; + struct dev_whitelist_item *whcopy, *walk; whcopy = kmalloc(sizeof(*whcopy), GFP_KERNEL); if (!whcopy) @@ -114,7 +114,21 @@ static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, memcpy(whcopy, wh, sizeof(*whcopy)); spin_lock(&dev_cgroup->lock); - list_add_tail(&whcopy->list, &dev_cgroup->whitelist); + list_for_each_entry(walk, &dev_cgroup->whitelist, list) { + if (walk->type != wh->type) + continue; + if (walk->major != wh->major) + continue; + if (walk->minor != wh->minor) + continue; + + walk->access |= wh->access; + kfree(whcopy); + whcopy = NULL; + } + + if (whcopy != NULL) + list_add_tail(&whcopy->list, &dev_cgroup->whitelist); spin_unlock(&dev_cgroup->lock); return 0; } -- cgit v1.2.3 From dba6a4d32d8677c99e73798d3375417f8a6d46de Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 5 Jun 2008 22:46:32 -0700 Subject: keys: remove unused key_alloc_sem This semaphore doesn't appear to be used, so remove it. Signed-off-by: Daniel Walker Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/keys/internal.h | 1 - 1 file changed, 1 deletion(-) (limited to 'security') diff --git a/security/keys/internal.h b/security/keys/internal.h index 8c05587f501..b39f5c2e2c4 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -78,7 +78,6 @@ extern unsigned key_quota_maxbytes; extern struct rb_root key_serial_tree; extern spinlock_t key_serial_lock; -extern struct semaphore key_alloc_sem; extern struct mutex key_construction_mutex; extern wait_queue_head_t request_key_conswq; -- cgit v1.2.3 From 8cdbc2b9826b3543fecff2f6d6400fa77b21ffdd Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Thu, 12 Jun 2008 15:21:33 -0700 Subject: capabilities: add (back) dummy support for KEEPCAPS The dummy module is used by folk that run security conscious code(!?). A feature of such code (for example, dhclient) is that it tries to operate with minimum privilege (dropping unneeded capabilities). While the dummy module doesn't restrict code execution based on capability state, the user code expects the kernel to appear to support it. This patch adds back faked support for the PR_SET_KEEPCAPS etc., calls - making the kernel behave as before 2.6.26. For details see: http://bugzilla.kernel.org/show_bug.cgi?id=10748 Signed-off-by: Andrew G. Morgan Acked-by: Serge Hallyn Cc: James Morris Cc: Stephen Smalley Cc: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/dummy.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'security') diff --git a/security/dummy.c b/security/dummy.c index f50c6c3c32c..b8916883b77 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) { @@ -607,7 +609,27 @@ static int dummy_task_kill (struct task_struct *p, struct siginfo *info, static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, long *rc_p) { - return 0; + switch (option) { + case PR_CAPBSET_READ: + *rc_p = (cap_valid(arg2) ? 1 : -EINVAL); + break; + case PR_GET_KEEPCAPS: + *rc_p = issecure(SECURE_KEEP_CAPS); + break; + case PR_SET_KEEPCAPS: + if (arg2 > 1) + *rc_p = -EINVAL; + else if (arg2) + current->securebits |= issecure_mask(SECURE_KEEP_CAPS); + else + current->securebits &= + ~issecure_mask(SECURE_KEEP_CAPS); + break; + default: + return 0; + } + + return 1; } static void dummy_task_reparent_to_init (struct task_struct *p) -- cgit v1.2.3