Skip to content

Commit

Permalink
xfrm: rework default policy structure
Browse files Browse the repository at this point in the history
[ Upstream commit b58b1f5 ]

This is a follow up of commit f8d858e ("xfrm: make user policy API
complete"). The goal is to align userland API to the internal structures.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by:  Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
NicolasDichtel authored and gregkh committed May 25, 2022
1 parent 57c1bbe commit 0d2e9d8
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 63 deletions.
6 changes: 1 addition & 5 deletions include/net/netns/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,7 @@ struct netns_xfrm {
int sysctl_larval_drop;
u32 sysctl_acq_expires;

u8 policy_default;
#define XFRM_POL_DEFAULT_IN 1
#define XFRM_POL_DEFAULT_OUT 2
#define XFRM_POL_DEFAULT_FWD 4
#define XFRM_POL_DEFAULT_MASK 7
u8 policy_default[XFRM_POLICY_MAX];

#ifdef CONFIG_SYSCTL
struct ctl_table_header *sysctl_hdr;
Expand Down
48 changes: 18 additions & 30 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1088,25 +1088,18 @@ xfrm_state_addr_cmp(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x, un
}

#ifdef CONFIG_XFRM
static inline bool
xfrm_default_allow(struct net *net, int dir)
{
u8 def = net->xfrm.policy_default;

switch (dir) {
case XFRM_POLICY_IN:
return def & XFRM_POL_DEFAULT_IN ? false : true;
case XFRM_POLICY_OUT:
return def & XFRM_POL_DEFAULT_OUT ? false : true;
case XFRM_POLICY_FWD:
return def & XFRM_POL_DEFAULT_FWD ? false : true;
}
return false;
}

int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb,
unsigned short family);

static inline bool __xfrm_check_nopolicy(struct net *net, struct sk_buff *skb,
int dir)
{
if (!net->xfrm.policy_count[dir] && !secpath_exists(skb))
return net->xfrm.policy_default[dir] == XFRM_USERPOLICY_ACCEPT;

return false;
}

static inline int __xfrm_policy_check2(struct sock *sk, int dir,
struct sk_buff *skb,
unsigned int family, int reverse)
Expand All @@ -1117,13 +1110,9 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir,
if (sk && sk->sk_policy[XFRM_POLICY_IN])
return __xfrm_policy_check(sk, ndir, skb, family);

if (xfrm_default_allow(net, dir))
return (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) ||
(skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
__xfrm_policy_check(sk, ndir, skb, family);
else
return (skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
__xfrm_policy_check(sk, ndir, skb, family);
return __xfrm_check_nopolicy(net, skb, dir) ||
(skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
__xfrm_policy_check(sk, ndir, skb, family);
}

static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family)
Expand Down Expand Up @@ -1175,13 +1164,12 @@ static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
{
struct net *net = dev_net(skb->dev);

if (xfrm_default_allow(net, XFRM_POLICY_OUT))
return !net->xfrm.policy_count[XFRM_POLICY_OUT] ||
(skb_dst(skb)->flags & DST_NOXFRM) ||
__xfrm_route_forward(skb, family);
else
return (skb_dst(skb)->flags & DST_NOXFRM) ||
__xfrm_route_forward(skb, family);
if (!net->xfrm.policy_count[XFRM_POLICY_OUT] &&
net->xfrm.policy_default[XFRM_POLICY_OUT] == XFRM_USERPOLICY_ACCEPT)
return true;

return (skb_dst(skb)->flags & DST_NOXFRM) ||
__xfrm_route_forward(skb, family);
}

static inline int xfrm4_route_forward(struct sk_buff *skb)
Expand Down
10 changes: 7 additions & 3 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3162,7 +3162,7 @@ struct dst_entry *xfrm_lookup_with_ifid(struct net *net,

nopol:
if (!(dst_orig->dev->flags & IFF_LOOPBACK) &&
!xfrm_default_allow(net, dir)) {
net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK) {
err = -EPERM;
goto error;
}
Expand Down Expand Up @@ -3613,7 +3613,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}

if (!pol) {
if (!xfrm_default_allow(net, dir)) {
if (net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
return 0;
}
Expand Down Expand Up @@ -3673,7 +3673,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}
xfrm_nr = ti;

if (!xfrm_default_allow(net, dir) && !xfrm_nr) {
if (net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK &&
!xfrm_nr) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
goto reject;
}
Expand Down Expand Up @@ -4162,6 +4163,9 @@ static int __net_init xfrm_net_init(struct net *net)
spin_lock_init(&net->xfrm.xfrm_policy_lock);
seqcount_spinlock_init(&net->xfrm.xfrm_policy_hash_generation, &net->xfrm.xfrm_policy_lock);
mutex_init(&net->xfrm.xfrm_cfg_mutex);
net->xfrm.policy_default[XFRM_POLICY_IN] = XFRM_USERPOLICY_ACCEPT;
net->xfrm.policy_default[XFRM_POLICY_FWD] = XFRM_USERPOLICY_ACCEPT;
net->xfrm.policy_default[XFRM_POLICY_OUT] = XFRM_USERPOLICY_ACCEPT;

rv = xfrm_statistics_init(net);
if (rv < 0)
Expand Down
43 changes: 18 additions & 25 deletions net/xfrm/xfrm_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -1932,38 +1932,35 @@ static int xfrm_notify_userpolicy(struct net *net)
}

up = nlmsg_data(nlh);
up->in = net->xfrm.policy_default & XFRM_POL_DEFAULT_IN ?
XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
up->fwd = net->xfrm.policy_default & XFRM_POL_DEFAULT_FWD ?
XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
up->out = net->xfrm.policy_default & XFRM_POL_DEFAULT_OUT ?
XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
up->in = net->xfrm.policy_default[XFRM_POLICY_IN];
up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD];
up->out = net->xfrm.policy_default[XFRM_POLICY_OUT];

nlmsg_end(skb, nlh);

return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
}

static bool xfrm_userpolicy_is_valid(__u8 policy)
{
return policy == XFRM_USERPOLICY_BLOCK ||
policy == XFRM_USERPOLICY_ACCEPT;
}

static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
{
struct net *net = sock_net(skb->sk);
struct xfrm_userpolicy_default *up = nlmsg_data(nlh);

if (up->in == XFRM_USERPOLICY_BLOCK)
net->xfrm.policy_default |= XFRM_POL_DEFAULT_IN;
else if (up->in == XFRM_USERPOLICY_ACCEPT)
net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_IN;
if (xfrm_userpolicy_is_valid(up->in))
net->xfrm.policy_default[XFRM_POLICY_IN] = up->in;

if (up->fwd == XFRM_USERPOLICY_BLOCK)
net->xfrm.policy_default |= XFRM_POL_DEFAULT_FWD;
else if (up->fwd == XFRM_USERPOLICY_ACCEPT)
net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_FWD;
if (xfrm_userpolicy_is_valid(up->fwd))
net->xfrm.policy_default[XFRM_POLICY_FWD] = up->fwd;

if (up->out == XFRM_USERPOLICY_BLOCK)
net->xfrm.policy_default |= XFRM_POL_DEFAULT_OUT;
else if (up->out == XFRM_USERPOLICY_ACCEPT)
net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_OUT;
if (xfrm_userpolicy_is_valid(up->out))
net->xfrm.policy_default[XFRM_POLICY_OUT] = up->out;

rt_genid_bump_all(net);

Expand Down Expand Up @@ -1993,13 +1990,9 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,
}

r_up = nlmsg_data(r_nlh);

r_up->in = net->xfrm.policy_default & XFRM_POL_DEFAULT_IN ?
XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
r_up->fwd = net->xfrm.policy_default & XFRM_POL_DEFAULT_FWD ?
XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
r_up->out = net->xfrm.policy_default & XFRM_POL_DEFAULT_OUT ?
XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT;
r_up->in = net->xfrm.policy_default[XFRM_POLICY_IN];
r_up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD];
r_up->out = net->xfrm.policy_default[XFRM_POLICY_OUT];
nlmsg_end(r_skb, r_nlh);

return nlmsg_unicast(net->xfrm.nlsk, r_skb, portid);
Expand Down

0 comments on commit 0d2e9d8

Please sign in to comment.