diff options
author | Josh Boyer <jwboyer@fedoraproject.org> | 2014-05-06 14:12:07 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@fedoraproject.org> | 2014-05-06 14:12:07 -0400 |
commit | 70b6f2e94b1b0490472e8d1d06571ec4e96b7208 (patch) | |
tree | 0aa4781cce6b51160f91d83ec4ec801e456068ea | |
parent | 122e19846ff464a3804e20bb2b62d16738bf2c4c (diff) | |
download | kernel-70b6f2e94b1b0490472e8d1d06571ec4e96b7208.tar.gz kernel-70b6f2e94b1b0490472e8d1d06571ec4e96b7208.tar.xz kernel-70b6f2e94b1b0490472e8d1d06571ec4e96b7208.zip |
CVE-2014-0181 insufficient netlink permission checks (rhbz 1094270 1094265)
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 + |