diff options
| -rw-r--r-- | fs/binfmt_flat.c | 8 | ||||
| -rw-r--r-- | include/linux/capability.h | 5 | ||||
| -rw-r--r-- | include/linux/init_task.h | 7 | ||||
| -rw-r--r-- | include/linux/key.h | 13 | ||||
| -rw-r--r-- | include/linux/kmod.h | 3 | ||||
| -rw-r--r-- | kernel/capability.c | 4 | ||||
| -rw-r--r-- | kernel/cred.c | 6 | ||||
| -rw-r--r-- | kernel/kmod.c | 100 | ||||
| -rw-r--r-- | kernel/sysctl.c | 6 | ||||
| -rw-r--r-- | net/dns_resolver/dns_key.c | 10 | ||||
| -rw-r--r-- | security/Kconfig | 1 | ||||
| -rw-r--r-- | security/commoncap.c | 13 | ||||
| -rw-r--r-- | security/keys/internal.h | 4 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 6 | ||||
| -rw-r--r-- | security/keys/keyring.c | 37 | ||||
| -rw-r--r-- | security/keys/proc.c | 2 | ||||
| -rw-r--r-- | security/keys/process_keys.c | 12 | ||||
| -rw-r--r-- | security/keys/request_key.c | 3 | ||||
| -rw-r--r-- | security/keys/request_key_auth.c | 3 | ||||
| -rw-r--r-- | security/keys/user_defined.c | 4 | ||||
| -rw-r--r-- | security/tomoyo/common.c | 17 | ||||
| -rw-r--r-- | security/tomoyo/file.c | 1 | ||||
| -rw-r--r-- | security/tomoyo/memory.c | 1 | ||||
| -rw-r--r-- | security/tomoyo/mount.c | 1 | ||||
| -rw-r--r-- | security/tomoyo/util.c | 2 | 
25 files changed, 205 insertions, 64 deletions
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 397d3057d33..1bffbe0ed77 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -820,6 +820,8 @@ static int load_flat_shared_library(int id, struct lib_info *libs)  	int res;  	char buf[16]; +	memset(&bprm, 0, sizeof(bprm)); +  	/* Create the file name */  	sprintf(buf, "/lib/lib%d.so", id); @@ -835,6 +837,12 @@ static int load_flat_shared_library(int id, struct lib_info *libs)  	if (!bprm.cred)  		goto out; +	/* We don't really care about recalculating credentials at this point +	 * as we're past the point of no return and are dealing with shared +	 * libraries. +	 */ +	bprm.cred_prepared = 1; +  	res = prepare_binprm(&bprm);  	if (!IS_ERR_VALUE(res)) diff --git a/include/linux/capability.h b/include/linux/capability.h index 4554db0cde8..c4211235000 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -417,7 +417,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 } }) @@ -427,11 +426,7 @@ extern const kernel_cap_t __cap_init_eff_set;  #endif /* _KERNEL_CAPABILITY_U32S != 2 */ -#define CAP_INIT_INH_SET    CAP_EMPTY_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)) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 689496bb665..bafc58c00fc 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/include/linux/key.h b/include/linux/key.h index b2bb0171956..ef19b99aff9 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))) diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 31023182385..d4a5c84c503 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -24,6 +24,7 @@  #include <linux/errno.h>  #include <linux/compiler.h>  #include <linux/workqueue.h> +#include <linux/sysctl.h>  #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/capability.c b/kernel/capability.c index 32a80e08ff4..283c529f8b1 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -22,12 +22,8 @@   */  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; diff --git a/kernel/cred.c b/kernel/cred.c index 8093c16b84b..e12c8af793f 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,  	.user_ns		= &init_user_ns,  	.group_info		= &init_groups, diff --git a/kernel/kmod.c b/kernel/kmod.c index 5ae0ff38425..ad6a81c58b4 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -25,6 +25,7 @@  #include <linux/kmod.h>  #include <linux/slab.h>  #include <linux/completion.h> +#include <linux/cred.h>  #include <linux/file.h>  #include <linux/fdtable.h>  #include <linux/workqueue.h> @@ -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); @@ -420,6 +442,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 3dd0c46fa3b..4bffd62c2f1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -56,6 +56,7 @@  #include <linux/kprobes.h>  #include <linux/pipe_fs_i.h>  #include <linux/oom.h> +#include <linux/kmod.h>  #include <asm/uaccess.h>  #include <asm/processor.h> @@ -616,6 +617,11 @@ static struct ctl_table kern_table[] = {  		.child		= random_table,  	},  	{ +		.procname	= "usermodehelper", +		.mode		= 0555, +		.child		= usermodehelper_table, +	}, +	{  		.procname	= "overflowuid",  		.data		= &overflowuid,  		.maxlen		= sizeof(int), diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index cfa7a5e1c5c..fa000d26dc6 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -212,10 +212,12 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)  	int err = key->type_data.x[0];  	seq_puts(m, key->description); -	if (err) -		seq_printf(m, ": %d", err); -	else -		seq_printf(m, ": %u", key->datalen); +	if (key_is_instantiated(key)) { +		if (err) +			seq_printf(m, ": %d", err); +		else +			seq_printf(m, ": %u", key->datalen); +	}  }  /* diff --git a/security/Kconfig b/security/Kconfig index 95accd442d5..e0f08b52e4a 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -167,6 +167,7 @@ config INTEL_TXT  config LSM_MMAP_MIN_ADDR  	int "Low address space for LSM to protect from user allocation"  	depends on SECURITY && SECURITY_SELINUX +	default 32768 if ARM  	default 65536  	help  	  This is the portion of low virtual memory which should be protected diff --git a/security/commoncap.c b/security/commoncap.c index f20e984ccfb..a93b3b73307 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -529,15 +529,10 @@ skip:  	new->suid = new->fsuid = new->euid;  	new->sgid = new->fsgid = new->egid; -	/* For init, we want to retain the capabilities set in the initial -	 * task.  Thus we skip the usual capability rules -	 */ -	if (!is_global_init(current)) { -		if (effective) -			new->cap_effective = new->cap_permitted; -		else -			cap_clear(new->cap_effective); -	} +	if (effective) +		new->cap_effective = new->cap_permitted; +	else +		cap_clear(new->cap_effective);  	bprm->cap_effective = effective;  	/* diff --git a/security/keys/internal.h b/security/keys/internal.h index 07a025f8190..f375152a250 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -109,11 +109,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,  				    const struct cred *cred,  				    struct key_type *type,  				    const void *description, -				    key_match_func_t match); +				    key_match_func_t match, +				    bool no_state_check);  extern key_ref_t search_my_process_keyrings(struct key_type *type,  					    const void *description,  					    key_match_func_t match, +					    bool no_state_check,  					    const struct cred *cred);  extern key_ref_t search_process_keyrings(struct key_type *type,  					 const void *description, diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 427fddcaeb1..eca51918c95 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -206,8 +206,14 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,  		goto error5;  	} +	/* wait for the key to finish being constructed */ +	ret = wait_for_key_construction(key, 1); +	if (ret < 0) +		goto error6; +  	ret = key->serial; +error6:   	key_put(key);  error5:  	key_type_put(ktype); diff --git a/security/keys/keyring.c b/security/keys/keyring.c index cdd2f3f88c8..a06ffab3856 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -176,13 +176,15 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)  	else  		seq_puts(m, "[anon]"); -	rcu_read_lock(); -	klist = rcu_dereference(keyring->payload.subscriptions); -	if (klist) -		seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); -	else -		seq_puts(m, ": empty"); -	rcu_read_unlock(); +	if (key_is_instantiated(keyring)) { +		rcu_read_lock(); +		klist = rcu_dereference(keyring->payload.subscriptions); +		if (klist) +			seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); +		else +			seq_puts(m, ": empty"); +		rcu_read_unlock(); +	}  }  /* @@ -271,6 +273,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,   * @type: The type of key to search for.   * @description: Parameter for @match.   * @match: Function to rule on whether or not a key is the one required. + * @no_state_check: Don't check if a matching key is bad   *   * Search the supplied keyring tree for a key that matches the criteria given.   * The root keyring and any linked keyrings must grant Search permission to the @@ -303,7 +306,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,  			     const struct cred *cred,  			     struct key_type *type,  			     const void *description, -			     key_match_func_t match) +			     key_match_func_t match, +			     bool no_state_check)  {  	struct {  		struct keyring_list *keylist; @@ -345,6 +349,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,  	kflags = keyring->flags;  	if (keyring->type == type && match(keyring, description)) {  		key = keyring; +		if (no_state_check) +			goto found;  		/* check it isn't negative and hasn't expired or been  		 * revoked */ @@ -384,11 +390,13 @@ descend:  			continue;  		/* skip revoked keys and expired keys */ -		if (kflags & (1 << KEY_FLAG_REVOKED)) -			continue; +		if (!no_state_check) { +			if (kflags & (1 << KEY_FLAG_REVOKED)) +				continue; -		if (key->expiry && now.tv_sec >= key->expiry) -			continue; +			if (key->expiry && now.tv_sec >= key->expiry) +				continue; +		}  		/* keys that don't match */  		if (!match(key, description)) @@ -399,6 +407,9 @@ descend:  					cred, KEY_SEARCH) < 0)  			continue; +		if (no_state_check) +			goto found; +  		/* we set a different error code if we pass a negative key */  		if (kflags & (1 << KEY_FLAG_NEGATIVE)) {  			err = key->type_data.reject_error; @@ -478,7 +489,7 @@ key_ref_t keyring_search(key_ref_t keyring,  		return ERR_PTR(-ENOKEY);  	return keyring_search_aux(keyring, current->cred, -				  type, description, type->match); +				  type, description, type->match, false);  }  EXPORT_SYMBOL(keyring_search); diff --git a/security/keys/proc.c b/security/keys/proc.c index 525cf8a29cd..49bbc97943a 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -199,7 +199,7 @@ static int proc_keys_show(struct seq_file *m, void *v)  	if (key->perm & KEY_POS_VIEW) {  		skey_ref = search_my_process_keyrings(key->type, key,  						      lookup_user_key_possessed, -						      cred); +						      true, cred);  		if (!IS_ERR(skey_ref)) {  			key_ref_put(skey_ref);  			key_ref = make_key_ref(key, 1); diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 930634e4514..6c0480db888 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -331,6 +331,7 @@ void key_fsgid_changed(struct task_struct *tsk)  key_ref_t search_my_process_keyrings(struct key_type *type,  				     const void *description,  				     key_match_func_t match, +				     bool no_state_check,  				     const struct cred *cred)  {  	key_ref_t key_ref, ret, err; @@ -350,7 +351,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,  	if (cred->thread_keyring) {  		key_ref = keyring_search_aux(  			make_key_ref(cred->thread_keyring, 1), -			cred, type, description, match); +			cred, type, description, match, no_state_check);  		if (!IS_ERR(key_ref))  			goto found; @@ -371,7 +372,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,  	if (cred->tgcred->process_keyring) {  		key_ref = keyring_search_aux(  			make_key_ref(cred->tgcred->process_keyring, 1), -			cred, type, description, match); +			cred, type, description, match, no_state_check);  		if (!IS_ERR(key_ref))  			goto found; @@ -395,7 +396,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,  			make_key_ref(rcu_dereference(  					     cred->tgcred->session_keyring),  				     1), -			cred, type, description, match); +			cred, type, description, match, no_state_check);  		rcu_read_unlock();  		if (!IS_ERR(key_ref)) @@ -417,7 +418,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,  	else if (cred->user->session_keyring) {  		key_ref = keyring_search_aux(  			make_key_ref(cred->user->session_keyring, 1), -			cred, type, description, match); +			cred, type, description, match, no_state_check);  		if (!IS_ERR(key_ref))  			goto found; @@ -459,7 +460,8 @@ key_ref_t search_process_keyrings(struct key_type *type,  	might_sleep(); -	key_ref = search_my_process_keyrings(type, description, match, cred); +	key_ref = search_my_process_keyrings(type, description, match, +					     false, cred);  	if (!IS_ERR(key_ref))  		goto found;  	err = key_ref; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index df3c0417ee4..b18a7174590 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -530,8 +530,7 @@ struct key *request_key_and_link(struct key_type *type,  	       dest_keyring, flags);  	/* search all the process keyrings for a key */ -	key_ref = search_process_keyrings(type, description, type->match, -					  cred); +	key_ref = search_process_keyrings(type, description, type->match, cred);  	if (!IS_ERR(key_ref)) {  		key = key_ref_to_ptr(key_ref); diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 68164031a74..f6337c9082e 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -59,7 +59,8 @@ static void request_key_auth_describe(const struct key *key,  	seq_puts(m, "key:");  	seq_puts(m, key->description); -	seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); +	if (key_is_instantiated(key)) +		seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);  }  /* diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index f66baf44f32..5b366d7af3c 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -157,8 +157,8 @@ EXPORT_SYMBOL_GPL(user_destroy);  void user_describe(const struct key *key, struct seq_file *m)  {  	seq_puts(m, key->description); - -	seq_printf(m, ": %u", key->datalen); +	if (key_is_instantiated(key)) +		seq_printf(m, ": %u", key->datalen);  }  EXPORT_SYMBOL_GPL(user_describe); diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 7556315c197..a0d09e56874 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -108,10 +108,9 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)  			head->read_user_buf += len;  			w += len;  		} -		if (*w) { -			head->r.w[0] = w; +		head->r.w[0] = w; +		if (*w)  			return false; -		}  		/* Add '\0' for query. */  		if (head->poll) {  			if (!head->read_user_buf_avail || @@ -459,8 +458,16 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)  	if (profile == &tomoyo_default_profile)  		return -EINVAL;  	if (!strcmp(data, "COMMENT")) { -		const struct tomoyo_path_info *old_comment = profile->comment; -		profile->comment = tomoyo_get_name(cp); +		static DEFINE_SPINLOCK(lock); +		const struct tomoyo_path_info *new_comment +			= tomoyo_get_name(cp); +		const struct tomoyo_path_info *old_comment; +		if (!new_comment) +			return -ENOMEM; +		spin_lock(&lock); +		old_comment = profile->comment; +		profile->comment = new_comment; +		spin_unlock(&lock);  		tomoyo_put_name(old_comment);  		return 0;  	} diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index cb09f1fce91..d64e8ecb6fb 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -1011,7 +1011,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path)  		break;  	case TOMOYO_TYPE_RMDIR:  	case TOMOYO_TYPE_CHROOT: -	case TOMOYO_TYPE_UMOUNT:  		tomoyo_add_slash(&buf);  		break;  	} diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 297612669c7..42a7b1ba8cb 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c @@ -75,6 +75,7 @@ void *tomoyo_commit_ok(void *data, const unsigned int size)  		memset(data, 0, size);  		return ptr;  	} +	kfree(ptr);  	return NULL;  } diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 82bf8c2390b..162a864dba2 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -143,6 +143,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,  			goto out;  		}  		requested_dev_name = tomoyo_realpath_from_path(&path); +		path_put(&path);  		if (!requested_dev_name) {  			error = -ENOENT;  			goto out; diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 9bfc1ee8222..6d5393204d9 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -390,7 +390,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname)  		if (!cp)  			break;  		if (*domainname != '/' || -		    !tomoyo_correct_word2(domainname, cp - domainname - 1)) +		    !tomoyo_correct_word2(domainname, cp - domainname))  			goto out;  		domainname = cp + 1;  	}  |