Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4723e94f authored by “pankaj.suryawanshi”'s avatar “pankaj.suryawanshi” Committed by Harshit Agarwal
Browse files

properly handle multiple messages in selinux_netlink_send()

Change-Id: I563773d5f99028a542f229018c2e87cbfce3db5b
parent 1e2bb714
Loading
Loading
Loading
Loading
+45 −25
Original line number Diff line number Diff line
@@ -5592,40 +5592,60 @@ static int selinux_tun_dev_open(void *security)

static int selinux_nlmsg_perm(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;

	err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
	if (err) {
		if (err == -EINVAL) {
		/* 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;

		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"
			       " pig=%d comm=%s\n",
				" pid=%d comm=%s\n",
				sk->sk_protocol, nlh->nlmsg_type,
			       secclass_map[sksec->sclass - 1].name,
				secclass_map[sclass - 1].name,
				task_pid_nr(current), current->comm);
			if (!enforcing_enabled(&selinux_state) ||
			    security_get_allow_unknown(&selinux_state))
				err = 0;
			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;
}

#ifdef CONFIG_NETFILTER