summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2012-08-17 12:42:30 +0200
committerJames Morris <james.l.morris@oracle.com>2012-08-17 12:42:30 +0200
commit51b743fe87d7fb3dba7a2ff4a1fe23bb65dc2245 (patch)
treef8b8f601713a3ecb264eb9f145636343d9350520 /security
parentptrace: mark __ptrace_may_access() static (diff)
parentLinux 3.6-rc2 (diff)
downloadlinux-51b743fe87d7fb3dba7a2ff4a1fe23bb65dc2245.tar.xz
linux-51b743fe87d7fb3dba7a2ff4a1fe23bb65dc2245.zip
Merge tag 'v3.6-rc2' into next
Linux 3.6-rc2 Resync with Linus.
Diffstat (limited to 'security')
-rw-r--r--security/keys/internal.h2
-rw-r--r--security/keys/keyctl.c26
-rw-r--r--security/keys/process_keys.c5
-rw-r--r--security/selinux/avc.c2
-rw-r--r--security/selinux/hooks.c33
-rw-r--r--security/selinux/include/classmap.h4
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/netlink.c17
-rw-r--r--security/selinux/selinuxfs.c6
-rw-r--r--security/smack/smackfs.c8
-rw-r--r--security/yama/yama_lsm.c41
11 files changed, 97 insertions, 49 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h
index c990b8c8ef1d..22ff05269e3d 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -149,7 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
#define KEY_LOOKUP_FOR_UNLINK 0x04
extern long join_session_keyring(const char *name);
-extern void key_change_session_keyring(struct task_work *twork);
+extern void key_change_session_keyring(struct callback_head *twork);
extern struct work_struct key_gc_work;
extern unsigned key_gc_delay;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 3bdc419b272f..3364fbf46807 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1456,7 +1456,7 @@ long keyctl_session_to_parent(void)
{
struct task_struct *me, *parent;
const struct cred *mycred, *pcred;
- struct task_work *newwork, *oldwork;
+ struct callback_head *newwork, *oldwork;
key_ref_t keyring_r;
struct cred *cred;
int ret;
@@ -1466,19 +1466,17 @@ long keyctl_session_to_parent(void)
return PTR_ERR(keyring_r);
ret = -ENOMEM;
- newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
- if (!newwork)
- goto error_keyring;
/* our parent is going to need a new cred struct, a new tgcred struct
* and new security data, so we allocate them here to prevent ENOMEM in
* our parent */
cred = cred_alloc_blank();
if (!cred)
- goto error_newwork;
+ goto error_keyring;
+ newwork = &cred->rcu;
cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
- init_task_work(newwork, key_change_session_keyring, cred);
+ init_task_work(newwork, key_change_session_keyring);
me = current;
rcu_read_lock();
@@ -1488,6 +1486,7 @@ long keyctl_session_to_parent(void)
oldwork = NULL;
parent = me->real_parent;
+ task_lock(parent);
/* the parent mustn't be init and mustn't be a kernel thread */
if (parent->pid <= 1 || !parent->mm)
goto unlock;
@@ -1531,20 +1530,15 @@ long keyctl_session_to_parent(void)
if (!ret)
newwork = NULL;
unlock:
+ task_unlock(parent);
write_unlock_irq(&tasklist_lock);
rcu_read_unlock();
- if (oldwork) {
- put_cred(oldwork->data);
- kfree(oldwork);
- }
- if (newwork) {
- put_cred(newwork->data);
- kfree(newwork);
- }
+ if (oldwork)
+ put_cred(container_of(oldwork, struct cred, rcu));
+ if (newwork)
+ put_cred(cred);
return ret;
-error_newwork:
- kfree(newwork);
error_keyring:
key_ref_put(keyring_r);
return ret;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 4ad54eea1ea4..54339cfd6734 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -834,12 +834,11 @@ error:
* Replace a process's session keyring on behalf of one of its children when
* the target process is about to resume userspace execution.
*/
-void key_change_session_keyring(struct task_work *twork)
+void key_change_session_keyring(struct callback_head *twork)
{
const struct cred *old = current_cred();
- struct cred *new = twork->data;
+ struct cred *new = container_of(twork, struct cred, rcu);
- kfree(twork);
if (unlikely(current->flags & PF_EXITING)) {
put_cred(new);
return;
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 68d82daed257..4d3fab47e643 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -274,7 +274,7 @@ static struct avc_node *avc_alloc_node(void)
{
struct avc_node *node;
- node = kmem_cache_zalloc(avc_node_cachep, GFP_ATOMIC);
+ node = kmem_cache_zalloc(avc_node_cachep, GFP_ATOMIC|__GFP_NOMEMALLOC);
if (!node)
goto out;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 372ec6502aa8..6c77f63c7591 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2129,7 +2129,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
int fd;
j++;
- i = j * __NFDBITS;
+ i = j * BITS_PER_LONG;
fdt = files_fdtable(files);
if (i >= fdt->max_fds)
break;
@@ -2157,8 +2157,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
get_file(devnull);
} else {
devnull = dentry_open(
- dget(selinux_null),
- mntget(selinuxfs_mount),
+ &selinux_null,
O_RDWR, cred);
if (IS_ERR(devnull)) {
devnull = NULL;
@@ -2717,7 +2716,7 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, dentry, FILE__SETATTR);
- if (ia_valid & ATTR_SIZE)
+ if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE))
av |= FILE__OPEN;
return dentry_has_perm(cred, dentry, av);
@@ -2792,11 +2791,16 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
/* We strip a nul only if it is at the end, otherwise the
* context contains a nul and we should audit that */
- str = value;
- if (str[size - 1] == '\0')
- audit_size = size - 1;
- else
- audit_size = size;
+ if (value) {
+ str = value;
+ if (str[size - 1] == '\0')
+ audit_size = size - 1;
+ else
+ audit_size = size;
+ } else {
+ str = "";
+ audit_size = 0;
+ }
ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
audit_log_format(ab, "op=setxattr invalid_context=");
audit_log_n_untrustedstring(ab, value, audit_size);
@@ -3181,6 +3185,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
case F_GETFL:
case F_GETOWN:
case F_GETSIG:
+ case F_GETOWNER_UIDS:
/* Just check FD__USE permission */
err = file_has_perm(cred, file, 0);
break;
@@ -5763,21 +5768,21 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
{
.hook = selinux_ipv4_postroute,
.owner = THIS_MODULE,
- .pf = PF_INET,
+ .pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_SELINUX_LAST,
},
{
.hook = selinux_ipv4_forward,
.owner = THIS_MODULE,
- .pf = PF_INET,
+ .pf = NFPROTO_IPV4,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_SELINUX_FIRST,
},
{
.hook = selinux_ipv4_output,
.owner = THIS_MODULE,
- .pf = PF_INET,
+ .pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_SELINUX_FIRST,
}
@@ -5789,14 +5794,14 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
{
.hook = selinux_ipv6_postroute,
.owner = THIS_MODULE,
- .pf = PF_INET6,
+ .pf = NFPROTO_IPV6,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP6_PRI_SELINUX_LAST,
},
{
.hook = selinux_ipv6_forward,
.owner = THIS_MODULE,
- .pf = PF_INET6,
+ .pf = NFPROTO_IPV6,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP6_PRI_SELINUX_FIRST,
}
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index b8c53723e09b..df2de54a958d 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -145,7 +145,9 @@ struct security_class_mapping secclass_map[] = {
"node_bind", "name_connect", NULL } },
{ "memprotect", { "mmap_zero", NULL } },
{ "peer", { "recv", NULL } },
- { "capability2", { "mac_override", "mac_admin", "syslog", NULL } },
+ { "capability2",
+ { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend",
+ NULL } },
{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
{ "tun_socket",
{ COMMON_SOCK_PERMS, NULL } },
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index dde2005407aa..6d3885165d14 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -221,7 +221,7 @@ extern void selinux_status_update_policyload(int seqno);
extern void selinux_complete_init(void);
extern int selinux_disable(void);
extern void exit_sel_fs(void);
-extern struct dentry *selinux_null;
+extern struct path selinux_null;
extern struct vfsmount *selinuxfs_mount;
extern void selnl_notify_setenforce(int val);
extern void selnl_notify_policyload(u32 seqno);
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 161e01a6c7ef..8a77725423e0 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -19,6 +19,7 @@
#include <linux/netlink.h>
#include <linux/selinux_netlink.h>
#include <net/net_namespace.h>
+#include <net/netlink.h>
#include "security.h"
@@ -47,7 +48,7 @@ static void selnl_add_payload(struct nlmsghdr *nlh, int len, int msgtype, void *
{
switch (msgtype) {
case SELNL_MSG_SETENFORCE: {
- struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
+ struct selnl_msg_setenforce *msg = nlmsg_data(nlh);
memset(msg, 0, len);
msg->val = *((int *)data);
@@ -55,7 +56,7 @@ static void selnl_add_payload(struct nlmsghdr *nlh, int len, int msgtype, void *
}
case SELNL_MSG_POLICYLOAD: {
- struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
+ struct selnl_msg_policyload *msg = nlmsg_data(nlh);
memset(msg, 0, len);
msg->seqno = *((u32 *)data);
@@ -81,7 +82,9 @@ static void selnl_notify(int msgtype, void *data)
goto oom;
tmp = skb->tail;
- nlh = NLMSG_PUT(skb, 0, 0, msgtype, len);
+ nlh = nlmsg_put(skb, 0, 0, msgtype, len, 0);
+ if (!nlh)
+ goto out_kfree_skb;
selnl_add_payload(nlh, len, msgtype, data);
nlh->nlmsg_len = skb->tail - tmp;
NETLINK_CB(skb).dst_group = SELNLGRP_AVC;
@@ -89,7 +92,7 @@ static void selnl_notify(int msgtype, void *data)
out:
return;
-nlmsg_failure:
+out_kfree_skb:
kfree_skb(skb);
oom:
printk(KERN_ERR "SELinux: OOM in %s\n", __func__);
@@ -108,8 +111,12 @@ void selnl_notify_policyload(u32 seqno)
static int __init selnl_init(void)
{
+ struct netlink_kernel_cfg cfg = {
+ .groups = SELNLGRP_MAX,
+ };
+
selnl = netlink_kernel_create(&init_net, NETLINK_SELINUX,
- SELNLGRP_MAX, NULL, NULL, THIS_MODULE);
+ THIS_MODULE, &cfg);
if (selnl == NULL)
panic("SELinux: Cannot create netlink socket.");
netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 3ad290251288..298e695d6822 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1297,7 +1297,7 @@ out:
#define NULL_FILE_NAME "null"
-struct dentry *selinux_null;
+struct path selinux_null;
static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
@@ -1838,7 +1838,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
d_add(dentry, inode);
- selinux_null = dentry;
+ selinux_null.dentry = dentry;
dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino);
if (IS_ERR(dentry)) {
@@ -1912,7 +1912,7 @@ static int __init init_sel_fs(void)
return err;
}
- selinuxfs_mount = kern_mount(&sel_fs_type);
+ selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
if (IS_ERR(selinuxfs_mount)) {
printk(KERN_ERR "selinuxfs: could not mount!\n");
err = PTR_ERR(selinuxfs_mount);
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index d31e6d957c21..b1b768e4049a 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -323,11 +323,11 @@ static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
int datalen;
int rc = -1;
- /*
- * This is probably inefficient, but safe.
- */
+ /* This is inefficient */
datalen = strlen(data);
- subject = kzalloc(datalen, GFP_KERNEL);
+
+ /* Our first element can be 64 + \0 with no spaces */
+ subject = kzalloc(datalen + 1, GFP_KERNEL);
if (subject == NULL)
return -1;
object = kzalloc(datalen, GFP_KERNEL);
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 83554ee8a587..d51b7c76c37d 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -290,10 +290,51 @@ static int yama_ptrace_access_check(struct task_struct *child,
return rc;
}
+/**
+ * yama_ptrace_traceme - validate PTRACE_TRACEME calls
+ * @parent: task that will become the ptracer of the current task
+ *
+ * Returns 0 if following the ptrace is allowed, -ve on error.
+ */
+static int yama_ptrace_traceme(struct task_struct *parent)
+{
+ int rc;
+
+ /* If standard caps disallows it, so does Yama. We should
+ * only tighten restrictions further.
+ */
+ rc = cap_ptrace_traceme(parent);
+ if (rc)
+ return rc;
+
+ /* Only disallow PTRACE_TRACEME on more aggressive settings. */
+ switch (ptrace_scope) {
+ case YAMA_SCOPE_CAPABILITY:
+ if (!ns_capable(task_user_ns(parent), CAP_SYS_PTRACE))
+ rc = -EPERM;
+ break;
+ case YAMA_SCOPE_NO_ATTACH:
+ rc = -EPERM;
+ break;
+ }
+
+ if (rc) {
+ char name[sizeof(current->comm)];
+ printk_ratelimited(KERN_NOTICE
+ "ptraceme of pid %d was attempted by: %s (pid %d)\n",
+ current->pid,
+ get_task_comm(name, parent),
+ parent->pid);
+ }
+
+ return rc;
+}
+
static struct security_operations yama_ops = {
.name = "yama",
.ptrace_access_check = yama_ptrace_access_check,
+ .ptrace_traceme = yama_ptrace_traceme,
.task_prctl = yama_task_prctl,
.task_free = yama_task_free,
};