diff options
author | James Morris <james.l.morris@oracle.com> | 2012-08-17 12:42:30 +0200 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2012-08-17 12:42:30 +0200 |
commit | 51b743fe87d7fb3dba7a2ff4a1fe23bb65dc2245 (patch) | |
tree | f8b8f601713a3ecb264eb9f145636343d9350520 /security | |
parent | ptrace: mark __ptrace_may_access() static (diff) | |
parent | Linux 3.6-rc2 (diff) | |
download | linux-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.h | 2 | ||||
-rw-r--r-- | security/keys/keyctl.c | 26 | ||||
-rw-r--r-- | security/keys/process_keys.c | 5 | ||||
-rw-r--r-- | security/selinux/avc.c | 2 | ||||
-rw-r--r-- | security/selinux/hooks.c | 33 | ||||
-rw-r--r-- | security/selinux/include/classmap.h | 4 | ||||
-rw-r--r-- | security/selinux/include/security.h | 2 | ||||
-rw-r--r-- | security/selinux/netlink.c | 17 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 6 | ||||
-rw-r--r-- | security/smack/smackfs.c | 8 | ||||
-rw-r--r-- | security/yama/yama_lsm.c | 41 |
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, }; |