diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 383 | ||||
-rw-r--r-- | security/selinux/include/classmap.h | 64 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 10 | ||||
-rw-r--r-- | security/selinux/include/security.h | 3 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 98 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 3 |
6 files changed, 327 insertions, 234 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5eebce1af9a4..e6b1b7410321 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,68 @@ 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; + case PF_SMC: + return SECCLASS_SMC_SOCKET; +#if PF_MAX > 44 +#error New address family defined, please update this function. +#endif + } + } + return SECCLASS_SOCKET; } @@ -1608,55 +1675,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 +1716,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 +1887,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 +2142,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 +2169,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 +2226,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 +2266,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 +2401,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 +3498,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 +3509,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 +3561,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 +3571,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 +3711,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 +3823,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 +3880,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 +3903,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 +3929,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 +4254,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 +4267,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 +4330,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; @@ -4430,7 +4430,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; @@ -4482,7 +4482,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) @@ -4493,7 +4493,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; @@ -4514,30 +4514,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; @@ -4547,12 +4547,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, @@ -5040,7 +5040,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; } @@ -5371,20 +5371,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; @@ -5452,7 +5449,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; @@ -5499,7 +5496,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; @@ -5593,7 +5591,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; @@ -5641,7 +5639,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; @@ -5685,7 +5684,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; @@ -5733,7 +5732,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: @@ -5814,15 +5814,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")) @@ -5835,8 +5836,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) @@ -5847,41 +5850,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) @@ -5935,7 +5934,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; @@ -5962,7 +5962,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); @@ -6210,7 +6210,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), @@ -6350,7 +6349,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"); diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 13ae49b0baa0..d429c4a1c551 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -171,5 +171,69 @@ struct security_class_mapping secclass_map[] = { { COMMON_CAP_PERMS, NULL } }, { "cap2_userns", { COMMON_CAP2_PERMS, NULL } }, + { "sctp_socket", + { COMMON_SOCK_PERMS, + "node_bind", NULL } }, + { "icmp_socket", + { COMMON_SOCK_PERMS, + "node_bind", NULL } }, + { "ax25_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "ipx_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "netrom_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "atmpvc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "x25_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "rose_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "decnet_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "atmsvc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "rds_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "irda_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "pppox_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "llc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "can_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "tipc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "bluetooth_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "iucv_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "rxrpc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "isdn_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "phonet_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "ieee802154_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "caif_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "alg_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "nfc_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "vsock_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "kcm_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "qipcrtr_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "smc_socket", + { COMMON_SOCK_PERMS, NULL } }, { NULL } }; + +#if PF_MAX > 44 +#error New address family defined, please update secclass_map. +#endif diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index e8dab0f02c72..c03cdcd12a3b 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -37,6 +37,16 @@ struct task_security_struct { u32 sockcreate_sid; /* fscreate 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; +} + enum label_initialized { LABEL_INVALID, /* invalid or not initialized */ LABEL_INITIALIZED, /* initialized */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 308a286c6cbe..beaa14b8b6cf 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -69,7 +69,7 @@ extern int selinux_enabled; enum { POLICYDB_CAPABILITY_NETPEER, POLICYDB_CAPABILITY_OPENPERM, - POLICYDB_CAPABILITY_REDHAT1, + POLICYDB_CAPABILITY_EXTSOCKCLASS, POLICYDB_CAPABILITY_ALWAYSNETWORK, __POLICYDB_CAPABILITY_MAX }; @@ -77,6 +77,7 @@ enum { extern int selinux_policycap_netpeer; extern int selinux_policycap_openperm; +extern int selinux_policycap_extsockclass; extern int selinux_policycap_alwaysnetwork; /* diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index cf9293e01fc1..c354807381c1 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -45,7 +45,7 @@ static char *policycap_names[] = { "network_peer_controls", "open_perms", - "redhat1", + "extended_socket_class", "always_check_network" }; @@ -77,25 +77,6 @@ static char policy_opened; /* global data for policy capabilities */ static struct dentry *policycap_dir; -/* Check whether a task is allowed to use a security operation. */ -static int task_has_security(struct task_struct *tsk, - u32 perms) -{ - const struct task_security_struct *tsec; - u32 sid = 0; - - rcu_read_lock(); - tsec = __task_cred(tsk)->security; - if (tsec) - sid = tsec->sid; - rcu_read_unlock(); - if (!tsec) - return -EACCES; - - return avc_has_perm(sid, SECINITSID_SECURITY, - SECCLASS_SECURITY, perms, NULL); -} - enum sel_inos { SEL_ROOT_INO = 2, SEL_LOAD, /* load policy */ @@ -166,7 +147,9 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, new_value = !!new_value; if (new_value != selinux_enforcing) { - length = task_has_security(current, SECURITY__SETENFORCE); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETENFORCE, + NULL); if (length) goto out; audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, @@ -368,7 +351,8 @@ static int sel_open_policy(struct inode *inode, struct file *filp) mutex_lock(&sel_mutex); - rc = task_has_security(current, SECURITY__READ_POLICY); + rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); if (rc) goto err; @@ -429,7 +413,8 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf, mutex_lock(&sel_mutex); - ret = task_has_security(current, SECURITY__READ_POLICY); + ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); if (ret) goto out; @@ -499,7 +484,8 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, mutex_lock(&sel_mutex); - length = task_has_security(current, SECURITY__LOAD_POLICY); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL); if (length) goto out; @@ -522,20 +508,28 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, goto out; length = security_load_policy(data, count); - if (length) + if (length) { + pr_warn_ratelimited("SELinux: failed to load policy\n"); goto out; + } length = sel_make_bools(); - if (length) + if (length) { + pr_err("SELinux: failed to load policy booleans\n"); goto out1; + } length = sel_make_classes(); - if (length) + if (length) { + pr_err("SELinux: failed to load policy classes\n"); goto out1; + } length = sel_make_policycap(); - if (length) + if (length) { + pr_err("SELinux: failed to load policy capabilities\n"); goto out1; + } length = count; @@ -561,7 +555,8 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size) u32 sid, len; ssize_t length; - length = task_has_security(current, SECURITY__CHECK_CONTEXT); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL); if (length) goto out; @@ -604,7 +599,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, ssize_t length; unsigned int new_value; - length = task_has_security(current, SECURITY__SETCHECKREQPROT); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT, + NULL); if (length) return length; @@ -645,7 +642,8 @@ static ssize_t sel_write_validatetrans(struct file *file, u16 tclass; int rc; - rc = task_has_security(current, SECURITY__VALIDATE_TRANS); + rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL); if (rc) goto out; @@ -772,7 +770,8 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) struct av_decision avd; ssize_t length; - length = task_has_security(current, SECURITY__COMPUTE_AV); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL); if (length) goto out; @@ -822,7 +821,9 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) u32 len; int nargs; - length = task_has_security(current, SECURITY__COMPUTE_CREATE); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, + NULL); if (length) goto out; @@ -919,7 +920,9 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) char *newcon = NULL; u32 len; - length = task_has_security(current, SECURITY__COMPUTE_RELABEL); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, + NULL); if (length) goto out; @@ -975,7 +978,9 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) int i, rc; u32 len, nsids; - length = task_has_security(current, SECURITY__COMPUTE_USER); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_USER, + NULL); if (length) goto out; @@ -1035,7 +1040,9 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) char *newcon = NULL; u32 len; - length = task_has_security(current, SECURITY__COMPUTE_MEMBER); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, + NULL); if (length) goto out; @@ -1142,7 +1149,9 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, mutex_lock(&sel_mutex); - length = task_has_security(current, SECURITY__SETBOOL); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETBOOL, + NULL); if (length) goto out; @@ -1198,7 +1207,9 @@ static ssize_t sel_commit_bools_write(struct file *filep, mutex_lock(&sel_mutex); - length = task_has_security(current, SECURITY__SETBOOL); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETBOOL, + NULL); if (length) goto out; @@ -1299,8 +1310,11 @@ static int sel_make_bools(void) isec = (struct inode_security_struct *)inode->i_security; ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); - if (ret) - goto out; + if (ret) { + pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n", + page); + sid = SECINITSID_SECURITY; + } isec->sid = sid; isec->initialized = LABEL_INITIALIZED; @@ -1351,7 +1365,9 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, ssize_t ret; unsigned int new_value; - ret = task_has_security(current, SECURITY__SETSECPARAM); + ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, + SECCLASS_SECURITY, SECURITY__SETSECPARAM, + NULL); if (ret) return ret; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 082b20c78363..a70fcee9824b 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -72,6 +72,7 @@ int selinux_policycap_netpeer; int selinux_policycap_openperm; +int selinux_policycap_extsockclass; int selinux_policycap_alwaysnetwork; static DEFINE_RWLOCK(policy_rwlock); @@ -1988,6 +1989,8 @@ static void security_load_policycaps(void) POLICYDB_CAPABILITY_NETPEER); selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_OPENPERM); + selinux_policycap_extsockclass = ebitmap_get_bit(&policydb.policycaps, + POLICYDB_CAPABILITY_EXTSOCKCLASS); selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_ALWAYSNETWORK); } |