Commit 9f0f4260 authored by Paul Moore's avatar Paul Moore Committed by Kleber Sacilotto de Souza

selinux: properly handle multiple messages in selinux_netlink_send()

BugLink: https://bugs.launchpad.net/bugs/1878246

commit fb739741 upstream.

Fix the SELinux netlink_send hook to properly handle multiple netlink
messages in a single sk_buff; each message is parsed and subject to
SELinux access control.  Prior to this patch, SELinux only inspected
the first message in the sk_buff.

Cc: stable@vger.kernel.org
Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
Reviewed-by: default avatarStephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarIan May <ian.may@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 057a9486
...@@ -4814,38 +4814,59 @@ static int selinux_tun_dev_open(void *security) ...@@ -4814,38 +4814,59 @@ static int selinux_tun_dev_open(void *security)
static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
{ {
int err = 0; int rc = 0;
u32 perm; unsigned int msg_len;
unsigned int data_len = skb->len;
unsigned char *data = skb->data;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
u16 sclass = sksec->sclass;
u32 perm;
if (skb->len < NLMSG_HDRLEN) { while (data_len >= nlmsg_total_size(0)) {
err = -EINVAL; nlh = (struct nlmsghdr *)data;
goto out;
}
nlh = nlmsg_hdr(skb);
err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm); /* NOTE: the nlmsg_len field isn't reliably set by some netlink
if (err) { * users which means we can't reject skb's with bogus
if (err == -EINVAL) { * length fields; our solution is to follow what
printk(KERN_WARNING * netlink_rcv_skb() does and simply skip processing at
"SELinux: unrecognized netlink message:" * messages with length fields that are clearly junk
" protocol=%hu nlmsg_type=%hu sclass=%s\n", */
sk->sk_protocol, nlh->nlmsg_type, if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len)
secclass_map[sksec->sclass - 1].name); return 0;
if (!selinux_enforcing || security_get_allow_unknown())
err = 0; rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm);
if (rc == 0) {
rc = sock_has_perm(current, 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[sclass - 1].name,
task_pid_nr(current), current->comm);
if (selinux_enforcing && !security_get_allow_unknown())
return rc;
rc = 0;
} else if (rc == -ENOENT) {
/* -ENOENT is a missing socket/class mapping, ignore */
rc = 0;
} else {
return rc;
} }
/* Ignore */ /* move to the next message after applying netlink padding */
if (err == -ENOENT) msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
err = 0; if (msg_len >= data_len)
goto out; return 0;
data_len -= msg_len;
data += msg_len;
} }
err = sock_has_perm(current, sk, perm); return rc;
out:
return err;
} }
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment