summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@fedoraproject.org>2014-05-06 14:12:07 -0400
committerJosh Boyer <jwboyer@fedoraproject.org>2014-05-06 14:12:07 -0400
commit70b6f2e94b1b0490472e8d1d06571ec4e96b7208 (patch)
tree0aa4781cce6b51160f91d83ec4ec801e456068ea
parent122e19846ff464a3804e20bb2b62d16738bf2c4c (diff)
downloadkernel-70b6f2e94b1b0490472e8d1d06571ec4e96b7208.tar.gz
kernel-70b6f2e94b1b0490472e8d1d06571ec4e96b7208.tar.xz
kernel-70b6f2e94b1b0490472e8d1d06571ec4e96b7208.zip
CVE-2014-0181 insufficient netlink permission checks (rhbz 1094270 1094265)
-rw-r--r--1-5-netlink-Rename-netlink_capable-netlink_allowed.patch68
-rw-r--r--2-5-net-Move-the-permission-check-in-sock_diag_put_filterinfo-to-packet_diag_dump.patch104
-rw-r--r--3-5-net-Add-variants-of-capable-for-use-on-on-sockets.patch97
-rw-r--r--4-5-net-Add-variants-of-capable-for-use-on-netlink-messages.patch116
-rw-r--r--5-5-net-Use-netlink_ns_capable-to-verify-the-permisions-of-netlink-messages.patch433
-rw-r--r--kernel.spec22
-rw-r--r--net-Fix-ns_capable-check-in-sock_diag_put_filterinfo.patch72
7 files changed, 911 insertions, 1 deletions
diff --git a/1-5-netlink-Rename-netlink_capable-netlink_allowed.patch b/1-5-netlink-Rename-netlink_capable-netlink_allowed.patch
new file mode 100644
index 00000000..ad18ba87
--- /dev/null
+++ b/1-5-netlink-Rename-netlink_capable-netlink_allowed.patch
@@ -0,0 +1,68 @@
+Bugzilla: 1094270
+Upstream-status: 3.15 and queued for stable
+
+From a7e6a36c02e8a4c6547bfc2b789bfbfcc95072f9 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 23 Apr 2014 14:25:48 -0700
+Subject: [PATCH 2/6] netlink: Rename netlink_capable netlink_allowed
+
+netlink_capable is a static internal function in af_netlink.c and we
+have better uses for the name netlink_capable.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+---
+ net/netlink/af_netlink.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 04748ab649c2..28d66fbc7cef 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1360,7 +1360,7 @@ retry:
+ return err;
+ }
+
+-static inline int netlink_capable(const struct socket *sock, unsigned int flag)
++static inline int netlink_allowed(const struct socket *sock, unsigned int flag)
+ {
+ return (nl_table[sock->sk->sk_protocol].flags & flag) ||
+ ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN);
+@@ -1428,7 +1428,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
+
+ /* Only superuser is allowed to listen multicasts */
+ if (nladdr->nl_groups) {
+- if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV))
++ if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
+ return -EPERM;
+ err = netlink_realloc_groups(sk);
+ if (err)
+@@ -1490,7 +1490,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
+ return -EINVAL;
+
+ if ((nladdr->nl_groups || nladdr->nl_pid) &&
+- !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
++ !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
+ return -EPERM;
+
+ if (!nlk->portid)
+@@ -2096,7 +2096,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
+ break;
+ case NETLINK_ADD_MEMBERSHIP:
+ case NETLINK_DROP_MEMBERSHIP: {
+- if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV))
++ if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
+ return -EPERM;
+ err = netlink_realloc_groups(sk);
+ if (err)
+@@ -2247,7 +2247,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ dst_group = ffs(addr->nl_groups);
+ err = -EPERM;
+ if ((dst_group || dst_portid) &&
+- !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
++ !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
+ goto out;
+ } else {
+ dst_portid = nlk->dst_portid;
+--
+1.9.0
+
diff --git a/2-5-net-Move-the-permission-check-in-sock_diag_put_filterinfo-to-packet_diag_dump.patch b/2-5-net-Move-the-permission-check-in-sock_diag_put_filterinfo-to-packet_diag_dump.patch
new file mode 100644
index 00000000..237569e6
--- /dev/null
+++ b/2-5-net-Move-the-permission-check-in-sock_diag_put_filterinfo-to-packet_diag_dump.patch
@@ -0,0 +1,104 @@
+Bugzilla: 1094270
+Upstream-status: 3.15 and queued for stable
+
+From 568ddf41e32a9b4337d87fdb507e729029a69e49 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 23 Apr 2014 14:26:25 -0700
+Subject: [PATCH 3/6] net: Move the permission check in
+ sock_diag_put_filterinfo to packet_diag_dump
+
+The permission check in sock_diag_put_filterinfo is wrong, and it is so removed
+from it's sources it is not clear why it is wrong. Move the computation
+into packet_diag_dump and pass a bool of the result into sock_diag_filterinfo.
+
+This does not yet correct the capability check but instead simply moves it to make
+it clear what is going on.
+
+Reported-by: Andy Lutomirski <luto@amacapital.net>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+---
+ include/linux/sock_diag.h | 2 +-
+ net/core/sock_diag.c | 4 ++--
+ net/packet/diag.c | 7 ++++++-
+ 3 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
+index 302ab805b0bb..46cca4c06848 100644
+--- a/include/linux/sock_diag.h
++++ b/include/linux/sock_diag.h
+@@ -23,7 +23,7 @@ int sock_diag_check_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_filterinfo(struct sock *sk,
++int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
+ struct sk_buff *skb, int attrtype);
+
+ #endif
+diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
+index 6a7fae228634..c38e7a2b5a8e 100644
+--- a/net/core/sock_diag.c
++++ b/net/core/sock_diag.c
+@@ -49,7 +49,7 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
+ }
+ EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
+
+-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 nlattr *attr;
+@@ -57,7 +57,7 @@ int sock_diag_put_filterinfo(struct sock *sk,
+ unsigned int len;
+ int err = 0;
+
+- if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
++ if (!may_report_filterinfo) {
+ nla_reserve(skb, attrtype, 0);
+ return 0;
+ }
+diff --git a/net/packet/diag.c b/net/packet/diag.c
+index 435ff99ba8c7..b34d0de24091 100644
+--- a/net/packet/diag.c
++++ b/net/packet/diag.c
+@@ -128,6 +128,7 @@ static int pdiag_put_fanout(struct packet_sock *po, struct sk_buff *nlskb)
+
+ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
+ struct packet_diag_req *req,
++ bool may_report_filterinfo,
+ struct user_namespace *user_ns,
+ u32 portid, u32 seq, u32 flags, int sk_ino)
+ {
+@@ -172,7 +173,8 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
+ goto out_nlmsg_trim;
+
+ if ((req->pdiag_show & PACKET_SHOW_FILTER) &&
+- sock_diag_put_filterinfo(sk, skb, PACKET_DIAG_FILTER))
++ sock_diag_put_filterinfo(may_report_filterinfo, sk, skb,
++ PACKET_DIAG_FILTER))
+ goto out_nlmsg_trim;
+
+ return nlmsg_end(skb, nlh);
+@@ -188,9 +190,11 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+ struct packet_diag_req *req;
+ struct net *net;
+ struct sock *sk;
++ bool may_report_filterinfo;
+
+ net = sock_net(skb->sk);
+ req = nlmsg_data(cb->nlh);
++ may_report_filterinfo = ns_capable(net->user_ns, CAP_NET_ADMIN);
+
+ mutex_lock(&net->packet.sklist_lock);
+ sk_for_each(sk, &net->packet.sklist) {
+@@ -200,6 +204,7 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+ goto next;
+
+ if (sk_diag_fill(sk, skb, req,
++ may_report_filterinfo,
+ sk_user_ns(NETLINK_CB(cb->skb).sk),
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+--
+1.9.0
+
diff --git a/3-5-net-Add-variants-of-capable-for-use-on-on-sockets.patch b/3-5-net-Add-variants-of-capable-for-use-on-on-sockets.patch
new file mode 100644
index 00000000..34df2924
--- /dev/null
+++ b/3-5-net-Add-variants-of-capable-for-use-on-on-sockets.patch
@@ -0,0 +1,97 @@
+Bugzilla: 1094270
+Upstream-status: 3.15 and queued for stable
+
+From ca469eb66a7b3e97a230c750de4d01b1dc53906a Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 23 Apr 2014 14:26:56 -0700
+Subject: [PATCH 4/6] net: Add variants of capable for use on on sockets
+
+sk_net_capable - The common case, operations that are safe in a network namespace.
+sk_capable - Operations that are not known to be safe in a network namespace
+sk_ns_capable - The general case for special cases.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+---
+ include/net/sock.h | 5 +++++
+ net/core/sock.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 54 insertions(+)
+
+diff --git a/include/net/sock.h b/include/net/sock.h
+index b9586a137cad..57c31dd15e64 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -2278,6 +2278,11 @@ int sock_get_timestampns(struct sock *, struct timespec __user *);
+ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level,
+ int type);
+
++bool sk_ns_capable(const struct sock *sk,
++ struct user_namespace *user_ns, int cap);
++bool sk_capable(const struct sock *sk, int cap);
++bool sk_net_capable(const struct sock *sk, int cap);
++
+ /*
+ * Enable debug/info messages
+ */
+diff --git a/net/core/sock.c b/net/core/sock.c
+index c0fc6bdad1e3..c8069561bdb7 100644
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -145,6 +145,55 @@
+ static DEFINE_MUTEX(proto_list_mutex);
+ static LIST_HEAD(proto_list);
+
++/**
++ * sk_ns_capable - General socket capability test
++ * @sk: Socket to use a capability on or through
++ * @user_ns: The user namespace of the capability to use
++ * @cap: The capability to use
++ *
++ * Test to see if the opener of the socket had when the socket was
++ * created and the current process has the capability @cap in the user
++ * namespace @user_ns.
++ */
++bool sk_ns_capable(const struct sock *sk,
++ struct user_namespace *user_ns, int cap)
++{
++ return file_ns_capable(sk->sk_socket->file, user_ns, cap) &&
++ ns_capable(user_ns, cap);
++}
++EXPORT_SYMBOL(sk_ns_capable);
++
++/**
++ * sk_capable - Socket global capability test
++ * @sk: Socket to use a capability on or through
++ * @cap: The global capbility to use
++ *
++ * Test to see if the opener of the socket had when the socket was
++ * created and the current process has the capability @cap in all user
++ * namespaces.
++ */
++bool sk_capable(const struct sock *sk, int cap)
++{
++ return sk_ns_capable(sk, &init_user_ns, cap);
++}
++EXPORT_SYMBOL(sk_capable);
++
++/**
++ * sk_net_capable - Network namespace socket capability test
++ * @sk: Socket to use a capability on or through
++ * @cap: The capability to use
++ *
++ * Test to see if the opener of the socket had when the socke was created
++ * and the current process has the capability @cap over the network namespace
++ * the socket is a member of.
++ */
++bool sk_net_capable(const struct sock *sk, int cap)
++{
++ return sk_ns_capable(sk, sock_net(sk)->user_ns, cap);
++}
++EXPORT_SYMBOL(sk_net_capable);
++
++
+ #ifdef CONFIG_MEMCG_KMEM
+ int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
+ {
+--
+1.9.0
+
diff --git a/4-5-net-Add-variants-of-capable-for-use-on-netlink-messages.patch b/4-5-net-Add-variants-of-capable-for-use-on-netlink-messages.patch
new file mode 100644
index 00000000..dfae87ae
--- /dev/null
+++ b/4-5-net-Add-variants-of-capable-for-use-on-netlink-messages.patch
@@ -0,0 +1,116 @@
+Bugzilla: 1094270
+Upstream-status: 3.15 and queued for stable
+
+From 71f40189cc9a0a28296d201652a5766d7c8aa66f Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 23 Apr 2014 14:28:03 -0700
+Subject: [PATCH 5/6] net: Add variants of capable for use on netlink messages
+
+netlink_net_capable - The common case use, for operations that are safe on a network namespace
+netlink_capable - For operations that are only known to be safe for the global root
+netlink_ns_capable - The general case of capable used to handle special cases
+
+__netlink_ns_capable - Same as netlink_ns_capable except taking a netlink_skb_parms instead of
+ the skbuff of a netlink message.
+
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+---
+ include/linux/netlink.h | 7 ++++++
+ net/netlink/af_netlink.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 72 insertions(+)
+
+diff --git a/include/linux/netlink.h b/include/linux/netlink.h
+index aad8eeaf416d..f64b01787ddc 100644
+--- a/include/linux/netlink.h
++++ b/include/linux/netlink.h
+@@ -169,4 +169,11 @@ struct netlink_tap {
+ extern int netlink_add_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 */
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 28d66fbc7cef..6d69c27897f3 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1360,6 +1360,71 @@ retry:
+ return err;
+ }
+
++/**
++ * __netlink_ns_capable - General netlink message capability test
++ * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace.
++ * @user_ns: The user namespace of the capability to use
++ * @cap: The capability to use
++ *
++ * Test to see if the opener of the socket we received the message
++ * from had when the netlink socket was created and the sender of the
++ * message has has the capability @cap in the user namespace @user_ns.
++ */
++bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
++ struct user_namespace *user_ns, int cap)
++{
++ return sk_ns_capable(nsp->sk, user_ns, cap);
++}
++EXPORT_SYMBOL(__netlink_ns_capable);
++
++/**
++ * netlink_ns_capable - General netlink message capability test
++ * @skb: socket buffer holding a netlink command from userspace
++ * @user_ns: The user namespace of the capability to use
++ * @cap: The capability to use
++ *
++ * Test to see if the opener of the socket we received the message
++ * from had when the netlink socket was created and the sender of the
++ * message has has the capability @cap in the user namespace @user_ns.
++ */
++bool netlink_ns_capable(const struct sk_buff *skb,
++ struct user_namespace *user_ns, int cap)
++{
++ return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap);
++}
++EXPORT_SYMBOL(netlink_ns_capable);
++
++/**
++ * netlink_capable - Netlink global message capability test
++ * @skb: socket buffer holding a netlink command from userspace
++ * @cap: The capability to use
++ *
++ * Test to see if the opener of the socket we received the message
++ * from had when the netlink socket was created and the sender of the
++ * message has has the capability @cap in all user namespaces.
++ */
++bool netlink_capable(const struct sk_buff *skb, int cap)
++{
++ return netlink_ns_capable(skb, &init_user_ns, cap);
++}
++EXPORT_SYMBOL(netlink_capable);
++
++/**
++ * netlink_net_capable - Netlink network namespace message capability test
++ * @skb: socket buffer holding a netlink command from userspace
++ * @cap: The capability to use
++ *
++ * Test to see if the opener of the socket we received the message
++ * from had when the netlink socket was created and the sender of the
++ * message has has the capability @cap over the network namespace of
++ * the socket we received the message from.
++ */
++bool netlink_net_capable(const struct sk_buff *skb, int cap)
++{
++ return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap);
++}
++EXPORT_SYMBOL(netlink_net_capable);
++
+ static inline int netlink_allowed(const struct socket *sock, unsigned int flag)
+ {
+ return (nl_table[sock->sk->sk_protocol].flags & flag) ||
+--
+1.9.0
+
diff --git a/5-5-net-Use-netlink_ns_capable-to-verify-the-permisions-of-netlink-messages.patch b/5-5-net-Use-netlink_ns_capable-to-verify-the-permisions-of-netlink-messages.patch
new file mode 100644
index 00000000..b92c5da6
--- /dev/null
+++ b/5-5-net-Use-netlink_ns_capable-to-verify-the-permisions-of-netlink-messages.patch
@@ -0,0 +1,433 @@
+Bugzilla: 1094270
+Upstream-status: 3.15 and queued for stable
+
+From 386e6689d3a9234ab00a80ab51906adedfa7fea7 Mon Sep 17 00:00:00 2001
+From: "Eric W. Biederman" <ebiederm@xmission.com>
+Date: Wed, 23 Apr 2014 14:29:27 -0700
+Subject: [PATCH 6/6] net: Use netlink_ns_capable to verify the permisions of
+ netlink messages
+
+It is possible by passing a netlink socket to a more privileged
+executable and then to fool that executable into writing to the socket
+data that happens to be valid netlink message to do something that
+privileged executable did not intend to do.
+
+To keep this from happening replace bare capable and ns_capable calls
+with netlink_capable, netlink_net_calls and netlink_ns_capable calls.
+Which act the same as the previous calls except they verify that the
+opener of the socket had the desired permissions as well.
+
+Reported-by: Andy Lutomirski <luto@amacapital.net>
+Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
+---
+ crypto/crypto_user.c | 2 +-
+ drivers/connector/cn_proc.c | 2 +-
+ drivers/scsi/scsi_netlink.c | 2 +-
+ kernel/audit.c | 4 ++--
+ net/can/gw.c | 4 ++--
+ net/core/rtnetlink.c | 20 +++++++++++---------
+ net/dcb/dcbnl.c | 2 +-
+ net/decnet/dn_dev.c | 4 ++--
+ net/decnet/dn_fib.c | 4 ++--
+ net/decnet/netfilter/dn_rtmsg.c | 2 +-
+ net/netfilter/nfnetlink.c | 2 +-
+ net/netlink/genetlink.c | 2 +-
+ net/packet/diag.c | 2 +-
+ net/phonet/pn_netlink.c | 8 ++++----
+ net/sched/act_api.c | 2 +-
+ net/sched/cls_api.c | 2 +-
+ net/sched/sch_api.c | 6 +++---
+ net/tipc/netlink.c | 2 +-
+ net/xfrm/xfrm_user.c | 2 +-
+ 19 files changed, 38 insertions(+), 36 deletions(-)
+
+diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
+index 1512e41cd93d..43665d0d0905 100644
+--- a/crypto/crypto_user.c
++++ b/crypto/crypto_user.c
+@@ -466,7 +466,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ type -= CRYPTO_MSG_BASE;
+ link = &crypto_dispatch[type];
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
+diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
+index 18c5b9b16645..3165811e2407 100644
+--- a/drivers/connector/cn_proc.c
++++ b/drivers/connector/cn_proc.c
+@@ -369,7 +369,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
+ return;
+
+ /* Can only change if privileged. */
+- if (!capable(CAP_NET_ADMIN)) {
++ if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {
+ err = EPERM;
+ goto out;
+ }
+diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
+index fe30ea94ffe6..109802f776ed 100644
+--- a/drivers/scsi/scsi_netlink.c
++++ b/drivers/scsi/scsi_netlink.c
+@@ -77,7 +77,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
+ goto next_msg;
+ }
+
+- if (!capable(CAP_SYS_ADMIN)) {
++ if (!netlink_capable(skb, CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto next_msg;
+ }
+diff --git a/kernel/audit.c b/kernel/audit.c
+index 95a20f3f52f1..f7e680d896ec 100644
+--- a/kernel/audit.c
++++ b/kernel/audit.c
+@@ -639,13 +639,13 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
+ case AUDIT_TTY_SET:
+ case AUDIT_TRIM:
+ case AUDIT_MAKE_EQUIV:
+- if (!capable(CAP_AUDIT_CONTROL))
++ if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
+ err = -EPERM;
+ break;
+ case AUDIT_USER:
+ case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
+ case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
+- if (!capable(CAP_AUDIT_WRITE))
++ if (!netlink_capable(skb, CAP_AUDIT_WRITE))
+ err = -EPERM;
+ break;
+ default: /* bad msg */
+diff --git a/net/can/gw.c b/net/can/gw.c
+index ac31891967da..050a2110d43f 100644
+--- a/net/can/gw.c
++++ b/net/can/gw.c
+@@ -804,7 +804,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
+ u8 limhops = 0;
+ int err = 0;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (nlmsg_len(nlh) < sizeof(*r))
+@@ -893,7 +893,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
+ u8 limhops = 0;
+ int err = 0;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (nlmsg_len(nlh) < sizeof(*r))
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 120eecc0f5a4..463dfe6496b4 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -1386,7 +1386,8 @@ static int do_set_master(struct net_device *dev, int ifindex)
+ return 0;
+ }
+
+-static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
++static int do_setlink(const struct sk_buff *skb,
++ struct net_device *dev, struct ifinfomsg *ifm,
+ struct nlattr **tb, char *ifname, int modified)
+ {
+ const struct net_device_ops *ops = dev->netdev_ops;
+@@ -1398,7 +1399,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
+ err = PTR_ERR(net);
+ goto errout;
+ }
+- if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
++ if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
+ err = -EPERM;
+ goto errout;
+ }
+@@ -1652,7 +1653,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)
+ if (err < 0)
+ goto errout;
+
+- err = do_setlink(dev, ifm, tb, ifname, 0);
++ err = do_setlink(skb, dev, ifm, tb, ifname, 0);
+ errout:
+ return err;
+ }
+@@ -1769,7 +1770,8 @@ err:
+ }
+ EXPORT_SYMBOL(rtnl_create_link);
+
+-static int rtnl_group_changelink(struct net *net, int group,
++static int rtnl_group_changelink(const struct sk_buff *skb,
++ struct net *net, int group,
+ struct ifinfomsg *ifm,
+ struct nlattr **tb)
+ {
+@@ -1778,7 +1780,7 @@ static int rtnl_group_changelink(struct net *net, int group,
+
+ for_each_netdev(net, dev) {
+ if (dev->group == group) {
+- err = do_setlink(dev, ifm, tb, NULL, 0);
++ err = do_setlink(skb, dev, ifm, tb, NULL, 0);
+ if (err < 0)
+ return err;
+ }
+@@ -1920,12 +1922,12 @@ replay:
+ modified = 1;
+ }
+
+- return do_setlink(dev, ifm, tb, ifname, modified);
++ return do_setlink(skb, dev, ifm, tb, ifname, modified);
+ }
+
+ if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
+ if (ifm->ifi_index == 0 && tb[IFLA_GROUP])
+- return rtnl_group_changelink(net,
++ return rtnl_group_changelink(skb, net,
+ nla_get_u32(tb[IFLA_GROUP]),
+ ifm, tb);
+ return -ENODEV;
+@@ -2312,7 +2314,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
+ int err = -EINVAL;
+ __u8 *addr;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
+@@ -2764,7 +2766,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ sz_idx = type>>2;
+ kind = type&3;
+
+- if (kind != 2 && !ns_capable(net->user_ns, CAP_NET_ADMIN))
++ if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
+diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
+index 553644402670..f8b98d89c285 100644
+--- a/net/dcb/dcbnl.c
++++ b/net/dcb/dcbnl.c
+@@ -1669,7 +1669,7 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
+ struct nlmsghdr *reply_nlh = NULL;
+ const struct reply_func *fn;
+
+- if ((nlh->nlmsg_type == RTM_SETDCB) && !capable(CAP_NET_ADMIN))
++ if ((nlh->nlmsg_type == RTM_SETDCB) && !netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,
+diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
+index a603823a3e27..3b726f31c64c 100644
+--- a/net/decnet/dn_dev.c
++++ b/net/decnet/dn_dev.c
+@@ -574,7 +574,7 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
+ struct dn_ifaddr __rcu **ifap;
+ int err = -EINVAL;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!net_eq(net, &init_net))
+@@ -618,7 +618,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
+ struct dn_ifaddr *ifa;
+ int err;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!net_eq(net, &init_net))
+diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
+index 57dc159245ec..d332aefb0846 100644
+--- a/net/decnet/dn_fib.c
++++ b/net/decnet/dn_fib.c
+@@ -505,7 +505,7 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
+ struct nlattr *attrs[RTA_MAX+1];
+ int err;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!net_eq(net, &init_net))
+@@ -530,7 +530,7 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
+ struct nlattr *attrs[RTA_MAX+1];
+ int err;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!net_eq(net, &init_net))
+diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
+index e83015cecfa7..e4d9560a910b 100644
+--- a/net/decnet/netfilter/dn_rtmsg.c
++++ b/net/decnet/netfilter/dn_rtmsg.c
+@@ -107,7 +107,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
+ if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+ return;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ RCV_SKB_FAIL(-EPERM);
+
+ /* Eventually we might send routing messages too */
+diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
+index 046aa13b4fea..c6881781d70a 100644
+--- a/net/netfilter/nfnetlink.c
++++ b/net/netfilter/nfnetlink.c
+@@ -367,7 +367,7 @@ static void nfnetlink_rcv(struct sk_buff *skb)
+ skb->len < nlh->nlmsg_len)
+ return;
+
+- if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
++ if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
+ netlink_ack(skb, nlh, -EPERM);
+ return;
+ }
+diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
+index b1dcdb932a86..a3ba3ca0ff92 100644
+--- a/net/netlink/genetlink.c
++++ b/net/netlink/genetlink.c
+@@ -561,7 +561,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
+ return -EOPNOTSUPP;
+
+ if ((ops->flags & GENL_ADMIN_PERM) &&
+- !capable(CAP_NET_ADMIN))
++ !netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+diff --git a/net/packet/diag.c b/net/packet/diag.c
+index b34d0de24091..92f2c7107eec 100644
+--- a/net/packet/diag.c
++++ b/net/packet/diag.c
+@@ -194,7 +194,7 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+
+ net = sock_net(skb->sk);
+ req = nlmsg_data(cb->nlh);
+- may_report_filterinfo = ns_capable(net->user_ns, CAP_NET_ADMIN);
++ may_report_filterinfo = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
+
+ mutex_lock(&net->packet.sklist_lock);
+ sk_for_each(sk, &net->packet.sklist) {
+diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
+index dc15f4300808..b64151ade6b3 100644
+--- a/net/phonet/pn_netlink.c
++++ b/net/phonet/pn_netlink.c
+@@ -70,10 +70,10 @@ static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
+ int err;
+ u8 pnaddr;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+- if (!capable(CAP_SYS_ADMIN))
++ if (!netlink_capable(skb, CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ASSERT_RTNL();
+@@ -233,10 +233,10 @@ static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
+ int err;
+ u8 dst;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+- if (!capable(CAP_SYS_ADMIN))
++ if (!netlink_capable(skb, CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ASSERT_RTNL();
+diff --git a/net/sched/act_api.c b/net/sched/act_api.c
+index 72bdc7166345..3b2265523552 100644
+--- a/net/sched/act_api.c
++++ b/net/sched/act_api.c
+@@ -908,7 +908,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n)
+ u32 portid = skb ? NETLINK_CB(skb).portid : 0;
+ int ret = 0, ovr = 0;
+
+- if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN))
++ if ((n->nlmsg_type != RTM_GETACTION) && !netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 29a30a14c315..bdbdb1a7920a 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -134,7 +134,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
+ int err;
+ int tp_created = 0;
+
+- if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN))
++ if ((n->nlmsg_type != RTM_GETTFILTER) && !netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ replay:
+diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
+index a07d55e75698..98532cfa7823 100644
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -1084,7 +1084,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
+ struct Qdisc *p = NULL;
+ int err;
+
+- if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN))
++ if ((n->nlmsg_type != RTM_GETQDISC) && !netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
+@@ -1151,7 +1151,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
+ struct Qdisc *q, *p;
+ int err;
+
+- if (!capable(CAP_NET_ADMIN))
++ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ replay:
+@@ -1491,7 +1491,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n)
+ u32 qid;
+ int err;
+
+- if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN))
++ if ((n->nlmsg_type != RTM_GETTCLASS) && !netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
+diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
+index 3aaf73de9e2d..ad844d365340 100644
+--- a/net/tipc/netlink.c
++++ b/net/tipc/netlink.c
+@@ -47,7 +47,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
+ int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+ u16 cmd;
+
+- if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
++ if ((req_userhdr->cmd & 0xC000) && (!netlink_capable(skb, CAP_NET_ADMIN)))
+ cmd = TIPC_CMD_NOT_NET_ADMIN;
+ else
+ cmd = req_userhdr->cmd;
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index 2f7ddc3a59b4..b10d04fa3933 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -2350,7 +2350,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+ link = &xfrm_dispatch[type];
+
+ /* All operations require privileges, even GET */
+- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
++ if (!netlink_net_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
+--
+1.9.0
+
diff --git a/kernel.spec b/kernel.spec
index 4252e224..ee1c094f 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -779,6 +779,14 @@ Patch25079: 0003-samsung-laptop-Add-broken-acpi-video-quirk-for-NC210.patch
#rhbz 1067181
Patch25080: 0004-acpi-blacklist-Add-dmi_enable_osi_linux-quirk-for-As.patch
+#CVE-2014-0181 rhbz 1094270 1094265
+Patch25081: net-Fix-ns_capable-check-in-sock_diag_put_filterinfo.patch
+Patch25082: 1-5-netlink-Rename-netlink_capable-netlink_allowed.patch
+Patch25083: 2-5-net-Move-the-permission-check-in-sock_diag_put_filterinfo-to-packet_diag_dump.patch
+Patch25084: 3-5-net-Add-variants-of-capable-for-use-on-on-sockets.patch
+Patch25085: 4-5-net-Add-variants-of-capable-for-use-on-netlink-messages.patch
+Patch25086: 5-5-net-Use-netlink_ns_capable-to-verify-the-permisions-of-netlink-messages.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -1511,6 +1519,15 @@ ApplyPatch 0003-samsung-laptop-Add-broken-acpi-video-quirk-for-NC210.patch
#rhbz 1067181
ApplyPatch 0004-acpi-blacklist-Add-dmi_enable_osi_linux-quirk-for-As.patch
+#CVE-2014-0181 rhbz 1094270 1094265
+ApplyPatch net-Fix-ns_capable-check-in-sock_diag_put_filterinfo.patch
+ApplyPatch 1-5-netlink-Rename-netlink_capable-netlink_allowed.patch
+ApplyPatch 2-5-net-Move-the-permission-check-in-sock_diag_put_filterinfo-to-packet_diag_dump.patch
+ApplyPatch 3-5-net-Add-variants-of-capable-for-use-on-on-sockets.patch
+ApplyPatch 4-5-net-Add-variants-of-capable-for-use-on-netlink-messages.patch
+ApplyPatch 5-5-net-Use-netlink_ns_capable-to-verify-the-permisions-of-netlink-messages.patch
+
+
# END OF PATCH APPLICATIONS
%endif
@@ -2322,7 +2339,10 @@ fi
# ||----w |
# || ||
%changelog
-* Tue May 06 2014 Justin M. Forbes <jforbes@fedoraproject.org> 3.14.3-200
+* Tue May 06 2014 Josh Boyer <jwboyer@fedoraproject.org> 3.14.3-200
+- CVE-2014-0181 insufficient netlink permission checks (rhbz 1094270 1094265)
+
+* Tue May 06 2014 Justin M. Forbes <jforbes@fedoraproject.org>
- Linux v3.14.3
* Tue May 06 2014 Hans de Goede <hdegoede@redhat.com>
diff --git a/net-Fix-ns_capable-check-in-sock_diag_put_filterinfo.patch b/net-Fix-ns_capable-check-in-sock_diag_put_filterinfo.patch
new file mode 100644
index 00000000..9e4abdb9
--- /dev/null
+++ b/net-Fix-ns_capable-check-in-sock_diag_put_filterinfo.patch
@@ -0,0 +1,72 @@
+Bugzilla: 1094270
+Upstream-status: 3.15 and queued for stable
+
+From 3b72ed3ca18b9f55fc90f55a52c32b22b3a2837e Mon Sep 17 00:00:00 2001
+From: Andrew Lutomirski <luto@amacapital.net>
+Date: Wed, 16 Apr 2014 21:41:34 -0700
+Subject: [PATCH 1/6] net: Fix ns_capable check in sock_diag_put_filterinfo
+
+The caller needs capabilities on the namespace being queried, not on
+their own namespace. This is a security bug, although it likely has
+only a minor impact.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Andy Lutomirski <luto@amacapital.net>
+Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
+---
+ include/linux/sock_diag.h | 2 +-
+ net/core/sock_diag.c | 4 ++--
+ net/packet/diag.c | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
+index 54f91d35e5fd..302ab805b0bb 100644
+--- a/include/linux/sock_diag.h
++++ b/include/linux/sock_diag.h
+@@ -23,7 +23,7 @@ int sock_diag_check_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_filterinfo(struct user_namespace *user_ns, struct sock *sk,
++int sock_diag_put_filterinfo(struct sock *sk,
+ struct sk_buff *skb, int attrtype);
+
+ #endif
+diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
+index a0e9cf6379de..6a7fae228634 100644
+--- a/net/core/sock_diag.c
++++ b/net/core/sock_diag.c
+@@ -49,7 +49,7 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
+ }
+ EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
+
+-int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
++int sock_diag_put_filterinfo(struct sock *sk,
+ struct sk_buff *skb, int attrtype)
+ {
+ struct nlattr *attr;
+@@ -57,7 +57,7 @@ int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
+ unsigned int len;
+ int err = 0;
+
+- if (!ns_capable(user_ns, CAP_NET_ADMIN)) {
++ if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
+ nla_reserve(skb, attrtype, 0);
+ return 0;
+ }
+diff --git a/net/packet/diag.c b/net/packet/diag.c
+index 533ce4ff108a..435ff99ba8c7 100644
+--- a/net/packet/diag.c
++++ b/net/packet/diag.c
+@@ -172,7 +172,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
+ goto out_nlmsg_trim;
+
+ if ((req->pdiag_show & PACKET_SHOW_FILTER) &&
+- sock_diag_put_filterinfo(user_ns, sk, skb, PACKET_DIAG_FILTER))
++ sock_diag_put_filterinfo(sk, skb, PACKET_DIAG_FILTER))
+ goto out_nlmsg_trim;
+
+ return nlmsg_end(skb, nlh);
+--
+1.9.0
+