lkml.org 
[lkml]   [2020]   [May]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 29/37] selinux: properly handle multiple messages in selinux_netlink_send()
    Date
    From: Paul Moore <paul@paul-moore.com>

    commit fb73974172ffaaf57a7c42f35424d9aece1a5af6 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: Dmitry Vyukov <dvyukov@google.com>
    Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
    Signed-off-by: Paul Moore <paul@paul-moore.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    security/selinux/hooks.c | 70 ++++++++++++++++++++++++++++++-----------------
    1 file changed, 45 insertions(+), 25 deletions(-)

    --- a/security/selinux/hooks.c
    +++ b/security/selinux/hooks.c
    @@ -5595,40 +5595,60 @@ static int selinux_tun_dev_open(void *se

    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",
    - 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;
    }

    #ifdef CONFIG_NETFILTER

    \
     
     \ /
      Last update: 2020-05-04 20:02    [W:4.088 / U:0.196 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site