summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Morris <jmorris@namei.org>2011-05-24 22:55:24 +1000
committerJames Morris <jmorris@namei.org>2011-05-24 22:55:24 +1000
commit434d42cfd05a7cc452457a81d2029540cba12150 (patch)
tree3a6b9b7f9ff2e1b7409dd66c15242b2a75aa4422
parentd762f4383100c2a87b1a3f2d678cd3b5425655b4 (diff)
parent12a5a2621b1ee14d32beca35304d7c6076a58815 (diff)
downloadlinux-434d42cfd05a7cc452457a81d2029540cba12150.tar.gz
linux-434d42cfd05a7cc452457a81d2029540cba12150.tar.bz2
linux-434d42cfd05a7cc452457a81d2029540cba12150.zip
Merge branch 'next' into for-linus
-rw-r--r--fs/binfmt_flat.c8
-rw-r--r--include/linux/capability.h5
-rw-r--r--include/linux/init_task.h7
-rw-r--r--include/linux/key.h13
-rw-r--r--include/linux/kmod.h3
-rw-r--r--kernel/capability.c4
-rw-r--r--kernel/cred.c6
-rw-r--r--kernel/kmod.c100
-rw-r--r--kernel/sysctl.c6
-rw-r--r--net/dns_resolver/dns_key.c10
-rw-r--r--security/Kconfig1
-rw-r--r--security/commoncap.c13
-rw-r--r--security/keys/internal.h4
-rw-r--r--security/keys/keyctl.c6
-rw-r--r--security/keys/keyring.c37
-rw-r--r--security/keys/proc.c2
-rw-r--r--security/keys/process_keys.c12
-rw-r--r--security/keys/request_key.c3
-rw-r--r--security/keys/request_key_auth.c3
-rw-r--r--security/keys/user_defined.c4
-rw-r--r--security/tomoyo/common.c17
-rw-r--r--security/tomoyo/file.c1
-rw-r--r--security/tomoyo/memory.c1
-rw-r--r--security/tomoyo/mount.c1
-rw-r--r--security/tomoyo/util.c2
25 files changed, 205 insertions, 64 deletions
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 397d3057d336..1bffbe0ed778 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 4554db0cde86..c42112350003 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 689496bb6654..bafc58c00fc3 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 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)))
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 310231823852..d4a5c84c503d 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 32a80e08ff4b..283c529f8b1c 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 8093c16b84b1..e12c8af793f8 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 5ae0ff38425f..ad6a81c58b44 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(&current->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 3dd0c46fa3bb..4bffd62c2f13 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 cfa7a5e1c5c9..fa000d26dc60 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 95accd442d55..e0f08b52e4ab 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 f20e984ccfb4..a93b3b733079 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 07a025f81902..f375152a2500 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 427fddcaeb19..eca51918c951 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 cdd2f3f88c88..a06ffab38568 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 525cf8a29cdd..49bbc97943ad 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 930634e45149..6c0480db8885 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 df3c0417ee40..b18a71745901 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 68164031a74e..f6337c9082eb 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 f66baf44f32d..5b366d7af3c4 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 7556315c1978..a0d09e56874b 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 cb09f1fce910..d64e8ecb6fb3 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 297612669c74..42a7b1ba8cbf 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 82bf8c2390bc..162a864dba24 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 9bfc1ee8222d..6d5393204d95 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;
}