summaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/hooks.c383
-rw-r--r--security/selinux/include/classmap.h64
-rw-r--r--security/selinux/include/objsec.h10
-rw-r--r--security/selinux/include/security.h3
-rw-r--r--security/selinux/selinuxfs.c98
-rw-r--r--security/selinux/ss/services.c3
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);
}