UPSTREAM: xfrm: fix "disable_policy" flag use when arriving from different devices
[ Upstream commit e6175a2ed1f18bf2f649625bf725e07adcfa6a28 ] In IPv4 setting the "disable_policy" flag on a device means no policy should be enforced for traffic originating from the device. This was implemented by seting the DST_NOPOLICY flag in the dst based on the originating device. However, dsts are cached in nexthops regardless of the originating devices, in which case, the DST_NOPOLICY flag value may be incorrect. Consider the following setup: +------------------------------+ | ROUTER | +-------------+ | +-----------------+ | | ipsec src |----|-|ipsec0 | | +-------------+ | |disable_policy=0 | +----+ | | +-----------------+ |eth1|-|----- +-------------+ | +-----------------+ +----+ | | noipsec src |----|-|eth0 | | +-------------+ | |disable_policy=1 | | | +-----------------+ | +------------------------------+ Where ROUTER has a default route towards eth1. dst entries for traffic arriving from eth0 would have DST_NOPOLICY and would be cached and therefore can be reused by traffic originating from ipsec0, skipping policy check. Fix by setting a IPSKB_NOPOLICY flag in IPCB and observing it instead of the DST in IN/FWD IPv4 policy checks. Fixes:1da177e4c3
("Linux-2.6.12-rc2") Reported-by: Shmulik Ladkani <shmulik.ladkani@gmail.com> Signed-off-by: Eyal Birger <eyal.birger@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Sasha Levin <sashal@kernel.org> (cherry picked from commit952c246496
) Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ib99071ce487325fd9c3646ca77dd682128feeb7c
This commit is contained in:
parent
6508a3753c
commit
9a526b9527
|
@ -55,6 +55,7 @@ struct inet_skb_parm {
|
|||
#define IPSKB_DOREDIRECT BIT(5)
|
||||
#define IPSKB_FRAG_PMTU BIT(6)
|
||||
#define IPSKB_L3SLAVE BIT(7)
|
||||
#define IPSKB_NOPOLICY BIT(8)
|
||||
|
||||
u16 frag_max_size;
|
||||
};
|
||||
|
|
|
@ -1092,6 +1092,18 @@ static inline bool __xfrm_check_nopolicy(struct net *net, struct sk_buff *skb,
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool __xfrm_check_dev_nopolicy(struct sk_buff *skb,
|
||||
int dir, unsigned short family)
|
||||
{
|
||||
if (dir != XFRM_POLICY_OUT && family == AF_INET) {
|
||||
/* same dst may be used for traffic originating from
|
||||
* devices with different policy settings.
|
||||
*/
|
||||
return IPCB(skb)->flags & IPSKB_NOPOLICY;
|
||||
}
|
||||
return skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY);
|
||||
}
|
||||
|
||||
static inline int __xfrm_policy_check2(struct sock *sk, int dir,
|
||||
struct sk_buff *skb,
|
||||
unsigned int family, int reverse)
|
||||
|
@ -1103,7 +1115,7 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir,
|
|||
return __xfrm_policy_check(sk, ndir, skb, family);
|
||||
|
||||
return __xfrm_check_nopolicy(net, skb, dir) ||
|
||||
(skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
|
||||
__xfrm_check_dev_nopolicy(skb, dir, family) ||
|
||||
__xfrm_policy_check(sk, ndir, skb, family);
|
||||
}
|
||||
|
||||
|
|
|
@ -1727,6 +1727,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||
unsigned int flags = RTCF_MULTICAST;
|
||||
struct rtable *rth;
|
||||
bool no_policy;
|
||||
u32 itag = 0;
|
||||
int err;
|
||||
|
||||
|
@ -1737,8 +1738,12 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
if (our)
|
||||
flags |= RTCF_LOCAL;
|
||||
|
||||
no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY);
|
||||
if (no_policy)
|
||||
IPCB(skb)->flags |= IPSKB_NOPOLICY;
|
||||
|
||||
rth = rt_dst_alloc(dev_net(dev)->loopback_dev, flags, RTN_MULTICAST,
|
||||
IN_DEV_ORCONF(in_dev, NOPOLICY), false);
|
||||
no_policy, false);
|
||||
if (!rth)
|
||||
return -ENOBUFS;
|
||||
|
||||
|
@ -1797,7 +1802,7 @@ static int __mkroute_input(struct sk_buff *skb,
|
|||
struct rtable *rth;
|
||||
int err;
|
||||
struct in_device *out_dev;
|
||||
bool do_cache;
|
||||
bool do_cache, no_policy;
|
||||
u32 itag = 0;
|
||||
|
||||
/* get a working reference to the output device */
|
||||
|
@ -1842,6 +1847,10 @@ static int __mkroute_input(struct sk_buff *skb,
|
|||
}
|
||||
}
|
||||
|
||||
no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY);
|
||||
if (no_policy)
|
||||
IPCB(skb)->flags |= IPSKB_NOPOLICY;
|
||||
|
||||
fnhe = find_exception(nhc, daddr);
|
||||
if (do_cache) {
|
||||
if (fnhe)
|
||||
|
@ -1854,8 +1863,7 @@ static int __mkroute_input(struct sk_buff *skb,
|
|||
}
|
||||
}
|
||||
|
||||
rth = rt_dst_alloc(out_dev->dev, 0, res->type,
|
||||
IN_DEV_ORCONF(in_dev, NOPOLICY),
|
||||
rth = rt_dst_alloc(out_dev->dev, 0, res->type, no_policy,
|
||||
IN_DEV_ORCONF(out_dev, NOXFRM));
|
||||
if (!rth) {
|
||||
err = -ENOBUFS;
|
||||
|
@ -2230,6 +2238,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
struct rtable *rth;
|
||||
struct flowi4 fl4;
|
||||
bool do_cache = true;
|
||||
bool no_policy;
|
||||
|
||||
/* IP on this device is disabled. */
|
||||
|
||||
|
@ -2347,6 +2356,10 @@ out: return err;
|
|||
RT_CACHE_STAT_INC(in_brd);
|
||||
|
||||
local_input:
|
||||
no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY);
|
||||
if (no_policy)
|
||||
IPCB(skb)->flags |= IPSKB_NOPOLICY;
|
||||
|
||||
do_cache &= res->fi && !itag;
|
||||
if (do_cache) {
|
||||
struct fib_nh_common *nhc = FIB_RES_NHC(*res);
|
||||
|
@ -2361,7 +2374,7 @@ out: return err;
|
|||
|
||||
rth = rt_dst_alloc(ip_rt_get_dev(net, res),
|
||||
flags | RTCF_LOCAL, res->type,
|
||||
IN_DEV_ORCONF(in_dev, NOPOLICY), false);
|
||||
no_policy, false);
|
||||
if (!rth)
|
||||
goto e_nobufs;
|
||||
|
||||
|
|
Loading…
Reference in New Issue