diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 12:49:56 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 12:49:56 -0800 |
commit | c9341ee0af4df0af8b727873ef851227345defed (patch) | |
tree | 81a48ed068936afd58a1cb9b6cb65f6e16dcb343 /security/selinux/hooks.c | |
parent | 7a771ceac771d009f7203c40b256b0608d7ea2f8 (diff) | |
parent | 61841be6358c03e864ad4c386c9a102edbba9cb8 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris:
"Highlights:
- major AppArmor update: policy namespaces & lots of fixes
- add /sys/kernel/security/lsm node for easy detection of loaded LSMs
- SELinux cgroupfs labeling support
- SELinux context mounts on tmpfs, ramfs, devpts within user
namespaces
- improved TPM 2.0 support"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (117 commits)
tpm: declare tpm2_get_pcr_allocation() as static
tpm: Fix expected number of response bytes of TPM1.2 PCR Extend
tpm xen: drop unneeded chip variable
tpm: fix misspelled "facilitate" in module parameter description
tpm_tis: fix the error handling of init_tis()
KEYS: Use memzero_explicit() for secret data
KEYS: Fix an error code in request_master_key()
sign-file: fix build error in sign-file.c with libressl
selinux: allow changing labels for cgroupfs
selinux: fix off-by-one in setprocattr
tpm: silence an array overflow warning
tpm: fix the type of owned field in cap_t
tpm: add securityfs support for TPM 2.0 firmware event log
tpm: enhance read_log_of() to support Physical TPM event log
tpm: enhance TPM 2.0 PCR extend to support multiple banks
tpm: implement TPM 2.0 capability to get active PCR banks
tpm: fix RC value check in tpm2_seal_trusted
tpm_tis: fix iTPM probe via probe_itpm() function
tpm: Begin the process to deprecate user_read_timer
tpm: remove tpm_read_index and tpm_write_index from tpm.h
...
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 381 |
1 files changed, 189 insertions, 192 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d98550abe16d..9bc12bcddc2c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -210,16 +210,6 @@ static inline u32 task_sid(const struct task_struct *task) return sid; } -/* - * get the subjective security ID of the current task - */ -static inline u32 current_sid(void) -{ - const struct task_security_struct *tsec = current_security(); - - return tsec->sid; -} - /* Allocate and free functions for each kind of security blob. */ static int inode_alloc_security(struct inode *inode) @@ -490,8 +480,11 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) sbsec->behavior == SECURITY_FS_USE_NATIVE || /* Special handling. Genfs but also in-core setxattr handler */ !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "cgroup") || + !strcmp(sb->s_type->name, "cgroup2") || !strcmp(sb->s_type->name, "pstore") || !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "rootfs"); } @@ -833,10 +826,14 @@ static int selinux_set_mnt_opts(struct super_block *sb, } /* - * If this is a user namespace mount, no contexts are allowed - * on the command line and security labels must be ignored. + * If this is a user namespace mount and the filesystem type is not + * explicitly whitelisted, then no contexts are allowed on the command + * line and security labels must be ignored. */ - if (sb->s_user_ns != &init_user_ns) { + if (sb->s_user_ns != &init_user_ns && + strcmp(sb->s_type->name, "tmpfs") && + strcmp(sb->s_type->name, "ramfs") && + strcmp(sb->s_type->name, "devpts")) { if (context_sid || fscontext_sid || rootcontext_sid || defcontext_sid) { rc = -EACCES; @@ -1268,6 +1265,8 @@ static inline int default_protocol_dgram(int protocol) static inline u16 socket_type_to_security_class(int family, int type, int protocol) { + int extsockclass = selinux_policycap_extsockclass; + switch (family) { case PF_UNIX: switch (type) { @@ -1282,13 +1281,19 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc case PF_INET6: switch (type) { case SOCK_STREAM: + case SOCK_SEQPACKET: if (default_protocol_stream(protocol)) return SECCLASS_TCP_SOCKET; + else if (extsockclass && protocol == IPPROTO_SCTP) + return SECCLASS_SCTP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DGRAM: if (default_protocol_dgram(protocol)) return SECCLASS_UDP_SOCKET; + else if (extsockclass && (protocol == IPPROTO_ICMP || + protocol == IPPROTO_ICMPV6)) + return SECCLASS_ICMP_SOCKET; else return SECCLASS_RAWIP_SOCKET; case SOCK_DCCP: @@ -1342,6 +1347,66 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_APPLETALK_SOCKET; } + if (extsockclass) { + switch (family) { + case PF_AX25: + return SECCLASS_AX25_SOCKET; + case PF_IPX: + return SECCLASS_IPX_SOCKET; + case PF_NETROM: + return SECCLASS_NETROM_SOCKET; + case PF_ATMPVC: + return SECCLASS_ATMPVC_SOCKET; + case PF_X25: + return SECCLASS_X25_SOCKET; + case PF_ROSE: + return SECCLASS_ROSE_SOCKET; + case PF_DECnet: + return SECCLASS_DECNET_SOCKET; + case PF_ATMSVC: + return SECCLASS_ATMSVC_SOCKET; + case PF_RDS: + return SECCLASS_RDS_SOCKET; + case PF_IRDA: + return SECCLASS_IRDA_SOCKET; + case PF_PPPOX: + return SECCLASS_PPPOX_SOCKET; + case PF_LLC: + return SECCLASS_LLC_SOCKET; + case PF_CAN: + return SECCLASS_CAN_SOCKET; + case PF_TIPC: + return SECCLASS_TIPC_SOCKET; + case PF_BLUETOOTH: + return SECCLASS_BLUETOOTH_SOCKET; + case PF_IUCV: + return SECCLASS_IUCV_SOCKET; + case PF_RXRPC: + return SECCLASS_RXRPC_SOCKET; + case PF_ISDN: + return SECCLASS_ISDN_SOCKET; + case PF_PHONET: + return SECCLASS_PHONET_SOCKET; + case PF_IEEE802154: + return SECCLASS_IEEE802154_SOCKET; + case PF_CAIF: + return SECCLASS_CAIF_SOCKET; + case PF_ALG: + return SECCLASS_ALG_SOCKET; + case PF_NFC: + return SECCLASS_NFC_SOCKET; + case PF_VSOCK: + return SECCLASS_VSOCK_SOCKET; + case PF_KCM: + return SECCLASS_KCM_SOCKET; + case PF_QIPCRTR: + return SECCLASS_QIPCRTR_SOCKET; +#if PF_MAX > 43 +#error New address family defined, please update this function. +#endif + } + } + return SECCLASS_SOCKET; } @@ -1608,55 +1673,6 @@ static inline u32 signal_to_av(int sig) return perm; } -/* - * Check permission between a pair of credentials - * fork check, ptrace check, etc. - */ -static int cred_has_perm(const struct cred *actor, - const struct cred *target, - u32 perms) -{ - u32 asid = cred_sid(actor), tsid = cred_sid(target); - - return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL); -} - -/* - * Check permission between a pair of tasks, e.g. signal checks, - * fork check, ptrace check, etc. - * tsk1 is the actor and tsk2 is the target - * - this uses the default subjective creds of tsk1 - */ -static int task_has_perm(const struct task_struct *tsk1, - const struct task_struct *tsk2, - u32 perms) -{ - const struct task_security_struct *__tsec1, *__tsec2; - u32 sid1, sid2; - - rcu_read_lock(); - __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid; - __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid; - rcu_read_unlock(); - return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL); -} - -/* - * Check permission between current and another task, e.g. signal checks, - * fork check, ptrace check, etc. - * current is the actor and tsk2 is the target - * - this uses current's subjective creds - */ -static int current_has_perm(const struct task_struct *tsk, - u32 perms) -{ - u32 sid, tsid; - - sid = current_sid(); - tsid = task_sid(tsk); - return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL); -} - #if CAP_LAST_CAP > 63 #error Fix SELinux to handle capabilities > 63. #endif @@ -1698,16 +1714,6 @@ static int cred_has_capability(const struct cred *cred, return rc; } -/* Check whether a task is allowed to use a system operation. */ -static int task_has_system(struct task_struct *tsk, - u32 perms) -{ - u32 sid = task_sid(tsk); - - return avc_has_perm(sid, SECINITSID_KERNEL, - SECCLASS_SYSTEM, perms, NULL); -} - /* Check whether a task has a particular permission to an inode. The 'adp' parameter is optional and allows other audit data to be passed (e.g. the dentry). */ @@ -1879,15 +1885,6 @@ static int may_create(struct inode *dir, FILESYSTEM__ASSOCIATE, &ad); } -/* Check whether a task can create a key. */ -static int may_create_key(u32 ksid, - struct task_struct *ctx) -{ - u32 sid = task_sid(ctx); - - return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); -} - #define MAY_LINK 0 #define MAY_UNLINK 1 #define MAY_RMDIR 2 @@ -2143,24 +2140,26 @@ static int selinux_binder_transfer_file(struct task_struct *from, static int selinux_ptrace_access_check(struct task_struct *child, unsigned int mode) { - if (mode & PTRACE_MODE_READ) { - u32 sid = current_sid(); - u32 csid = task_sid(child); + u32 sid = current_sid(); + u32 csid = task_sid(child); + + if (mode & PTRACE_MODE_READ) return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); - } - return current_has_perm(child, PROCESS__PTRACE); + return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); } static int selinux_ptrace_traceme(struct task_struct *parent) { - return task_has_perm(parent, current, PROCESS__PTRACE); + return avc_has_perm(task_sid(parent), current_sid(), SECCLASS_PROCESS, + PROCESS__PTRACE, NULL); } static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - return current_has_perm(target, PROCESS__GETCAP); + return avc_has_perm(current_sid(), task_sid(target), SECCLASS_PROCESS, + PROCESS__GETCAP, NULL); } static int selinux_capset(struct cred *new, const struct cred *old, @@ -2168,7 +2167,8 @@ static int selinux_capset(struct cred *new, const struct cred *old, const kernel_cap_t *inheritable, const kernel_cap_t *permitted) { - return cred_has_perm(old, new, PROCESS__SETCAP); + return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS, + PROCESS__SETCAP, NULL); } /* @@ -2224,29 +2224,22 @@ static int selinux_quota_on(struct dentry *dentry) static int selinux_syslog(int type) { - int rc; - switch (type) { case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ - rc = task_has_system(current, SYSTEM__SYSLOG_READ); - break; + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL); case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ /* Set level of messages printed to console */ case SYSLOG_ACTION_CONSOLE_LEVEL: - rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); - break; - case SYSLOG_ACTION_CLOSE: /* Close log */ - case SYSLOG_ACTION_OPEN: /* Open log */ - case SYSLOG_ACTION_READ: /* Read from log */ - case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */ - case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */ - default: - rc = task_has_system(current, SYSTEM__SYSLOG_MOD); - break; + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, + NULL); } - return rc; + /* All other syslog types */ + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL); } /* @@ -2271,13 +2264,13 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) /* binprm security operations */ -static u32 ptrace_parent_sid(struct task_struct *task) +static u32 ptrace_parent_sid(void) { u32 sid = 0; struct task_struct *tracer; rcu_read_lock(); - tracer = ptrace_parent(task); + tracer = ptrace_parent(current); if (tracer) sid = task_sid(tracer); rcu_read_unlock(); @@ -2406,7 +2399,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) * changes its SID has the appropriate permit */ if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { - u32 ptsid = ptrace_parent_sid(current); + u32 ptsid = ptrace_parent_sid(); if (ptsid != 0) { rc = avc_has_perm(ptsid, new_tsec->sid, SECCLASS_PROCESS, @@ -3503,6 +3496,7 @@ static int default_noexec; static int file_map_prot_check(struct file *file, unsigned long prot, int shared) { const struct cred *cred = current_cred(); + u32 sid = cred_sid(cred); int rc = 0; if (default_noexec && @@ -3513,7 +3507,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared * private file mapping that will also be writable. * This has an additional check. */ - rc = cred_has_perm(cred, cred, PROCESS__EXECMEM); + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, + PROCESS__EXECMEM, NULL); if (rc) goto error; } @@ -3564,6 +3559,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, unsigned long prot) { const struct cred *cred = current_cred(); + u32 sid = cred_sid(cred); if (selinux_checkreqprot) prot = reqprot; @@ -3573,12 +3569,14 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, int rc = 0; if (vma->vm_start >= vma->vm_mm->start_brk && vma->vm_end <= vma->vm_mm->brk) { - rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, + PROCESS__EXECHEAP, NULL); } else if (!vma->vm_file && ((vma->vm_start <= vma->vm_mm->start_stack && vma->vm_end >= vma->vm_mm->start_stack) || vma_is_stack_for_current(vma))) { - rc = current_has_perm(current, PROCESS__EXECSTACK); + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, + PROCESS__EXECSTACK, NULL); } else if (vma->vm_file && vma->anon_vma) { /* * We are making executable a file mapping that has @@ -3711,7 +3709,9 @@ static int selinux_file_open(struct file *file, const struct cred *cred) static int selinux_task_create(unsigned long clone_flags) { - return current_has_perm(current, PROCESS__FORK); + u32 sid = current_sid(); + + return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); } /* @@ -3821,15 +3821,12 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) static int selinux_kernel_module_request(char *kmod_name) { - u32 sid; struct common_audit_data ad; - sid = task_sid(current); - ad.type = LSM_AUDIT_DATA_KMOD; ad.u.kmod_name = kmod_name; - return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, &ad); } @@ -3881,17 +3878,20 @@ static int selinux_kernel_read_file(struct file *file, static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) { - return current_has_perm(p, PROCESS__SETPGID); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETPGID, NULL); } static int selinux_task_getpgid(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETPGID); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETPGID, NULL); } static int selinux_task_getsid(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETSESSION); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETSESSION, NULL); } static void selinux_task_getsecid(struct task_struct *p, u32 *secid) @@ -3901,17 +3901,20 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid) static int selinux_task_setnice(struct task_struct *p, int nice) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_setioprio(struct task_struct *p, int ioprio) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_getioprio(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETSCHED, NULL); } static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, @@ -3924,47 +3927,42 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, later be used as a safe reset point for the soft limit upon context transitions. See selinux_bprm_committing_creds. */ if (old_rlim->rlim_max != new_rlim->rlim_max) - return current_has_perm(p, PROCESS__SETRLIMIT); + return avc_has_perm(current_sid(), task_sid(p), + SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL); return 0; } static int selinux_task_setscheduler(struct task_struct *p) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_getscheduler(struct task_struct *p) { - return current_has_perm(p, PROCESS__GETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__GETSCHED, NULL); } static int selinux_task_movememory(struct task_struct *p) { - return current_has_perm(p, PROCESS__SETSCHED); + return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, + PROCESS__SETSCHED, NULL); } static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid) { u32 perm; - int rc; if (!sig) perm = PROCESS__SIGNULL; /* null signal; existence test */ else perm = signal_to_av(sig); - if (secid) - rc = avc_has_perm(secid, task_sid(p), - SECCLASS_PROCESS, perm, NULL); - else - rc = current_has_perm(p, perm); - return rc; -} - -static int selinux_task_wait(struct task_struct *p) -{ - return task_has_perm(p, current, PROCESS__SIGCHLD); + if (!secid) + secid = current_sid(); + return avc_has_perm(secid, task_sid(p), SECCLASS_PROCESS, perm, NULL); } static void selinux_task_to_inode(struct task_struct *p, @@ -4254,12 +4252,11 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec, socksid); } -static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) +static int sock_has_perm(struct sock *sk, u32 perms) { struct sk_security_struct *sksec = sk->sk_security; struct common_audit_data ad; struct lsm_network_audit net = {0,}; - u32 tsid = task_sid(task); if (sksec->sid == SECINITSID_KERNEL) return 0; @@ -4268,7 +4265,8 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) ad.u.net = &net; ad.u.net->sk = sk; - return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad); + return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms, + &ad); } static int selinux_socket_create(int family, int type, @@ -4330,7 +4328,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in u16 family; int err; - err = sock_has_perm(current, sk, SOCKET__BIND); + err = sock_has_perm(sk, SOCKET__BIND); if (err) goto out; @@ -4429,7 +4427,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, struct sk_security_struct *sksec = sk->sk_security; int err; - err = sock_has_perm(current, sk, SOCKET__CONNECT); + err = sock_has_perm(sk, SOCKET__CONNECT); if (err) return err; @@ -4481,7 +4479,7 @@ out: static int selinux_socket_listen(struct socket *sock, int backlog) { - return sock_has_perm(current, sock->sk, SOCKET__LISTEN); + return sock_has_perm(sock->sk, SOCKET__LISTEN); } static int selinux_socket_accept(struct socket *sock, struct socket *newsock) @@ -4492,7 +4490,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) u16 sclass; u32 sid; - err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT); + err = sock_has_perm(sock->sk, SOCKET__ACCEPT); if (err) return err; @@ -4513,30 +4511,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { - return sock_has_perm(current, sock->sk, SOCKET__WRITE); + return sock_has_perm(sock->sk, SOCKET__WRITE); } static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) { - return sock_has_perm(current, sock->sk, SOCKET__READ); + return sock_has_perm(sock->sk, SOCKET__READ); } static int selinux_socket_getsockname(struct socket *sock) { - return sock_has_perm(current, sock->sk, SOCKET__GETATTR); + return sock_has_perm(sock->sk, SOCKET__GETATTR); } static int selinux_socket_getpeername(struct socket *sock) { - return sock_has_perm(current, sock->sk, SOCKET__GETATTR); + return sock_has_perm(sock->sk, SOCKET__GETATTR); } static int selinux_socket_setsockopt(struct socket *sock, int level, int optname) { int err; - err = sock_has_perm(current, sock->sk, SOCKET__SETOPT); + err = sock_has_perm(sock->sk, SOCKET__SETOPT); if (err) return err; @@ -4546,12 +4544,12 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname static int selinux_socket_getsockopt(struct socket *sock, int level, int optname) { - return sock_has_perm(current, sock->sk, SOCKET__GETOPT); + return sock_has_perm(sock->sk, SOCKET__GETOPT); } static int selinux_socket_shutdown(struct socket *sock, int how) { - return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN); + return sock_has_perm(sock->sk, SOCKET__SHUTDOWN); } static int selinux_socket_unix_stream_connect(struct sock *sock, @@ -5039,7 +5037,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) goto out; } - err = sock_has_perm(current, sk, perm); + err = sock_has_perm(sk, perm); out: return err; } @@ -5370,20 +5368,17 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) return selinux_nlmsg_perm(sk, skb); } -static int ipc_alloc_security(struct task_struct *task, - struct kern_ipc_perm *perm, +static int ipc_alloc_security(struct kern_ipc_perm *perm, u16 sclass) { struct ipc_security_struct *isec; - u32 sid; isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); if (!isec) return -ENOMEM; - sid = task_sid(task); isec->sclass = sclass; - isec->sid = sid; + isec->sid = current_sid(); perm->security = isec; return 0; @@ -5451,7 +5446,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) u32 sid = current_sid(); int rc; - rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ); + rc = ipc_alloc_security(&msq->q_perm, SECCLASS_MSGQ); if (rc) return rc; @@ -5498,7 +5493,8 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd) case IPC_INFO: case MSG_INFO: /* No specific object, just general system-wide information. */ - return task_has_system(current, SYSTEM__IPC_INFO); + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case MSG_STAT: perms = MSGQ__GETATTR | MSGQ__ASSOCIATE; @@ -5592,7 +5588,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) u32 sid = current_sid(); int rc; - rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM); + rc = ipc_alloc_security(&shp->shm_perm, SECCLASS_SHM); if (rc) return rc; @@ -5640,7 +5636,8 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd) case IPC_INFO: case SHM_INFO: /* No specific object, just general system-wide information. */ - return task_has_system(current, SYSTEM__IPC_INFO); + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case SHM_STAT: perms = SHM__GETATTR | SHM__ASSOCIATE; @@ -5684,7 +5681,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) u32 sid = current_sid(); int rc; - rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM); + rc = ipc_alloc_security(&sma->sem_perm, SECCLASS_SEM); if (rc) return rc; @@ -5732,7 +5729,8 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd) case IPC_INFO: case SEM_INFO: /* No specific object, just general system-wide information. */ - return task_has_system(current, SYSTEM__IPC_INFO); + return avc_has_perm(current_sid(), SECINITSID_KERNEL, + SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case GETPID: case GETNCNT: case GETZCNT: @@ -5813,15 +5811,16 @@ static int selinux_getprocattr(struct task_struct *p, int error; unsigned len; + rcu_read_lock(); + __tsec = __task_cred(p)->security; + if (current != p) { - error = current_has_perm(p, PROCESS__GETATTR); + error = avc_has_perm(current_sid(), __tsec->sid, + SECCLASS_PROCESS, PROCESS__GETATTR, NULL); if (error) - return error; + goto bad; } - rcu_read_lock(); - __tsec = __task_cred(p)->security; - if (!strcmp(name, "current")) sid = __tsec->sid; else if (!strcmp(name, "prev")) @@ -5834,8 +5833,10 @@ static int selinux_getprocattr(struct task_struct *p, sid = __tsec->keycreate_sid; else if (!strcmp(name, "sockcreate")) sid = __tsec->sockcreate_sid; - else - goto invalid; + else { + error = -EINVAL; + goto bad; + } rcu_read_unlock(); if (!sid) @@ -5846,41 +5847,37 @@ static int selinux_getprocattr(struct task_struct *p, return error; return len; -invalid: +bad: rcu_read_unlock(); - return -EINVAL; + return error; } -static int selinux_setprocattr(struct task_struct *p, - char *name, void *value, size_t size) +static int selinux_setprocattr(const char *name, void *value, size_t size) { struct task_security_struct *tsec; struct cred *new; - u32 sid = 0, ptsid; + u32 mysid = current_sid(), sid = 0, ptsid; int error; char *str = value; - if (current != p) { - /* SELinux only allows a process to change its own - security attributes. */ - return -EACCES; - } - /* * Basic control over ability to set these attributes at all. - * current == p, but we'll pass them separately in case the - * above restriction is ever removed. */ if (!strcmp(name, "exec")) - error = current_has_perm(p, PROCESS__SETEXEC); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETEXEC, NULL); else if (!strcmp(name, "fscreate")) - error = current_has_perm(p, PROCESS__SETFSCREATE); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETFSCREATE, NULL); else if (!strcmp(name, "keycreate")) - error = current_has_perm(p, PROCESS__SETKEYCREATE); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETKEYCREATE, NULL); else if (!strcmp(name, "sockcreate")) - error = current_has_perm(p, PROCESS__SETSOCKCREATE); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETSOCKCREATE, NULL); else if (!strcmp(name, "current")) - error = current_has_perm(p, PROCESS__SETCURRENT); + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, + PROCESS__SETCURRENT, NULL); else error = -EINVAL; if (error) @@ -5934,7 +5931,8 @@ static int selinux_setprocattr(struct task_struct *p, } else if (!strcmp(name, "fscreate")) { tsec->create_sid = sid; } else if (!strcmp(name, "keycreate")) { - error = may_create_key(sid, p); + error = avc_has_perm(mysid, sid, SECCLASS_KEY, KEY__CREATE, + NULL); if (error) goto abort_change; tsec->keycreate_sid = sid; @@ -5961,7 +5959,7 @@ static int selinux_setprocattr(struct task_struct *p, /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and fail. */ - ptsid = ptrace_parent_sid(p); + ptsid = ptrace_parent_sid(); if (ptsid != 0) { error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); @@ -6209,7 +6207,6 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler), LSM_HOOK_INIT(task_movememory, selinux_task_movememory), LSM_HOOK_INIT(task_kill, selinux_task_kill), - LSM_HOOK_INIT(task_wait, selinux_task_wait), LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode), LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission), @@ -6349,7 +6346,7 @@ static __init int selinux_init(void) 0, SLAB_PANIC, NULL); avc_init(); - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks)); + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) panic("SELinux: Unable to register AVC netcache callback\n"); |