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
@@ -425,6 +425,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
||||
fl4.daddr = daddr;
|
||||
fl4.saddr = saddr;
|
||||
fl4.flowi4_mark = mark;
|
||||
fl4.flowi4_uid = sock_net_uid(net, NULL);
|
||||
fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
|
||||
fl4.flowi4_proto = IPPROTO_ICMP;
|
||||
fl4.flowi4_oif = l3mdev_master_ifindex(skb->dev);
|
||||
@@ -473,6 +474,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
|
||||
param->replyopts.opt.opt.faddr : iph->saddr);
|
||||
fl4->saddr = saddr;
|
||||
fl4->flowi4_mark = mark;
|
||||
fl4->flowi4_uid = sock_net_uid(net, NULL);
|
||||
fl4->flowi4_tos = RT_TOS(tos);
|
||||
fl4->flowi4_proto = IPPROTO_ICMP;
|
||||
fl4->fl4_icmp_type = type;
|
||||
|
@@ -415,7 +415,7 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk,
|
||||
sk->sk_protocol, inet_sk_flowi_flags(sk),
|
||||
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
|
||||
ireq->ir_loc_addr, ireq->ir_rmt_port,
|
||||
htons(ireq->ir_num));
|
||||
htons(ireq->ir_num), sk->sk_uid);
|
||||
security_req_classify_flow(req, flowi4_to_flowi(fl4));
|
||||
rt = ip_route_output_flow(net, fl4, sk);
|
||||
if (IS_ERR(rt))
|
||||
@@ -452,7 +452,7 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk,
|
||||
sk->sk_protocol, inet_sk_flowi_flags(sk),
|
||||
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
|
||||
ireq->ir_loc_addr, ireq->ir_rmt_port,
|
||||
htons(ireq->ir_num));
|
||||
htons(ireq->ir_num), sk->sk_uid);
|
||||
security_req_classify_flow(req, flowi4_to_flowi(fl4));
|
||||
rt = ip_route_output_flow(net, fl4, sk);
|
||||
if (IS_ERR(rt))
|
||||
|
@@ -1587,7 +1587,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
|
||||
RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol,
|
||||
ip_reply_arg_flowi_flags(arg),
|
||||
daddr, saddr,
|
||||
tcp_hdr(skb)->source, tcp_hdr(skb)->dest);
|
||||
tcp_hdr(skb)->source, tcp_hdr(skb)->dest,
|
||||
arg->uid);
|
||||
security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
|
||||
rt = ip_route_output_key(net, &fl4);
|
||||
if (IS_ERR(rt))
|
||||
|
@@ -789,7 +789,8 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
|
||||
flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
|
||||
RT_SCOPE_UNIVERSE, sk->sk_protocol,
|
||||
inet_sk_flowi_flags(sk), faddr, saddr, 0, 0);
|
||||
inet_sk_flowi_flags(sk), faddr, saddr, 0, 0,
|
||||
sk->sk_uid);
|
||||
|
||||
security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
|
||||
rt = ip_route_output_flow(net, &fl4, sk);
|
||||
|
@@ -606,7 +606,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
|
||||
inet_sk_flowi_flags(sk) |
|
||||
(inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
|
||||
daddr, saddr, 0, 0);
|
||||
daddr, saddr, 0, 0, sk->sk_uid);
|
||||
|
||||
if (!inet->hdrincl) {
|
||||
rfv.msg = msg;
|
||||
|
@@ -507,7 +507,8 @@ void __ip_select_ident(struct net *net, struct iphdr *iph, int segs)
|
||||
}
|
||||
EXPORT_SYMBOL(__ip_select_ident);
|
||||
|
||||
static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk,
|
||||
static void __build_flow_key(const struct net *net, struct flowi4 *fl4,
|
||||
const struct sock *sk,
|
||||
const struct iphdr *iph,
|
||||
int oif, u8 tos,
|
||||
u8 prot, u32 mark, int flow_flags)
|
||||
@@ -523,7 +524,8 @@ static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk,
|
||||
flowi4_init_output(fl4, oif, mark, tos,
|
||||
RT_SCOPE_UNIVERSE, prot,
|
||||
flow_flags,
|
||||
iph->daddr, iph->saddr, 0, 0);
|
||||
iph->daddr, iph->saddr, 0, 0,
|
||||
sock_net_uid(net, sk));
|
||||
}
|
||||
|
||||
static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb,
|
||||
@@ -535,7 +537,7 @@ static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb,
|
||||
u8 prot = iph->protocol;
|
||||
u32 mark = skb->mark;
|
||||
|
||||
__build_flow_key(fl4, sk, iph, oif, tos, prot, mark, 0);
|
||||
__build_flow_key(sock_net(sk), fl4, sk, iph, oif, tos, prot, mark, 0);
|
||||
}
|
||||
|
||||
static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk)
|
||||
@@ -552,7 +554,7 @@ static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk)
|
||||
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
|
||||
inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
|
||||
inet_sk_flowi_flags(sk),
|
||||
daddr, inet->inet_saddr, 0, 0);
|
||||
daddr, inet->inet_saddr, 0, 0, sk->sk_uid);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@@ -800,7 +802,7 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf
|
||||
|
||||
rt = (struct rtable *) dst;
|
||||
|
||||
__build_flow_key(&fl4, sk, iph, oif, tos, prot, mark, 0);
|
||||
__build_flow_key(sock_net(sk), &fl4, sk, iph, oif, tos, prot, mark, 0);
|
||||
__ip_do_redirect(rt, skb, &fl4, true);
|
||||
}
|
||||
|
||||
@@ -1018,7 +1020,7 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
|
||||
if (!mark)
|
||||
mark = IP4_REPLY_MARK(net, skb->mark);
|
||||
|
||||
__build_flow_key(&fl4, NULL, iph, oif,
|
||||
__build_flow_key(net, &fl4, NULL, iph, oif,
|
||||
RT_TOS(iph->tos), protocol, mark, flow_flags);
|
||||
rt = __ip_route_output_key(net, &fl4);
|
||||
if (!IS_ERR(rt)) {
|
||||
@@ -1034,7 +1036,7 @@ static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
|
||||
struct flowi4 fl4;
|
||||
struct rtable *rt;
|
||||
|
||||
__build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0);
|
||||
__build_flow_key(sock_net(sk), &fl4, sk, iph, 0, 0, 0, 0, 0);
|
||||
|
||||
if (!fl4.flowi4_mark)
|
||||
fl4.flowi4_mark = IP4_REPLY_MARK(sock_net(sk), skb->mark);
|
||||
@@ -1053,6 +1055,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
|
||||
struct rtable *rt;
|
||||
struct dst_entry *odst = NULL;
|
||||
bool new = false;
|
||||
struct net *net = sock_net(sk);
|
||||
|
||||
bh_lock_sock(sk);
|
||||
|
||||
@@ -1066,7 +1069,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
|
||||
goto out;
|
||||
}
|
||||
|
||||
__build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0);
|
||||
__build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0);
|
||||
|
||||
rt = (struct rtable *)odst;
|
||||
if (odst->obsolete && !odst->ops->check(odst, 0)) {
|
||||
@@ -1106,7 +1109,7 @@ void ipv4_redirect(struct sk_buff *skb, struct net *net,
|
||||
struct flowi4 fl4;
|
||||
struct rtable *rt;
|
||||
|
||||
__build_flow_key(&fl4, NULL, iph, oif,
|
||||
__build_flow_key(net, &fl4, NULL, iph, oif,
|
||||
RT_TOS(iph->tos), protocol, mark, flow_flags);
|
||||
rt = __ip_route_output_key(net, &fl4);
|
||||
if (!IS_ERR(rt)) {
|
||||
@@ -1121,9 +1124,10 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk)
|
||||
const struct iphdr *iph = (const struct iphdr *) skb->data;
|
||||
struct flowi4 fl4;
|
||||
struct rtable *rt;
|
||||
struct net *net = sock_net(sk);
|
||||
|
||||
__build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0);
|
||||
rt = __ip_route_output_key(sock_net(sk), &fl4);
|
||||
__build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0);
|
||||
rt = __ip_route_output_key(net, &fl4);
|
||||
if (!IS_ERR(rt)) {
|
||||
__ip_do_redirect(rt, skb, &fl4, false);
|
||||
ip_rt_put(rt);
|
||||
|
@@ -372,7 +372,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
|
||||
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP,
|
||||
inet_sk_flowi_flags(sk),
|
||||
opt->srr ? opt->faddr : ireq->ir_rmt_addr,
|
||||
ireq->ir_loc_addr, th->source, th->dest);
|
||||
ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid);
|
||||
security_req_classify_flow(req, flowi4_to_flowi(&fl4));
|
||||
rt = ip_route_output_key(sock_net(sk), &fl4);
|
||||
if (IS_ERR(rt)) {
|
||||
|
@@ -691,6 +691,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
|
||||
offsetof(struct inet_timewait_sock, tw_bound_dev_if));
|
||||
|
||||
arg.tos = ip_hdr(skb)->tos;
|
||||
arg.uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL);
|
||||
local_bh_disable();
|
||||
ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
|
||||
skb, &TCP_SKB_CB(skb)->header.h4.opt,
|
||||
@@ -711,7 +712,7 @@ out:
|
||||
outside socket context is ugly, certainly. What can I do?
|
||||
*/
|
||||
|
||||
static void tcp_v4_send_ack(struct net *net,
|
||||
static void tcp_v4_send_ack(const struct sock *sk,
|
||||
struct sk_buff *skb, u32 seq, u32 ack,
|
||||
u32 win, u32 tsval, u32 tsecr, int oif,
|
||||
struct tcp_md5sig_key *key,
|
||||
@@ -726,6 +727,7 @@ static void tcp_v4_send_ack(struct net *net,
|
||||
#endif
|
||||
];
|
||||
} rep;
|
||||
struct net *net = sock_net(sk);
|
||||
struct ip_reply_arg arg;
|
||||
|
||||
memset(&rep.th, 0, sizeof(struct tcphdr));
|
||||
@@ -775,6 +777,7 @@ static void tcp_v4_send_ack(struct net *net,
|
||||
if (oif)
|
||||
arg.bound_dev_if = oif;
|
||||
arg.tos = tos;
|
||||
arg.uid = sock_net_uid(net, sk_fullsock(sk) ? sk : NULL);
|
||||
local_bh_disable();
|
||||
ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
|
||||
skb, &TCP_SKB_CB(skb)->header.h4.opt,
|
||||
@@ -790,7 +793,7 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
|
||||
struct inet_timewait_sock *tw = inet_twsk(sk);
|
||||
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
|
||||
|
||||
tcp_v4_send_ack(sock_net(sk), skb,
|
||||
tcp_v4_send_ack(sk, skb,
|
||||
tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
|
||||
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
|
||||
tcp_time_stamp + tcptw->tw_ts_offset,
|
||||
@@ -818,7 +821,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
|
||||
* exception of <SYN> segments, MUST be right-shifted by
|
||||
* Rcv.Wind.Shift bits:
|
||||
*/
|
||||
tcp_v4_send_ack(sock_net(sk), skb, seq,
|
||||
tcp_v4_send_ack(sk, skb, seq,
|
||||
tcp_rsk(req)->rcv_nxt,
|
||||
req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
|
||||
tcp_time_stamp,
|
||||
|
@@ -1019,7 +1019,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos,
|
||||
RT_SCOPE_UNIVERSE, sk->sk_protocol,
|
||||
flow_flags,
|
||||
faddr, saddr, dport, inet->inet_sport);
|
||||
faddr, saddr, dport, inet->inet_sport,
|
||||
sk->sk_uid);
|
||||
|
||||
security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
|
||||
rt = ip_route_output_flow(net, fl4, sk);
|
||||
|
Reference in New Issue
Block a user