Commit 2d7a85f4 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

netlink: Only check file credentials for implicit destinations

It was possible to get a setuid root or setcap executable to write to
it's stdout or stderr (which has been set made a netlink socket) and
inadvertently reconfigure the networking stack.

To prevent this we check that both the creator of the socket and
the currentl applications has permission to reconfigure the network
stack.

Unfortunately this breaks Zebra which always uses sendto/sendmsg
and creates it's socket without any privileges.

To keep Zebra working don't bother checking if the creator of the
socket has privilege when a destination address is specified.  Instead
rely exclusively on the privileges of the sender of the socket.

Note from Andy: This is exactly Eric's code except for some comment
clarifications and formatting fixes.  Neither I nor, I think, anyone
else is thrilled with this approach, but I'm hesitant to wait on a
better fix since 3.15 is almost here.

Note to stable maintainers: This is a mess.  An earlier series of
patches in 3.15 fix a rather serious security issue (CVE-2014-0181),
but they did so in a way that breaks Zebra.  The offending series
includes:

    commit aa4cf945
    Author: Eric W. Biederman <ebiederm@xmission.com>
    Date:   Wed Apr 23 14:28:03 2014 -0700

        net: Add variants of capable for use on netlink messages

If a given kernel version is missing that series of fixes, it's
probably worth backporting it and this patch.  if that series is
present, then this fix is critical if you care about Zebra.

Cc: stable@vger.kernel.org
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarAndy Lutomirski <luto@amacapital.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 22fd2a52
...@@ -16,9 +16,10 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb) ...@@ -16,9 +16,10 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
} }
enum netlink_skb_flags { enum netlink_skb_flags {
NETLINK_SKB_MMAPED = 0x1, /* Packet data is mmaped */ NETLINK_SKB_MMAPED = 0x1, /* Packet data is mmaped */
NETLINK_SKB_TX = 0x2, /* Packet was sent by userspace */ NETLINK_SKB_TX = 0x2, /* Packet was sent by userspace */
NETLINK_SKB_DELIVERED = 0x4, /* Packet was delivered */ NETLINK_SKB_DELIVERED = 0x4, /* Packet was delivered */
NETLINK_SKB_DST = 0x8, /* Dst set in sendto or sendmsg */
}; };
struct netlink_skb_parms { struct netlink_skb_parms {
......
...@@ -1373,7 +1373,9 @@ static int netlink_autobind(struct socket *sock) ...@@ -1373,7 +1373,9 @@ static int netlink_autobind(struct socket *sock)
bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
struct user_namespace *user_ns, int cap) struct user_namespace *user_ns, int cap)
{ {
return sk_ns_capable(nsp->sk, user_ns, cap); return ((nsp->flags & NETLINK_SKB_DST) ||
file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) &&
ns_capable(user_ns, cap);
} }
EXPORT_SYMBOL(__netlink_ns_capable); EXPORT_SYMBOL(__netlink_ns_capable);
...@@ -2293,6 +2295,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, ...@@ -2293,6 +2295,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
struct scm_cookie scm; struct scm_cookie scm;
u32 netlink_skb_flags = 0;
if (msg->msg_flags&MSG_OOB) if (msg->msg_flags&MSG_OOB)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -2314,6 +2317,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, ...@@ -2314,6 +2317,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
if ((dst_group || dst_portid) && if ((dst_group || dst_portid) &&
!netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
goto out; goto out;
netlink_skb_flags |= NETLINK_SKB_DST;
} else { } else {
dst_portid = nlk->dst_portid; dst_portid = nlk->dst_portid;
dst_group = nlk->dst_group; dst_group = nlk->dst_group;
...@@ -2343,6 +2347,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, ...@@ -2343,6 +2347,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
NETLINK_CB(skb).portid = nlk->portid; NETLINK_CB(skb).portid = nlk->portid;
NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).dst_group = dst_group;
NETLINK_CB(skb).creds = siocb->scm->creds; NETLINK_CB(skb).creds = siocb->scm->creds;
NETLINK_CB(skb).flags = netlink_skb_flags;
err = -EFAULT; err = -EFAULT;
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
......
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