Skip to content

Commit 2d151d3

Browse files
committed
xfrm: Add possibility to set the default to block if we have no policy
As the default we assume the traffic to pass, if we have no matching IPsec policy. With this patch, we have a possibility to change this default from allow to block. It can be configured via netlink. Each direction (input/output/forward) can be configured separately. With the default to block configuered, we need allow policies for all packet flows we accept. We do not use default policy lookup for the loopback device. v1->v2 - fix compiling when XFRM is disabled - Reported-by: kernel test robot <[email protected]> Co-developed-by: Christian Langrock <[email protected]> Signed-off-by: Christian Langrock <[email protected]> Co-developed-by: Antony Antony <[email protected]> Signed-off-by: Antony Antony <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent f8fdade commit 2d151d3

File tree

5 files changed

+115
-6
lines changed

5 files changed

+115
-6
lines changed

include/net/netns/xfrm.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ struct netns_xfrm {
6565
u32 sysctl_aevent_rseqth;
6666
int sysctl_larval_drop;
6767
u32 sysctl_acq_expires;
68+
69+
u8 policy_default;
70+
#define XFRM_POL_DEFAULT_IN 1
71+
#define XFRM_POL_DEFAULT_OUT 2
72+
#define XFRM_POL_DEFAULT_FWD 4
73+
#define XFRM_POL_DEFAULT_MASK 7
74+
6875
#ifdef CONFIG_SYSCTL
6976
struct ctl_table_header *sysctl_hdr;
7077
#endif

include/net/xfrm.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,22 @@ xfrm_state_addr_cmp(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x, un
10751075
}
10761076

10771077
#ifdef CONFIG_XFRM
1078+
static inline bool
1079+
xfrm_default_allow(struct net *net, int dir)
1080+
{
1081+
u8 def = net->xfrm.policy_default;
1082+
1083+
switch (dir) {
1084+
case XFRM_POLICY_IN:
1085+
return def & XFRM_POL_DEFAULT_IN ? false : true;
1086+
case XFRM_POLICY_OUT:
1087+
return def & XFRM_POL_DEFAULT_OUT ? false : true;
1088+
case XFRM_POLICY_FWD:
1089+
return def & XFRM_POL_DEFAULT_FWD ? false : true;
1090+
}
1091+
return false;
1092+
}
1093+
10781094
int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb,
10791095
unsigned short family);
10801096

@@ -1088,9 +1104,13 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir,
10881104
if (sk && sk->sk_policy[XFRM_POLICY_IN])
10891105
return __xfrm_policy_check(sk, ndir, skb, family);
10901106

1091-
return (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) ||
1092-
(skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
1093-
__xfrm_policy_check(sk, ndir, skb, family);
1107+
if (xfrm_default_allow(net, dir))
1108+
return (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) ||
1109+
(skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
1110+
__xfrm_policy_check(sk, ndir, skb, family);
1111+
else
1112+
return (skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
1113+
__xfrm_policy_check(sk, ndir, skb, family);
10941114
}
10951115

10961116
static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family)
@@ -1142,9 +1162,13 @@ static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
11421162
{
11431163
struct net *net = dev_net(skb->dev);
11441164

1145-
return !net->xfrm.policy_count[XFRM_POLICY_OUT] ||
1146-
(skb_dst(skb)->flags & DST_NOXFRM) ||
1147-
__xfrm_route_forward(skb, family);
1165+
if (xfrm_default_allow(net, XFRM_POLICY_FWD))
1166+
return !net->xfrm.policy_count[XFRM_POLICY_OUT] ||
1167+
(skb_dst(skb)->flags & DST_NOXFRM) ||
1168+
__xfrm_route_forward(skb, family);
1169+
else
1170+
return (skb_dst(skb)->flags & DST_NOXFRM) ||
1171+
__xfrm_route_forward(skb, family);
11481172
}
11491173

11501174
static inline int xfrm4_route_forward(struct sk_buff *skb)

include/uapi/linux/xfrm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,11 @@ enum {
213213
XFRM_MSG_GETSPDINFO,
214214
#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
215215

216+
XFRM_MSG_SETDEFAULT,
217+
#define XFRM_MSG_SETDEFAULT XFRM_MSG_SETDEFAULT
218+
XFRM_MSG_GETDEFAULT,
219+
#define XFRM_MSG_GETDEFAULT XFRM_MSG_GETDEFAULT
220+
216221
XFRM_MSG_MAPPING,
217222
#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING
218223
__XFRM_MSG_MAX
@@ -508,6 +513,11 @@ struct xfrm_user_offload {
508513
#define XFRM_OFFLOAD_IPV6 1
509514
#define XFRM_OFFLOAD_INBOUND 2
510515

516+
struct xfrm_userpolicy_default {
517+
__u8 dirmask;
518+
__u8 action;
519+
};
520+
511521
#ifndef __KERNEL__
512522
/* backwards compatibility for userspace */
513523
#define XFRMGRP_ACQUIRE 1

net/xfrm/xfrm_policy.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3165,6 +3165,11 @@ struct dst_entry *xfrm_lookup_with_ifid(struct net *net,
31653165
return dst;
31663166

31673167
nopol:
3168+
if (!(dst_orig->dev->flags & IFF_LOOPBACK) &&
3169+
!xfrm_default_allow(net, dir)) {
3170+
err = -EPERM;
3171+
goto error;
3172+
}
31683173
if (!(flags & XFRM_LOOKUP_ICMP)) {
31693174
dst = dst_orig;
31703175
goto ok;
@@ -3553,6 +3558,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
35533558
}
35543559

35553560
if (!pol) {
3561+
if (!xfrm_default_allow(net, dir)) {
3562+
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
3563+
return 0;
3564+
}
3565+
35563566
if (sp && secpath_has_nontransport(sp, 0, &xerr_idx)) {
35573567
xfrm_secpath_reject(xerr_idx, skb, &fl);
35583568
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
@@ -3607,6 +3617,12 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
36073617
tpp[ti++] = &pols[pi]->xfrm_vec[i];
36083618
}
36093619
xfrm_nr = ti;
3620+
3621+
if (!xfrm_default_allow(net, dir) && !xfrm_nr) {
3622+
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
3623+
goto reject;
3624+
}
3625+
36103626
if (npols > 1) {
36113627
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
36123628
tpp = stp;

net/xfrm/xfrm_user.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,54 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
19611961
return skb;
19621962
}
19631963

1964+
static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,
1965+
struct nlattr **attrs)
1966+
{
1967+
struct net *net = sock_net(skb->sk);
1968+
struct xfrm_userpolicy_default *up = nlmsg_data(nlh);
1969+
u8 dirmask = (1 << up->dirmask) & XFRM_POL_DEFAULT_MASK;
1970+
u8 old_default = net->xfrm.policy_default;
1971+
1972+
net->xfrm.policy_default = (old_default & (0xff ^ dirmask))
1973+
| (up->action << up->dirmask);
1974+
1975+
rt_genid_bump_all(net);
1976+
1977+
return 0;
1978+
}
1979+
1980+
static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,
1981+
struct nlattr **attrs)
1982+
{
1983+
struct sk_buff *r_skb;
1984+
struct nlmsghdr *r_nlh;
1985+
struct net *net = sock_net(skb->sk);
1986+
struct xfrm_userpolicy_default *r_up, *up;
1987+
int len = NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_default));
1988+
u32 portid = NETLINK_CB(skb).portid;
1989+
u32 seq = nlh->nlmsg_seq;
1990+
1991+
up = nlmsg_data(nlh);
1992+
1993+
r_skb = nlmsg_new(len, GFP_ATOMIC);
1994+
if (!r_skb)
1995+
return -ENOMEM;
1996+
1997+
r_nlh = nlmsg_put(r_skb, portid, seq, XFRM_MSG_GETDEFAULT, sizeof(*r_up), 0);
1998+
if (!r_nlh) {
1999+
kfree_skb(r_skb);
2000+
return -EMSGSIZE;
2001+
}
2002+
2003+
r_up = nlmsg_data(r_nlh);
2004+
2005+
r_up->action = ((net->xfrm.policy_default & (1 << up->dirmask)) >> up->dirmask);
2006+
r_up->dirmask = up->dirmask;
2007+
nlmsg_end(r_skb, r_nlh);
2008+
2009+
return nlmsg_unicast(net->xfrm.nlsk, r_skb, portid);
2010+
}
2011+
19642012
static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
19652013
struct nlattr **attrs)
19662014
{
@@ -2664,6 +2712,8 @@ const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
26642712
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),
26652713
[XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
26662714
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
2715+
[XFRM_MSG_SETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
2716+
[XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
26672717
};
26682718
EXPORT_SYMBOL_GPL(xfrm_msg_min);
26692719

@@ -2743,6 +2793,8 @@ static const struct xfrm_link {
27432793
.nla_pol = xfrma_spd_policy,
27442794
.nla_max = XFRMA_SPD_MAX },
27452795
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
2796+
[XFRM_MSG_SETDEFAULT - XFRM_MSG_BASE] = { .doit = xfrm_set_default },
2797+
[XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = { .doit = xfrm_get_default },
27462798
};
27472799

27482800
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,

0 commit comments

Comments
 (0)