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

Commit 4fb74506 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'uid-routing'



Lorenzo Colitti says:

====================
net: inet: Support UID-based routing

This patchset adds support for per-UID routing. It allows the
administrator to configure rules such as:

  ip rule add uidrange 100-200 lookup 123

This functionality has been in use by all Android devices since
5.0. It is primarily used to impose per-app routing policies (on
Android, every app has its own UID) without having to resort to
rerouting packets in iptables, which breaks getsockname() and
MTU/MSS calculation, and generally disrupts end-to-end
connectivity.

This patch series is similar to the code currently used on
Android, but has better correctness and performance because
it stores the UID in the socket instead of calling sock_i_uid.
This avoids contention on sk->sk_callback_lock, and makes it
possible to correctly route a socket on which userspace has
called close(), for which sock_i_uid will return 0.

Changes from v1:
- Don't set the UID in sk_clone_lock, it's already set by
  sock_copy.
- For packets originated by kernel sockets, don't use the socket
  UID. This is the UID that created the namespace, but it might
  not be mapped in the namespace at all. Instead, use UID 0 in
  the namespace, which is less surprising and consistent with
  what happens in the root namespace.
- Fix UID routing of IPv4 and IPv6 SYN_RECV sockets.
- Fix UID routing of received IPv6 redirects.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0d53072a e2d118a1
Loading
Loading
Loading
Loading
+8 −1
Original line number Original line Diff line number Diff line
@@ -8,6 +8,11 @@
#include <net/flow.h>
#include <net/flow.h>
#include <net/rtnetlink.h>
#include <net/rtnetlink.h>


struct fib_kuid_range {
	kuid_t start;
	kuid_t end;
};

struct fib_rule {
struct fib_rule {
	struct list_head	list;
	struct list_head	list;
	int			iifindex;
	int			iifindex;
@@ -30,6 +35,7 @@ struct fib_rule {
	int			suppress_prefixlen;
	int			suppress_prefixlen;
	char			iifname[IFNAMSIZ];
	char			iifname[IFNAMSIZ];
	char			oifname[IFNAMSIZ];
	char			oifname[IFNAMSIZ];
	struct fib_kuid_range	uid_range;
	struct rcu_head		rcu;
	struct rcu_head		rcu;
};
};


@@ -92,7 +98,8 @@ struct fib_rules_ops {
	[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
	[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
	[FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
	[FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
	[FRA_GOTO]	= { .type = NLA_U32 }, \
	[FRA_GOTO]	= { .type = NLA_U32 }, \
	[FRA_L3MDEV]	= { .type = NLA_U8 }
	[FRA_L3MDEV]	= { .type = NLA_U8 }, \
	[FRA_UID_RANGE]	= { .len = sizeof(struct fib_rule_uid_range) }


static inline void fib_rule_get(struct fib_rule *rule)
static inline void fib_rule_get(struct fib_rule *rule)
{
{
+8 −1
Original line number Original line Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/in6.h>
#include <linux/in6.h>
#include <linux/atomic.h>
#include <linux/atomic.h>
#include <net/flow_dissector.h>
#include <net/flow_dissector.h>
#include <linux/uidgid.h>


/*
/*
 * ifindex generation is per-net namespace, and loopback is
 * ifindex generation is per-net namespace, and loopback is
@@ -37,6 +38,7 @@ struct flowi_common {
#define FLOWI_FLAG_SKIP_NH_OIF		0x04
#define FLOWI_FLAG_SKIP_NH_OIF		0x04
	__u32	flowic_secid;
	__u32	flowic_secid;
	struct flowi_tunnel flowic_tun_key;
	struct flowi_tunnel flowic_tun_key;
	kuid_t  flowic_uid;
};
};


union flowi_uli {
union flowi_uli {
@@ -74,6 +76,7 @@ struct flowi4 {
#define flowi4_flags		__fl_common.flowic_flags
#define flowi4_flags		__fl_common.flowic_flags
#define flowi4_secid		__fl_common.flowic_secid
#define flowi4_secid		__fl_common.flowic_secid
#define flowi4_tun_key		__fl_common.flowic_tun_key
#define flowi4_tun_key		__fl_common.flowic_tun_key
#define flowi4_uid		__fl_common.flowic_uid


	/* (saddr,daddr) must be grouped, same order as in IP header */
	/* (saddr,daddr) must be grouped, same order as in IP header */
	__be32			saddr;
	__be32			saddr;
@@ -93,7 +96,8 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
				      __u32 mark, __u8 tos, __u8 scope,
				      __u32 mark, __u8 tos, __u8 scope,
				      __u8 proto, __u8 flags,
				      __u8 proto, __u8 flags,
				      __be32 daddr, __be32 saddr,
				      __be32 daddr, __be32 saddr,
				      __be16 dport, __be16 sport)
				      __be16 dport, __be16 sport,
				      kuid_t uid)
{
{
	fl4->flowi4_oif = oif;
	fl4->flowi4_oif = oif;
	fl4->flowi4_iif = LOOPBACK_IFINDEX;
	fl4->flowi4_iif = LOOPBACK_IFINDEX;
@@ -104,6 +108,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
	fl4->flowi4_flags = flags;
	fl4->flowi4_flags = flags;
	fl4->flowi4_secid = 0;
	fl4->flowi4_secid = 0;
	fl4->flowi4_tun_key.tun_id = 0;
	fl4->flowi4_tun_key.tun_id = 0;
	fl4->flowi4_uid = uid;
	fl4->daddr = daddr;
	fl4->daddr = daddr;
	fl4->saddr = saddr;
	fl4->saddr = saddr;
	fl4->fl4_dport = dport;
	fl4->fl4_dport = dport;
@@ -131,6 +136,7 @@ struct flowi6 {
#define flowi6_flags		__fl_common.flowic_flags
#define flowi6_flags		__fl_common.flowic_flags
#define flowi6_secid		__fl_common.flowic_secid
#define flowi6_secid		__fl_common.flowic_secid
#define flowi6_tun_key		__fl_common.flowic_tun_key
#define flowi6_tun_key		__fl_common.flowic_tun_key
#define flowi6_uid		__fl_common.flowic_uid
	struct in6_addr		daddr;
	struct in6_addr		daddr;
	struct in6_addr		saddr;
	struct in6_addr		saddr;
	/* Note: flowi6_tos is encoded in flowlabel, too. */
	/* Note: flowi6_tos is encoded in flowlabel, too. */
@@ -176,6 +182,7 @@ struct flowi {
#define flowi_flags	u.__fl_common.flowic_flags
#define flowi_flags	u.__fl_common.flowic_flags
#define flowi_secid	u.__fl_common.flowic_secid
#define flowi_secid	u.__fl_common.flowic_secid
#define flowi_tun_key	u.__fl_common.flowic_tun_key
#define flowi_tun_key	u.__fl_common.flowic_tun_key
#define flowi_uid	u.__fl_common.flowic_uid
} __attribute__((__aligned__(BITS_PER_LONG/8)));
} __attribute__((__aligned__(BITS_PER_LONG/8)));


static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
+1 −0
Original line number Original line Diff line number Diff line
@@ -179,6 +179,7 @@ struct ip_reply_arg {
				/* -1 if not needed */ 
				/* -1 if not needed */ 
	int	    bound_dev_if;
	int	    bound_dev_if;
	u8  	    tos;
	u8  	    tos;
	kuid_t	    uid;
}; 
}; 


#define IP_REPLY_ARG_NOSRCCHECK 1
#define IP_REPLY_ARG_NOSRCCHECK 1
+3 −2
Original line number Original line Diff line number Diff line
@@ -140,9 +140,10 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
		  const struct in6_addr *gwaddr);
		  const struct in6_addr *gwaddr);


void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif,
void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif,
		     u32 mark);
		     u32 mark, kuid_t uid);
void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu);
void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu);
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);
void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
			    u32 mark);
			    u32 mark);
void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk);
void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk);
+3 −2
Original line number Original line Diff line number Diff line
@@ -153,7 +153,7 @@ static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi
	flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos,
	flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos,
			   RT_SCOPE_UNIVERSE, proto,
			   RT_SCOPE_UNIVERSE, proto,
			   sk ? inet_sk_flowi_flags(sk) : 0,
			   sk ? inet_sk_flowi_flags(sk) : 0,
			   daddr, saddr, dport, sport);
			   daddr, saddr, dport, sport, sock_net_uid(net, sk));
	if (sk)
	if (sk)
		security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
		security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
	return ip_route_output_flow(net, fl4, sk);
	return ip_route_output_flow(net, fl4, sk);
@@ -269,7 +269,8 @@ static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32
		flow_flags |= FLOWI_FLAG_ANYSRC;
		flow_flags |= FLOWI_FLAG_ANYSRC;


	flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
	flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE,
			   protocol, flow_flags, dst, src, dport, sport);
			   protocol, flow_flags, dst, src, dport, sport,
			   sk->sk_uid);
}
}


static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
Loading