summaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c78
1 files changed, 48 insertions, 30 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0b4e32161b77..7e954b555be6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2286,7 +2286,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
return -EACCES;
}
-static int selinux_bprm_set_creds(struct linux_binprm *bprm)
+static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
{
const struct task_security_struct *old_tsec;
struct task_security_struct *new_tsec;
@@ -2297,8 +2297,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
/* SELinux context only depends on initial program or script and not
* the script interpreter */
- if (bprm->called_set_creds)
- return 0;
old_tsec = selinux_cred(current_cred());
new_tsec = selinux_cred(bprm->cred);
@@ -5842,40 +5840,60 @@ static unsigned int selinux_ipv6_postroute(void *priv,
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- int err = 0;
- u32 perm;
+ int rc = 0;
+ unsigned int msg_len;
+ unsigned int data_len = skb->len;
+ unsigned char *data = skb->data;
struct nlmsghdr *nlh;
struct sk_security_struct *sksec = sk->sk_security;
+ u16 sclass = sksec->sclass;
+ u32 perm;
- if (skb->len < NLMSG_HDRLEN) {
- err = -EINVAL;
- goto out;
- }
- nlh = nlmsg_hdr(skb);
+ while (data_len >= nlmsg_total_size(0)) {
+ nlh = (struct nlmsghdr *)data;
+
+ /* NOTE: the nlmsg_len field isn't reliably set by some netlink
+ * users which means we can't reject skb's with bogus
+ * length fields; our solution is to follow what
+ * netlink_rcv_skb() does and simply skip processing at
+ * messages with length fields that are clearly junk
+ */
+ if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len)
+ return 0;
- err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
- if (err) {
- if (err == -EINVAL) {
+ rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm);
+ if (rc == 0) {
+ rc = sock_has_perm(sk, perm);
+ if (rc)
+ return rc;
+ } else if (rc == -EINVAL) {
+ /* -EINVAL is a missing msg/perm mapping */
pr_warn_ratelimited("SELinux: unrecognized netlink"
- " message: protocol=%hu nlmsg_type=%hu sclass=%s"
- " pid=%d comm=%s\n",
- sk->sk_protocol, nlh->nlmsg_type,
- secclass_map[sksec->sclass - 1].name,
- task_pid_nr(current), current->comm);
- if (!enforcing_enabled(&selinux_state) ||
- security_get_allow_unknown(&selinux_state))
- err = 0;
+ " message: protocol=%hu nlmsg_type=%hu sclass=%s"
+ " pid=%d comm=%s\n",
+ sk->sk_protocol, nlh->nlmsg_type,
+ secclass_map[sclass - 1].name,
+ task_pid_nr(current), current->comm);
+ if (enforcing_enabled(&selinux_state) &&
+ !security_get_allow_unknown(&selinux_state))
+ return rc;
+ rc = 0;
+ } else if (rc == -ENOENT) {
+ /* -ENOENT is a missing socket/class mapping, ignore */
+ rc = 0;
+ } else {
+ return rc;
}
- /* Ignore */
- if (err == -ENOENT)
- err = 0;
- goto out;
+ /* move to the next message after applying netlink padding */
+ msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (msg_len >= data_len)
+ return 0;
+ data_len -= msg_len;
+ data += msg_len;
}
- err = sock_has_perm(sk, perm);
-out:
- return err;
+ return rc;
}
static void ipc_init_security(struct ipc_security_struct *isec, u16 sclass)
@@ -6385,7 +6403,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
/* Permission checking based on the specified context is
performed during the actual operation (execve,
open/mkdir/...), when we know the full context of the
- operation. See selinux_bprm_set_creds for the execve
+ operation. See selinux_bprm_creds_for_exec for the execve
checks and may_create for the file creation checks. The
operation will then fail if the context is not permitted. */
tsec = selinux_cred(new);
@@ -6914,7 +6932,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(netlink_send, selinux_netlink_send),
- LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
+ LSM_HOOK_INIT(bprm_creds_for_exec, selinux_bprm_creds_for_exec),
LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),