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

Commit 29e8f59c authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'netlink-caps'



Eric W. Biederman says:

====================
netlink: Preventing abuse when passing file descriptors.

Andy Lutomirski when looking at the networking stack noticed that it is
possible to trick privilged processes into calling write on a netlink
socket and send netlink messages they did not intend.

In particular from time to time there are suid applications that will
write to stdout or stderr without checking exactly what kind of file
descriptors those are and can be tricked into acting as a limited form
of suid cat.  In other conversations the magic string CVE-2014-0181 has
been used to talk about this issue.

This patchset cleans things up a bit, adds some clean abstractions that
when used prevent this kind of problem and then finally changes all of
the handlers of netlink messages that I could find that call capable to
use netlink_ns_capable or an appropriate wrapper.

The abstraction netlink_ns_capable verifies that the original creator of
the netlink socket a message is sent from had the necessary capabilities
as well as verifying that the current sender of a netlink packet has the
necessary capabilities.

The idea is to prevent file descriptor passing of any form from
resulting in a file descriptor that can do more than it can for the
creator of the file descriptor.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 98a46d46 90f62cf3
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -466,7 +466,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
	type -= CRYPTO_MSG_BASE;
	type -= CRYPTO_MSG_BASE;
	link = &crypto_dispatch[type];
	link = &crypto_dispatch[type];


	if (!capable(CAP_NET_ADMIN))
	if (!netlink_capable(skb, CAP_NET_ADMIN))
		return -EPERM;
		return -EPERM;


	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
+1 −1
Original line number Original line Diff line number Diff line
@@ -369,7 +369,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
		return;
		return;


	/* Can only change if privileged. */
	/* Can only change if privileged. */
	if (!capable(CAP_NET_ADMIN)) {
	if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {
		err = EPERM;
		err = EPERM;
		goto out;
		goto out;
	}
	}
+1 −1
Original line number Original line Diff line number Diff line
@@ -77,7 +77,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
			goto next_msg;
			goto next_msg;
		}
		}


		if (!capable(CAP_SYS_ADMIN)) {
		if (!netlink_capable(skb, CAP_SYS_ADMIN)) {
			err = -EPERM;
			err = -EPERM;
			goto next_msg;
			goto next_msg;
		}
		}
+7 −0
Original line number Original line Diff line number Diff line
@@ -169,4 +169,11 @@ struct netlink_tap {
extern int netlink_add_tap(struct netlink_tap *nt);
extern int netlink_add_tap(struct netlink_tap *nt);
extern int netlink_remove_tap(struct netlink_tap *nt);
extern int netlink_remove_tap(struct netlink_tap *nt);


bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
			  struct user_namespace *ns, int cap);
bool netlink_ns_capable(const struct sk_buff *skb,
			struct user_namespace *ns, int cap);
bool netlink_capable(const struct sk_buff *skb, int cap);
bool netlink_net_capable(const struct sk_buff *skb, int cap);

#endif	/* __LINUX_NETLINK_H */
#endif	/* __LINUX_NETLINK_H */
+1 −1
Original line number Original line Diff line number Diff line
@@ -23,7 +23,7 @@ int sock_diag_check_cookie(void *sk, __u32 *cookie);
void sock_diag_save_cookie(void *sk, __u32 *cookie);
void sock_diag_save_cookie(void *sk, __u32 *cookie);


int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr);
int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr);
int sock_diag_put_filterinfo(struct sock *sk,
int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
			     struct sk_buff *skb, int attrtype);
			     struct sk_buff *skb, int attrtype);


#endif
#endif
Loading