From 78b7280cce23293f7570ad52c1ffe1485c6d9669 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 11 Mar 2011 17:57:23 +0000 Subject: KEYS: Improve /proc/keys Improve /proc/keys by: (1) Don't attempt to summarise the payload of a negated key. It won't have one. To this end, a helper function - key_is_instantiated() has been added that allows the caller to find out whether the key is positively instantiated (as opposed to being uninstantiated or negatively instantiated). (2) Do show keys that are negative, expired or revoked rather than hiding them. This requires an override flag (no_state_check) to be passed to search_my_process_keyrings() and keyring_search_aux() to suppress this check. Without this, keys that are possessed by the caller, but only grant permissions to the caller if possessed are skipped as the possession check fails. Keys that are visible due to user, group or other checks are visible with or without this patch. Signed-off-by: David Howells Signed-off-by: James Morris --- include/linux/key.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include') diff --git a/include/linux/key.h b/include/linux/key.h index b2bb01719561..ef19b99aff98 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -276,6 +276,19 @@ static inline key_serial_t key_serial(struct key *key) return key ? key->serial : 0; } +/** + * key_is_instantiated - Determine if a key has been positively instantiated + * @key: The key to check. + * + * Return true if the specified key has been positively instantiated, false + * otherwise. + */ +static inline bool key_is_instantiated(const struct key *key) +{ + return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && + !test_bit(KEY_FLAG_NEGATIVE, &key->flags); +} + #define rcu_dereference_key(KEY) \ (rcu_dereference_protected((KEY)->payload.rcudata, \ rwsem_is_locked(&((struct key *)(KEY))->sem))) -- cgit v1.2.3 From 17f60a7da150fdd0cfb9756f86a262daa72c835f Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 1 Apr 2011 17:07:50 -0400 Subject: capabilites: allow the application of capability limits to usermode helpers There is no way to limit the capabilities of usermodehelpers. This problem reared its head recently when someone complained that any user with cap_net_admin was able to load arbitrary kernel modules, even though the user didn't have cap_sys_module. The reason is because the actual load is done by a usermode helper and those always have the full cap set. This patch addes new sysctls which allow us to bound the permissions of usermode helpers. /proc/sys/kernel/usermodehelper/bset /proc/sys/kernel/usermodehelper/inheritable You must have CAP_SYS_MODULE and CAP_SETPCAP to change these (changes are &= ONLY). When the kernel launches a usermodehelper it will do so with these as the bset and pI. -v2: make globals static create spinlock to protect globals -v3: require both CAP_SETPCAP and CAP_SYS_MODULE -v4: fix the typo s/CAP_SET_PCAP/CAP_SETPCAP/ because I didn't commit Signed-off-by: Eric Paris No-objection-from: Serge E. Hallyn Acked-by: David Howells Acked-by: Serge E. Hallyn Acked-by: Andrew G. Morgan Signed-off-by: James Morris --- include/linux/kmod.h | 3 ++ kernel/kmod.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/sysctl.c | 6 ++++ 3 files changed, 109 insertions(+) (limited to 'include') diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 6efd7a78de6a..79bb98d71858 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -24,6 +24,7 @@ #include #include #include +#include #define KMOD_PATH_LEN 256 @@ -109,6 +110,8 @@ call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait) NULL, NULL, NULL); } +extern struct ctl_table usermodehelper_table[]; + extern void usermodehelper_init(void); extern int usermodehelper_disable(void); diff --git a/kernel/kmod.c b/kernel/kmod.c index 9cd0591c96a2..06fdea2819b6 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,13 @@ extern int max_threads; static struct workqueue_struct *khelper_wq; +#define CAP_BSET (void *)1 +#define CAP_PI (void *)2 + +static kernel_cap_t usermodehelper_bset = CAP_FULL_SET; +static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; +static DEFINE_SPINLOCK(umh_sysctl_lock); + #ifdef CONFIG_MODULES /* @@ -132,6 +140,7 @@ EXPORT_SYMBOL(__request_module); static int ____call_usermodehelper(void *data) { struct subprocess_info *sub_info = data; + struct cred *new; int retval; spin_lock_irq(¤t->sighand->siglock); @@ -153,6 +162,19 @@ static int ____call_usermodehelper(void *data) goto fail; } + retval = -ENOMEM; + new = prepare_kernel_cred(current); + if (!new) + goto fail; + + spin_lock(&umh_sysctl_lock); + new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset); + new->cap_inheritable = cap_intersect(usermodehelper_inheritable, + new->cap_inheritable); + spin_unlock(&umh_sysctl_lock); + + commit_creds(new); + retval = kernel_execve(sub_info->path, (const char *const *)sub_info->argv, (const char *const *)sub_info->envp); @@ -418,6 +440,84 @@ unlock: } EXPORT_SYMBOL(call_usermodehelper_exec); +static int proc_cap_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table t; + unsigned long cap_array[_KERNEL_CAPABILITY_U32S]; + kernel_cap_t new_cap; + int err, i; + + if (write && (!capable(CAP_SETPCAP) || + !capable(CAP_SYS_MODULE))) + return -EPERM; + + /* + * convert from the global kernel_cap_t to the ulong array to print to + * userspace if this is a read. + */ + spin_lock(&umh_sysctl_lock); + for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) { + if (table->data == CAP_BSET) + cap_array[i] = usermodehelper_bset.cap[i]; + else if (table->data == CAP_PI) + cap_array[i] = usermodehelper_inheritable.cap[i]; + else + BUG(); + } + spin_unlock(&umh_sysctl_lock); + + t = *table; + t.data = &cap_array; + + /* + * actually read or write and array of ulongs from userspace. Remember + * these are least significant 32 bits first + */ + err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos); + if (err < 0) + return err; + + /* + * convert from the sysctl array of ulongs to the kernel_cap_t + * internal representation + */ + for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) + new_cap.cap[i] = cap_array[i]; + + /* + * Drop everything not in the new_cap (but don't add things) + */ + spin_lock(&umh_sysctl_lock); + if (write) { + if (table->data == CAP_BSET) + usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap); + if (table->data == CAP_PI) + usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap); + } + spin_unlock(&umh_sysctl_lock); + + return 0; +} + +struct ctl_table usermodehelper_table[] = { + { + .procname = "bset", + .data = CAP_BSET, + .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long), + .mode = 0600, + .proc_handler = proc_cap_handler, + }, + { + .procname = "inheritable", + .data = CAP_PI, + .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long), + .mode = 0600, + .proc_handler = proc_cap_handler, + }, + { } +}; + void __init usermodehelper_init(void) { khelper_wq = create_singlethread_workqueue("khelper"); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c0bb32414b17..965134bed6cd 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -615,6 +616,11 @@ static struct ctl_table kern_table[] = { .mode = 0555, .child = random_table, }, + { + .procname = "usermodehelper", + .mode = 0555, + .child = usermodehelper_table, + }, { .procname = "overflowuid", .data = &overflowuid, -- cgit v1.2.3 From ffa8e59df047d57e812a04f7d6baf6a25c652c0c Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 1 Apr 2011 17:08:34 -0400 Subject: capabilities: do not drop CAP_SETPCAP from the initial task In olden' days of yore CAP_SETPCAP had special meaning for the init task. We actually have code to make sure that CAP_SETPCAP wasn't in pE of things using the init_cred. But CAP_SETPCAP isn't so special any more and we don't have a reason to special case dropping it for init or kthreads.... Signed-off-by: Eric Paris Acked-by: Andrew G. Morgan Signed-off-by: James Morris --- include/linux/capability.h | 6 ++++-- kernel/capability.c | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/capability.h b/include/linux/capability.h index 16ee8b49a200..11d562863e49 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -412,7 +412,6 @@ extern const kernel_cap_t __cap_init_eff_set; # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }}) # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }}) -# define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }}) # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \ CAP_FS_MASK_B1 } }) @@ -423,10 +422,10 @@ extern const kernel_cap_t __cap_init_eff_set; #endif /* _KERNEL_CAPABILITY_U32S != 2 */ #define CAP_INIT_INH_SET CAP_EMPTY_SET +#define CAP_INIT_EFF_SET CAP_FULL_SET # define cap_clear(c) do { (c) = __cap_empty_set; } while (0) # define cap_set_full(c) do { (c) = __cap_full_set; } while (0) -# define cap_set_init_eff(c) do { (c) = __cap_init_eff_set; } while (0) #define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag)) #define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag)) @@ -547,6 +546,9 @@ extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); extern bool task_ns_capable(struct task_struct *t, int cap); +extern const kernel_cap_t __cap_empty_set; +extern const kernel_cap_t __cap_full_set; + /** * nsown_capable - Check superior capability to one's own user_ns * @cap: The capability in question diff --git a/kernel/capability.c b/kernel/capability.c index bf0c734d0c12..2a374d512ead 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -23,11 +23,9 @@ const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET; const kernel_cap_t __cap_full_set = CAP_FULL_SET; -const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET; EXPORT_SYMBOL(__cap_empty_set); EXPORT_SYMBOL(__cap_full_set); -EXPORT_SYMBOL(__cap_init_eff_set); int file_caps_enabled = 1; -- cgit v1.2.3 From 5163b583a036b103c3cec7171d6731c125773ed6 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 1 Apr 2011 17:08:39 -0400 Subject: capabilities: delete unused cap_set_full unused code. Clean it up. Signed-off-by: Eric Paris Acked-by: David Howells Acked-by: Andrew G. Morgan Signed-off-by: James Morris --- include/linux/capability.h | 2 -- kernel/capability.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'include') diff --git a/include/linux/capability.h b/include/linux/capability.h index 11d562863e49..8d0da30dad23 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -425,7 +425,6 @@ extern const kernel_cap_t __cap_init_eff_set; #define CAP_INIT_EFF_SET CAP_FULL_SET # define cap_clear(c) do { (c) = __cap_empty_set; } while (0) -# define cap_set_full(c) do { (c) = __cap_full_set; } while (0) #define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag)) #define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag)) @@ -547,7 +546,6 @@ extern bool ns_capable(struct user_namespace *ns, int cap); extern bool task_ns_capable(struct task_struct *t, int cap); extern const kernel_cap_t __cap_empty_set; -extern const kernel_cap_t __cap_full_set; /** * nsown_capable - Check superior capability to one's own user_ns diff --git a/kernel/capability.c b/kernel/capability.c index 2a374d512ead..14ea4210a530 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -22,10 +22,8 @@ */ const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET; -const kernel_cap_t __cap_full_set = CAP_FULL_SET; EXPORT_SYMBOL(__cap_empty_set); -EXPORT_SYMBOL(__cap_full_set); int file_caps_enabled = 1; -- cgit v1.2.3 From a3232d2fa2e3cbab3e76d91cdae5890fee8a4034 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 1 Apr 2011 17:08:45 -0400 Subject: capabilities: delete all CAP_INIT macros The CAP_INIT macros of INH, BSET, and EFF made sense at one point in time, but now days they aren't helping. Just open code the logic in the init_cred. Signed-off-by: Eric Paris Acked-by: David Howells Signed-off-by: James Morris --- include/linux/capability.h | 3 --- include/linux/init_task.h | 7 ------- kernel/cred.c | 6 +++--- 3 files changed, 3 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/linux/capability.h b/include/linux/capability.h index 8d0da30dad23..04fed72809de 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -421,9 +421,6 @@ extern const kernel_cap_t __cap_init_eff_set; #endif /* _KERNEL_CAPABILITY_U32S != 2 */ -#define CAP_INIT_INH_SET CAP_EMPTY_SET -#define CAP_INIT_EFF_SET CAP_FULL_SET - # define cap_clear(c) do { (c) = __cap_empty_set; } while (0) #define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag)) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index caa151fbebb7..1f277204de34 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -83,13 +83,6 @@ extern struct group_info init_groups; #define INIT_IDS #endif -/* - * Because of the reduced scope of CAP_SETPCAP when filesystem - * capabilities are in effect, it is safe to allow CAP_SETPCAP to - * be available in the default configuration. - */ -# define CAP_INIT_BSET CAP_FULL_SET - #ifdef CONFIG_RCU_BOOST #define INIT_TASK_RCU_BOOST() \ .rcu_boost_mutex = NULL, diff --git a/kernel/cred.c b/kernel/cred.c index 5557b55048df..b982f0863ae9 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -49,10 +49,10 @@ struct cred init_cred = { .magic = CRED_MAGIC, #endif .securebits = SECUREBITS_DEFAULT, - .cap_inheritable = CAP_INIT_INH_SET, + .cap_inheritable = CAP_EMPTY_SET, .cap_permitted = CAP_FULL_SET, - .cap_effective = CAP_INIT_EFF_SET, - .cap_bset = CAP_INIT_BSET, + .cap_effective = CAP_FULL_SET, + .cap_bset = CAP_FULL_SET, .user = INIT_USER, .group_info = &init_groups, #ifdef CONFIG_KEYS -- cgit v1.2.3 From 1c9904297451f558191e211a48d8838b4bf792b0 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 21 Apr 2011 17:23:19 -0700 Subject: SECURITY: Move exec_permission RCU checks into security modules Right now all RCU walks fall back to reference walk when CONFIG_SECURITY is enabled, even though just the standard capability module is active. This is because security_inode_exec_permission unconditionally fails RCU walks. Move this decision to the low level security module. This requires passing the RCU flags down the security hook. This way at least the capability module and a few easy cases in selinux/smack work with RCU walks with CONFIG_SECURITY=y Signed-off-by: Andi Kleen Signed-off-by: Eric Paris --- include/linux/security.h | 2 +- security/capability.c | 2 +- security/security.c | 6 ++---- security/selinux/hooks.c | 6 +++++- security/smack/smack_lsm.c | 6 +++++- 5 files changed, 14 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/security.h b/include/linux/security.h index 84a202ac3de9..2f99ecd0fb2a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1454,7 +1454,7 @@ struct security_operations { struct inode *new_dir, struct dentry *new_dentry); int (*inode_readlink) (struct dentry *dentry); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); - int (*inode_permission) (struct inode *inode, int mask); + int (*inode_permission) (struct inode *inode, int mask, unsigned flags); int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); int (*inode_setxattr) (struct dentry *dentry, const char *name, diff --git a/security/capability.c b/security/capability.c index ab3d807accc3..56bb1605fd79 100644 --- a/security/capability.c +++ b/security/capability.c @@ -181,7 +181,7 @@ static int cap_inode_follow_link(struct dentry *dentry, return 0; } -static int cap_inode_permission(struct inode *inode, int mask) +static int cap_inode_permission(struct inode *inode, int mask, unsigned flags) { return 0; } diff --git a/security/security.c b/security/security.c index 47b8a447118f..7e34f98bf433 100644 --- a/security/security.c +++ b/security/security.c @@ -514,16 +514,14 @@ int security_inode_permission(struct inode *inode, int mask) { if (unlikely(IS_PRIVATE(inode))) return 0; - return security_ops->inode_permission(inode, mask); + return security_ops->inode_permission(inode, mask, 0); } int security_inode_exec_permission(struct inode *inode, unsigned int flags) { if (unlikely(IS_PRIVATE(inode))) return 0; - if (flags) - return -ECHILD; - return security_ops->inode_permission(inode, MAY_EXEC); + return security_ops->inode_permission(inode, MAY_EXEC, flags); } int security_inode_setattr(struct dentry *dentry, struct iattr *attr) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7a630a8a5cef..9a220be17a3f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2635,7 +2635,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na return dentry_has_perm(cred, NULL, dentry, FILE__READ); } -static int selinux_inode_permission(struct inode *inode, int mask) +static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) { const struct cred *cred = current_cred(); struct common_audit_data ad; @@ -2649,6 +2649,10 @@ static int selinux_inode_permission(struct inode *inode, int mask) if (!mask) return 0; + /* May be droppable after audit */ + if (flags & IPERM_FLAG_RCU) + return -ECHILD; + COMMON_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.inode = inode; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 23c7a6d0c80c..42fcb47747a3 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -686,7 +686,7 @@ static int smack_inode_rename(struct inode *old_inode, * * Returns 0 if access is permitted, -EACCES otherwise */ -static int smack_inode_permission(struct inode *inode, int mask) +static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) { struct smk_audit_info ad; @@ -696,6 +696,10 @@ static int smack_inode_permission(struct inode *inode, int mask) */ if (mask == 0) return 0; + + /* May be droppable after audit */ + if (flags & IPERM_FLAG_RCU) + return -ECHILD; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_setfield_u_fs_inode(&ad, inode); return smk_curacc(smk_of_inode(inode), mask, &ad); -- cgit v1.2.3 From f48b7399840b453e7282b523f535561fe9638a2d Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 25 Apr 2011 12:54:27 -0400 Subject: LSM: split LSM_AUDIT_DATA_FS into _PATH and _INODE The lsm common audit code has wacky contortions making sure which pieces of information are set based on if it was given a path, dentry, or inode. Split this into path and inode to get rid of some of the code complexity. Signed-off-by: Eric Paris Acked-by: Casey Schaufler --- include/linux/lsm_audit.h | 9 ++++----- security/lsm_audit.c | 50 ++++++++++++++++++++++++++-------------------- security/selinux/avc.c | 2 +- security/selinux/hooks.c | 50 +++++++++++++++++++++++----------------------- security/smack/smack.h | 8 ++++---- security/smack/smack_lsm.c | 32 ++++++++++++++--------------- 6 files changed, 78 insertions(+), 73 deletions(-) (limited to 'include') diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 112a55033352..bbaceab83a65 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -27,7 +27,7 @@ /* Auxiliary data to use in generating the audit record. */ struct common_audit_data { char type; -#define LSM_AUDIT_DATA_FS 1 +#define LSM_AUDIT_DATA_PATH 1 #define LSM_AUDIT_DATA_NET 2 #define LSM_AUDIT_DATA_CAP 3 #define LSM_AUDIT_DATA_IPC 4 @@ -35,12 +35,11 @@ struct common_audit_data { #define LSM_AUDIT_DATA_KEY 6 #define LSM_AUDIT_DATA_NONE 7 #define LSM_AUDIT_DATA_KMOD 8 +#define LSM_AUDIT_DATA_INODE 9 struct task_struct *tsk; union { - struct { - struct path path; - struct inode *inode; - } fs; + struct path path; + struct inode *inode; struct { int netif; struct sock *sk; diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 908aa712816a..2e846052cbf4 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -210,7 +210,6 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, static void dump_common_audit_data(struct audit_buffer *ab, struct common_audit_data *a) { - struct inode *inode = NULL; struct task_struct *tsk = current; if (a->tsk) @@ -229,33 +228,40 @@ static void dump_common_audit_data(struct audit_buffer *ab, case LSM_AUDIT_DATA_CAP: audit_log_format(ab, " capability=%d ", a->u.cap); break; - case LSM_AUDIT_DATA_FS: - if (a->u.fs.path.dentry) { - struct dentry *dentry = a->u.fs.path.dentry; - if (a->u.fs.path.mnt) { - audit_log_d_path(ab, "path=", &a->u.fs.path); - } else { - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, - dentry->d_name.name); - } - inode = dentry->d_inode; - } else if (a->u.fs.inode) { - struct dentry *dentry; - inode = a->u.fs.inode; - dentry = d_find_alias(inode); - if (dentry) { - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, - dentry->d_name.name); - dput(dentry); - } + case LSM_AUDIT_DATA_PATH: { + struct dentry *dentry = a->u.path.dentry; + struct inode *inode; + + if (a->u.path.mnt) { + audit_log_d_path(ab, "path=", &a->u.path); + } else { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, + dentry->d_name.name); } + inode = dentry->d_inode; if (inode) audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id, inode->i_ino); break; + } + case LSM_AUDIT_DATA_INODE: { + struct dentry *dentry; + struct inode *inode; + + inode = a->u.inode; + dentry = d_find_alias(inode); + if (dentry) { + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, + dentry->d_name.name); + dput(dentry); + } + audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id, + inode->i_ino); + break; + } case LSM_AUDIT_DATA_TASK: tsk = a->u.tsk; if (tsk && tsk->pid) { diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 1d027e29ce8d..ce742f1778e1 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -531,7 +531,7 @@ int avc_audit(u32 ssid, u32 tsid, * during retry. However this is logically just as if the operation * happened a little later. */ - if ((a->type == LSM_AUDIT_DATA_FS) && + if ((a->type == LSM_AUDIT_DATA_INODE) && (flags & IPERM_FLAG_RCU)) return -ECHILD; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ed5f29aa0a38..ad664d3056eb 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1488,8 +1488,8 @@ static int inode_has_perm(const struct cred *cred, if (!adp) { adp = &ad; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.inode = inode; + COMMON_AUDIT_DATA_INIT(&ad, INODE); + ad.u.inode = inode; } return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); @@ -1506,9 +1506,9 @@ static inline int dentry_has_perm(const struct cred *cred, struct inode *inode = dentry->d_inode; struct common_audit_data ad; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path.mnt = mnt; - ad.u.fs.path.dentry = dentry; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path.mnt = mnt; + ad.u.path.dentry = dentry; return inode_has_perm(cred, inode, av, &ad, 0); } @@ -1530,8 +1530,8 @@ static int file_has_perm(const struct cred *cred, u32 sid = cred_sid(cred); int rc; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path = file->f_path; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path = file->f_path; if (sid != fsec->sid) { rc = avc_has_perm(sid, fsec->sid, @@ -1569,8 +1569,8 @@ static int may_create(struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path.dentry = dentry; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path.dentry = dentry; rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, @@ -1621,8 +1621,8 @@ static int may_link(struct inode *dir, dsec = dir->i_security; isec = dentry->d_inode->i_security; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path.dentry = dentry; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path.dentry = dentry; av = DIR__SEARCH; av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); @@ -1667,9 +1667,9 @@ static inline int may_rename(struct inode *old_dir, old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); new_dsec = new_dir->i_security; - COMMON_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, PATH); - ad.u.fs.path.dentry = old_dentry; + ad.u.path.dentry = old_dentry; rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, DIR__REMOVE_NAME | DIR__SEARCH, &ad); if (rc) @@ -1685,7 +1685,7 @@ static inline int may_rename(struct inode *old_dir, return rc; } - ad.u.fs.path.dentry = new_dentry; + ad.u.path.dentry = new_dentry; av = DIR__ADD_NAME | DIR__SEARCH; if (new_dentry->d_inode) av |= DIR__REMOVE_NAME; @@ -1991,8 +1991,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) return rc; } - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path = bprm->file->f_path; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path = bprm->file->f_path; if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) new_tsec->sid = old_tsec->sid; @@ -2120,7 +2120,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, /* Revalidate access to inherited open files. */ - COMMON_AUDIT_DATA_INIT(&ad, FS); + COMMON_AUDIT_DATA_INIT(&ad, INODE); spin_lock(&files->file_lock); for (;;) { @@ -2468,8 +2468,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) if (flags & MS_KERNMOUNT) return 0; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path.dentry = sb->s_root; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path.dentry = sb->s_root; return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); } @@ -2478,8 +2478,8 @@ static int selinux_sb_statfs(struct dentry *dentry) const struct cred *cred = current_cred(); struct common_audit_data ad; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path.dentry = dentry->d_sb->s_root; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path.dentry = dentry->d_sb->s_root; return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } @@ -2653,8 +2653,8 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag if (!mask) return 0; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.inode = inode; + COMMON_AUDIT_DATA_INIT(&ad, INODE); + ad.u.inode = inode; if (from_access) ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; @@ -2732,8 +2732,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, if (!is_owner_or_cap(inode)) return -EPERM; - COMMON_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.path.dentry = dentry; + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path.dentry = dentry; rc = avc_has_perm(sid, isec->sid, isec->sclass, FILE__RELABELFROM, &ad); diff --git a/security/smack/smack.h b/security/smack/smack.h index b449cfdad21c..a16925c0e91a 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -316,22 +316,22 @@ static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, struct dentry *d) { - a->a.u.fs.path.dentry = d; + a->a.u.path.dentry = d; } static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a, struct vfsmount *m) { - a->a.u.fs.path.mnt = m; + a->a.u.path.mnt = m; } static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, struct inode *i) { - a->a.u.fs.inode = i; + a->a.u.inode = i; } static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, struct path p) { - a->a.u.fs.path = p; + a->a.u.path = p; } static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, struct sock *sk) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 42fcb47747a3..eeb393fbf925 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -383,7 +383,7 @@ static int smack_sb_statfs(struct dentry *dentry) int rc; struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); @@ -407,7 +407,7 @@ static int smack_sb_mount(char *dev_name, struct path *path, struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, *path); return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); @@ -426,7 +426,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags) struct superblock_smack *sbp; struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root); smk_ad_setfield_u_fs_path_mnt(&ad, mnt); @@ -563,7 +563,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, struct smk_audit_info ad; int rc; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(old_dentry->d_inode); @@ -592,7 +592,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) struct smk_audit_info ad; int rc; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); /* @@ -623,7 +623,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) struct smk_audit_info ad; int rc; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); /* @@ -663,7 +663,7 @@ static int smack_inode_rename(struct inode *old_inode, char *isp; struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(old_dentry->d_inode); @@ -700,7 +700,7 @@ static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) /* May be droppable after audit */ if (flags & IPERM_FLAG_RCU) return -ECHILD; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, inode); return smk_curacc(smk_of_inode(inode), mask, &ad); } @@ -720,7 +720,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) */ if (iattr->ia_valid & ATTR_FORCE) return 0; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); @@ -737,7 +737,7 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) { struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); smk_ad_setfield_u_fs_path_mnt(&ad, mnt); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); @@ -784,7 +784,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, } else rc = cap_inode_setxattr(dentry, name, value, size, flags); - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); if (rc == 0) @@ -845,7 +845,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) { struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); @@ -877,7 +877,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) } else rc = cap_inode_removexattr(dentry, name); - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); if (rc == 0) rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); @@ -1047,7 +1047,7 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, int rc = 0; struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); if (_IOC_DIR(cmd) & _IOC_WRITE) @@ -1070,7 +1070,7 @@ static int smack_file_lock(struct file *file, unsigned int cmd) { struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); return smk_curacc(file->f_security, MAY_WRITE, &ad); } @@ -1089,7 +1089,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, struct smk_audit_info ad; int rc; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); switch (cmd) { -- cgit v1.2.3 From a269434d2fb48a4d66c1d7bf821b7874b59c5b41 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 25 Apr 2011 13:10:27 -0400 Subject: LSM: separate LSM_AUDIT_DATA_DENTRY from LSM_AUDIT_DATA_PATH This patch separates and audit message that only contains a dentry from one that contains a full path. This allows us to make it harder to misuse the interfaces or for the interfaces to be implemented wrong. Signed-off-by: Eric Paris Acked-by: Casey Schaufler --- include/linux/lsm_audit.h | 2 ++ security/lsm_audit.c | 25 ++++++++++++++++--------- security/selinux/hooks.c | 26 +++++++++++++------------- security/smack/smack.h | 7 +------ security/smack/smack_lsm.c | 34 ++++++++++++++++++++-------------- 5 files changed, 52 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index bbaceab83a65..88e78dedc2e8 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -36,9 +36,11 @@ struct common_audit_data { #define LSM_AUDIT_DATA_NONE 7 #define LSM_AUDIT_DATA_KMOD 8 #define LSM_AUDIT_DATA_INODE 9 +#define LSM_AUDIT_DATA_DENTRY 10 struct task_struct *tsk; union { struct path path; + struct dentry *dentry; struct inode *inode; struct { int netif; diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 2e846052cbf4..893af8a2fa1e 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -229,17 +229,24 @@ static void dump_common_audit_data(struct audit_buffer *ab, audit_log_format(ab, " capability=%d ", a->u.cap); break; case LSM_AUDIT_DATA_PATH: { - struct dentry *dentry = a->u.path.dentry; struct inode *inode; - if (a->u.path.mnt) { - audit_log_d_path(ab, "path=", &a->u.path); - } else { - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, - dentry->d_name.name); - } - inode = dentry->d_inode; + audit_log_d_path(ab, "path=", &a->u.path); + + inode = a->u.path.dentry->d_inode; + if (inode) + audit_log_format(ab, " dev=%s ino=%lu", + inode->i_sb->s_id, + inode->i_ino); + break; + } + case LSM_AUDIT_DATA_DENTRY: { + struct inode *inode; + + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, a->u.dentry->d_name.name); + + inode = a->u.dentry->d_inode; if (inode) audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id, diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ad664d3056eb..9e8078a42a94 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1569,8 +1569,8 @@ static int may_create(struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - COMMON_AUDIT_DATA_INIT(&ad, PATH); - ad.u.path.dentry = dentry; + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); + ad.u.dentry = dentry; rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, @@ -1621,8 +1621,8 @@ static int may_link(struct inode *dir, dsec = dir->i_security; isec = dentry->d_inode->i_security; - COMMON_AUDIT_DATA_INIT(&ad, PATH); - ad.u.path.dentry = dentry; + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); + ad.u.dentry = dentry; av = DIR__SEARCH; av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); @@ -1667,9 +1667,9 @@ static inline int may_rename(struct inode *old_dir, old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); new_dsec = new_dir->i_security; - COMMON_AUDIT_DATA_INIT(&ad, PATH); + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); - ad.u.path.dentry = old_dentry; + ad.u.dentry = old_dentry; rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, DIR__REMOVE_NAME | DIR__SEARCH, &ad); if (rc) @@ -1685,7 +1685,7 @@ static inline int may_rename(struct inode *old_dir, return rc; } - ad.u.path.dentry = new_dentry; + ad.u.dentry = new_dentry; av = DIR__ADD_NAME | DIR__SEARCH; if (new_dentry->d_inode) av |= DIR__REMOVE_NAME; @@ -2468,8 +2468,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) if (flags & MS_KERNMOUNT) return 0; - COMMON_AUDIT_DATA_INIT(&ad, PATH); - ad.u.path.dentry = sb->s_root; + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); + ad.u.dentry = sb->s_root; return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); } @@ -2478,8 +2478,8 @@ static int selinux_sb_statfs(struct dentry *dentry) const struct cred *cred = current_cred(); struct common_audit_data ad; - COMMON_AUDIT_DATA_INIT(&ad, PATH); - ad.u.path.dentry = dentry->d_sb->s_root; + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); + ad.u.dentry = dentry->d_sb->s_root; return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } @@ -2732,8 +2732,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, if (!is_owner_or_cap(inode)) return -EPERM; - COMMON_AUDIT_DATA_INIT(&ad, PATH); - ad.u.path.dentry = dentry; + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); + ad.u.dentry = dentry; rc = avc_has_perm(sid, isec->sid, isec->sclass, FILE__RELABELFROM, &ad); diff --git a/security/smack/smack.h b/security/smack/smack.h index a16925c0e91a..2b6c6a516123 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -316,12 +316,7 @@ static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, struct dentry *d) { - a->a.u.path.dentry = d; -} -static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a, - struct vfsmount *m) -{ - a->a.u.path.mnt = m; + a->a.u.dentry = d; } static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, struct inode *i) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index eeb393fbf925..a3bdd1383928 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -383,7 +383,7 @@ static int smack_sb_statfs(struct dentry *dentry) int rc; struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); @@ -425,10 +425,13 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags) { struct superblock_smack *sbp; struct smk_audit_info ad; + struct path path; + + path.dentry = mnt->mnt_root; + path.mnt = mnt; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); - smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root); - smk_ad_setfield_u_fs_path_mnt(&ad, mnt); + smk_ad_setfield_u_fs_path(&ad, path); sbp = mnt->mnt_sb->s_security; return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); @@ -563,7 +566,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, struct smk_audit_info ad; int rc; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(old_dentry->d_inode); @@ -592,7 +595,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) struct smk_audit_info ad; int rc; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); /* @@ -623,7 +626,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) struct smk_audit_info ad; int rc; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); /* @@ -663,7 +666,7 @@ static int smack_inode_rename(struct inode *old_inode, char *isp; struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(old_dentry->d_inode); @@ -720,7 +723,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) */ if (iattr->ia_valid & ATTR_FORCE) return 0; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); @@ -736,10 +739,13 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) { struct smk_audit_info ad; + struct path path; + + path.dentry = dentry; + path.mnt = mnt; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); - smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - smk_ad_setfield_u_fs_path_mnt(&ad, mnt); + smk_ad_setfield_u_fs_path(&ad, path); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); } @@ -784,7 +790,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, } else rc = cap_inode_setxattr(dentry, name, value, size, flags); - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); if (rc == 0) @@ -845,7 +851,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) { struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); @@ -877,7 +883,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) } else rc = cap_inode_removexattr(dentry, name); - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); if (rc == 0) rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); @@ -1070,7 +1076,7 @@ static int smack_file_lock(struct file *file, unsigned int cmd) { struct smk_audit_info ad; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); return smk_curacc(file->f_security, MAY_WRITE, &ad); } -- cgit v1.2.3 From 5a3ea8782c63d3501cb764c176f153c0d9a400e1 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 28 Apr 2011 15:55:52 -0400 Subject: flex_array: flex_array_prealloc takes a number of elements, not an end Change flex_array_prealloc to take the number of elements for which space should be allocated instead of the last (inclusive) element. Users and documentation are updated accordingly. flex_arrays got introduced before they had users. When folks started using it, they ended up needing a different API than was coded up originally. This swaps over to the API that folks apparently need. Based-on-patch-by: Steffen Klassert Signed-off-by: Eric Paris Tested-by: Chris Richards Acked-by: Dave Hansen Cc: stable@kernel.org [2.6.38+] --- Documentation/flexible-arrays.txt | 4 ++-- include/linux/flex_array.h | 2 +- lib/flex_array.c | 13 ++++++++----- security/selinux/ss/policydb.c | 6 +++--- 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/Documentation/flexible-arrays.txt b/Documentation/flexible-arrays.txt index cb8a3a00cc92..df904aec9904 100644 --- a/Documentation/flexible-arrays.txt +++ b/Documentation/flexible-arrays.txt @@ -66,10 +66,10 @@ trick is to ensure that any needed memory allocations are done before entering atomic context, using: int flex_array_prealloc(struct flex_array *array, unsigned int start, - unsigned int end, gfp_t flags); + unsigned int nr_elements, gfp_t flags); This function will ensure that memory for the elements indexed in the range -defined by start and end has been allocated. Thereafter, a +defined by start and nr_elements has been allocated. Thereafter, a flex_array_put() call on an element in that range is guaranteed not to block. diff --git a/include/linux/flex_array.h b/include/linux/flex_array.h index 70e4efabe0fb..ebeb2f3ad068 100644 --- a/include/linux/flex_array.h +++ b/include/linux/flex_array.h @@ -61,7 +61,7 @@ struct flex_array { struct flex_array *flex_array_alloc(int element_size, unsigned int total, gfp_t flags); int flex_array_prealloc(struct flex_array *fa, unsigned int start, - unsigned int end, gfp_t flags); + unsigned int nr_elements, gfp_t flags); void flex_array_free(struct flex_array *fa); void flex_array_free_parts(struct flex_array *fa); int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, diff --git a/lib/flex_array.c b/lib/flex_array.c index c0ea40ba2082..0c33b24498ba 100644 --- a/lib/flex_array.c +++ b/lib/flex_array.c @@ -232,10 +232,10 @@ EXPORT_SYMBOL(flex_array_clear); /** * flex_array_prealloc - guarantee that array space exists - * @fa: the flex array for which to preallocate parts - * @start: index of first array element for which space is allocated - * @end: index of last (inclusive) element for which space is allocated - * @flags: page allocation flags + * @fa: the flex array for which to preallocate parts + * @start: index of first array element for which space is allocated + * @nr_elements: number of elements for which space is allocated + * @flags: page allocation flags * * This will guarantee that no future calls to flex_array_put() * will allocate memory. It can be used if you are expecting to @@ -245,13 +245,16 @@ EXPORT_SYMBOL(flex_array_clear); * Locking must be provided by the caller. */ int flex_array_prealloc(struct flex_array *fa, unsigned int start, - unsigned int end, gfp_t flags) + unsigned int nr_elements, gfp_t flags) { int start_part; int end_part; int part_nr; + unsigned int end; struct flex_array_part *part; + end = start + nr_elements - 1; + if (start >= fa->total_nr_elements || end >= fa->total_nr_elements) return -ENOSPC; if (elements_fit_in_base(fa)) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 549120c56edd..102e9ec1b77a 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -545,7 +545,7 @@ static int policydb_index(struct policydb *p) goto out; rc = flex_array_prealloc(p->type_val_to_struct_array, 0, - p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO); + p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto out; @@ -562,7 +562,7 @@ static int policydb_index(struct policydb *p) goto out; rc = flex_array_prealloc(p->sym_val_to_name[i], - 0, p->symtab[i].nprim - 1, + 0, p->symtab[i].nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto out; @@ -2439,7 +2439,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; /* preallocate so we don't have to worry about the put ever failing */ - rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1, + rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); if (rc) goto bad; -- cgit v1.2.3