net: inet: Support UID-based routing in IP protocols.
- Use the UID in routing lookups made by protocol connect() and sendmsg() functions. - Make sure that routing lookups triggered by incoming packets (e.g., Path MTU discovery) take the UID of the socket into account. - For packets not associated with a userspace socket, (e.g., ping replies) use UID 0 inside the user namespace corresponding to the network namespace the socket belongs to. This allows all namespaces to apply routing and iptables rules to kernel-originated traffic in that namespaces by matching UID 0. This is better than using the UID of the kernel socket that is sending the traffic, because the UID of kernel sockets created at namespace creation time (e.g., the per-processor ICMP and TCP sockets) is the UID of the user that created the socket, which might not be mapped in the namespace. Tested: compiles allnoconfig, allyesconfig, allmodconfig Tested: https://android-review.googlesource.com/253302 Signed-off-by: Lorenzo Colitti <lorenzo@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
622ec2c9d5
commit
e2d118a1cb
@@ -678,6 +678,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
|
||||
fl6.flowi6_mark = sk->sk_mark;
|
||||
fl6.fl6_dport = inet->inet_dport;
|
||||
fl6.fl6_sport = inet->inet_sport;
|
||||
fl6.flowi6_uid = sk->sk_uid;
|
||||
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
|
||||
|
||||
rcu_read_lock();
|
||||
|
@@ -662,9 +662,10 @@ static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
return 0;
|
||||
|
||||
if (type == NDISC_REDIRECT)
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0);
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0,
|
||||
sock_net_uid(net, NULL));
|
||||
else
|
||||
ip6_update_pmtu(skb, net, info, 0, 0);
|
||||
ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
|
||||
xfrm_state_put(x);
|
||||
|
||||
return 0;
|
||||
|
@@ -54,6 +54,7 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6, struct sock *sk)
|
||||
fl6->fl6_dport = inet->inet_dport;
|
||||
fl6->fl6_sport = inet->inet_sport;
|
||||
fl6->flowlabel = np->flow_label;
|
||||
fl6->flowi6_uid = sk->sk_uid;
|
||||
|
||||
if (!fl6->flowi6_oif)
|
||||
fl6->flowi6_oif = np->sticky_pktinfo.ipi6_ifindex;
|
||||
|
@@ -474,9 +474,10 @@ static int esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
return 0;
|
||||
|
||||
if (type == NDISC_REDIRECT)
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0);
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0,
|
||||
sock_net_uid(net, NULL));
|
||||
else
|
||||
ip6_update_pmtu(skb, net, info, 0, 0);
|
||||
ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
|
||||
xfrm_state_put(x);
|
||||
|
||||
return 0;
|
||||
|
@@ -92,9 +92,10 @@ static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
struct net *net = dev_net(skb->dev);
|
||||
|
||||
if (type == ICMPV6_PKT_TOOBIG)
|
||||
ip6_update_pmtu(skb, net, info, 0, 0);
|
||||
ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
|
||||
else if (type == NDISC_REDIRECT)
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0);
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0,
|
||||
sock_net_uid(net, NULL));
|
||||
|
||||
if (!(type & ICMPV6_INFOMSG_MASK))
|
||||
if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
|
||||
@@ -484,6 +485,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
|
||||
fl6.flowi6_oif = iif;
|
||||
fl6.fl6_icmp_type = type;
|
||||
fl6.fl6_icmp_code = code;
|
||||
fl6.flowi6_uid = sock_net_uid(net, NULL);
|
||||
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
|
||||
|
||||
sk = icmpv6_xmit_lock(net);
|
||||
@@ -658,6 +660,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
|
||||
fl6.flowi6_oif = skb->dev->ifindex;
|
||||
fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
|
||||
fl6.flowi6_mark = mark;
|
||||
fl6.flowi6_uid = sock_net_uid(net, NULL);
|
||||
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
|
||||
|
||||
sk = icmpv6_xmit_lock(net);
|
||||
|
@@ -88,6 +88,7 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk,
|
||||
fl6->flowi6_mark = ireq->ir_mark;
|
||||
fl6->fl6_dport = ireq->ir_rmt_port;
|
||||
fl6->fl6_sport = htons(ireq->ir_num);
|
||||
fl6->flowi6_uid = sk->sk_uid;
|
||||
security_req_classify_flow(req, flowi6_to_flowi(fl6));
|
||||
|
||||
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
|
||||
@@ -136,6 +137,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
|
||||
fl6->flowi6_mark = sk->sk_mark;
|
||||
fl6->fl6_sport = inet->inet_sport;
|
||||
fl6->fl6_dport = inet->inet_dport;
|
||||
fl6->flowi6_uid = sk->sk_uid;
|
||||
security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
|
||||
|
||||
rcu_read_lock();
|
||||
|
@@ -548,6 +548,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
|
||||
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
|
||||
fl6.flowi6_mark = skb->mark;
|
||||
|
||||
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
|
||||
|
||||
err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
|
||||
if (err)
|
||||
return -1;
|
||||
@@ -602,6 +604,8 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
|
||||
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
|
||||
fl6.flowi6_mark = skb->mark;
|
||||
|
||||
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
|
||||
|
||||
if (gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)))
|
||||
return -1;
|
||||
|
||||
|
@@ -1240,6 +1240,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
fl6.flowi6_mark = skb->mark;
|
||||
}
|
||||
|
||||
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
|
||||
|
||||
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
|
||||
return -1;
|
||||
|
||||
@@ -1318,6 +1320,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
fl6.flowi6_mark = skb->mark;
|
||||
}
|
||||
|
||||
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
|
||||
|
||||
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
|
||||
return -1;
|
||||
|
||||
|
@@ -608,9 +608,10 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
return 0;
|
||||
|
||||
if (type == NDISC_REDIRECT)
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0);
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0,
|
||||
sock_net_uid(net, NULL));
|
||||
else
|
||||
ip6_update_pmtu(skb, net, info, 0, 0);
|
||||
ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
|
||||
xfrm_state_put(x);
|
||||
|
||||
return 0;
|
||||
|
@@ -74,9 +74,10 @@ static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
return 0;
|
||||
|
||||
if (type == NDISC_REDIRECT)
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0);
|
||||
ip6_redirect(skb, net, skb->dev->ifindex, 0,
|
||||
sock_net_uid(net, NULL));
|
||||
else
|
||||
ip6_update_pmtu(skb, net, info, 0, 0);
|
||||
ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
|
||||
xfrm_state_put(x);
|
||||
|
||||
return 0;
|
||||
|
@@ -26,6 +26,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb)
|
||||
struct flowi6 fl6 = {
|
||||
.flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
|
||||
.flowi6_mark = skb->mark,
|
||||
.flowi6_uid = sock_net_uid(net, skb->sk),
|
||||
.daddr = iph->daddr,
|
||||
.saddr = iph->saddr,
|
||||
};
|
||||
|
@@ -113,6 +113,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
fl6.daddr = *daddr;
|
||||
fl6.flowi6_oif = oif;
|
||||
fl6.flowi6_mark = sk->sk_mark;
|
||||
fl6.flowi6_uid = sk->sk_uid;
|
||||
fl6.fl6_icmp_type = user_icmph.icmp6_type;
|
||||
fl6.fl6_icmp_code = user_icmph.icmp6_code;
|
||||
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
|
||||
|
@@ -776,6 +776,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
memset(&fl6, 0, sizeof(fl6));
|
||||
|
||||
fl6.flowi6_mark = sk->sk_mark;
|
||||
fl6.flowi6_uid = sk->sk_uid;
|
||||
|
||||
ipc6.hlimit = -1;
|
||||
ipc6.tclass = -1;
|
||||
|
@@ -1405,7 +1405,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
|
||||
}
|
||||
|
||||
void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
|
||||
int oif, u32 mark)
|
||||
int oif, u32 mark, kuid_t uid)
|
||||
{
|
||||
const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
|
||||
struct dst_entry *dst;
|
||||
@@ -1417,6 +1417,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
|
||||
fl6.daddr = iph->daddr;
|
||||
fl6.saddr = iph->saddr;
|
||||
fl6.flowlabel = ip6_flowinfo(iph);
|
||||
fl6.flowi6_uid = uid;
|
||||
|
||||
dst = ip6_route_output(net, NULL, &fl6);
|
||||
if (!dst->error)
|
||||
@@ -1430,7 +1431,7 @@ void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
|
||||
struct dst_entry *dst;
|
||||
|
||||
ip6_update_pmtu(skb, sock_net(sk), mtu,
|
||||
sk->sk_bound_dev_if, sk->sk_mark);
|
||||
sk->sk_bound_dev_if, sk->sk_mark, sk->sk_uid);
|
||||
|
||||
dst = __sk_dst_get(sk);
|
||||
if (!dst || !dst->obsolete ||
|
||||
@@ -1522,7 +1523,8 @@ static struct dst_entry *ip6_route_redirect(struct net *net,
|
||||
flags, __ip6_route_redirect);
|
||||
}
|
||||
|
||||
void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
|
||||
void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark,
|
||||
kuid_t uid)
|
||||
{
|
||||
const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data;
|
||||
struct dst_entry *dst;
|
||||
@@ -1535,6 +1537,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
|
||||
fl6.daddr = iph->daddr;
|
||||
fl6.saddr = iph->saddr;
|
||||
fl6.flowlabel = ip6_flowinfo(iph);
|
||||
fl6.flowi6_uid = uid;
|
||||
|
||||
dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr);
|
||||
rt6_do_redirect(dst, NULL, skb);
|
||||
@@ -1556,6 +1559,7 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
|
||||
fl6.flowi6_mark = mark;
|
||||
fl6.daddr = msg->dest;
|
||||
fl6.saddr = iph->daddr;
|
||||
fl6.flowi6_uid = sock_net_uid(net, NULL);
|
||||
|
||||
dst = ip6_route_redirect(net, &fl6, &iph->saddr);
|
||||
rt6_do_redirect(dst, NULL, skb);
|
||||
@@ -1564,7 +1568,8 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
|
||||
|
||||
void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
|
||||
{
|
||||
ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
|
||||
ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark,
|
||||
sk->sk_uid);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_sk_redirect);
|
||||
|
||||
|
@@ -227,6 +227,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
|
||||
fl6.flowi6_mark = ireq->ir_mark;
|
||||
fl6.fl6_dport = ireq->ir_rmt_port;
|
||||
fl6.fl6_sport = inet_sk(sk)->inet_sport;
|
||||
fl6.flowi6_uid = sk->sk_uid;
|
||||
security_req_classify_flow(req, flowi6_to_flowi(&fl6));
|
||||
|
||||
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
|
||||
|
@@ -233,6 +233,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
|
||||
fl6.flowi6_mark = sk->sk_mark;
|
||||
fl6.fl6_dport = usin->sin6_port;
|
||||
fl6.fl6_sport = inet->inet_sport;
|
||||
fl6.flowi6_uid = sk->sk_uid;
|
||||
|
||||
opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
|
||||
final_p = fl6_update_dst(&fl6, opt, &final);
|
||||
@@ -824,6 +825,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
|
||||
fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
|
||||
fl6.fl6_dport = t1->dest;
|
||||
fl6.fl6_sport = t1->source;
|
||||
fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL);
|
||||
security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
|
||||
|
||||
/* Pass a socket to ip6_dst_lookup either it is for RST
|
||||
|
@@ -1138,6 +1138,7 @@ do_udp_sendmsg:
|
||||
fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex;
|
||||
|
||||
fl6.flowi6_mark = sk->sk_mark;
|
||||
fl6.flowi6_uid = sk->sk_uid;
|
||||
sockc.tsflags = sk->sk_tsflags;
|
||||
|
||||
if (msg->msg_controllen) {
|
||||
|
Reference in New Issue
Block a user