Skip to content

Commit b35560e

Browse files
committed
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2019-02-21 1) Don't do TX bytes accounting for the esp trailer when sending from a request socket as this will result in an out of bounds memory write. From Martin Willi. 2) Destroy xfrm_state synchronously on net exit path to avoid nested gc flush callbacks that may trigger a warning in xfrm6_tunnel_net_exit(). From Cong Wang. 3) Do an unconditionally clone in pfkey_broadcast_one() to avoid a race when freeing the skb. From Sean Tranchetti. 4) Fix inbound traffic via XFRM interfaces across network namespaces. We did the lookup for interfaces and policies in the wrong namespace. From Tobias Brunner. Please pull or let me know if there are problems. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 31088cb + 660899d commit b35560e

File tree

9 files changed

+53
-47
lines changed

9 files changed

+53
-47
lines changed

include/net/xfrm.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols)
853853
xfrm_pol_put(pols[i]);
854854
}
855855

856-
void __xfrm_state_destroy(struct xfrm_state *);
856+
void __xfrm_state_destroy(struct xfrm_state *, bool);
857857

858858
static inline void __xfrm_state_put(struct xfrm_state *x)
859859
{
@@ -863,7 +863,13 @@ static inline void __xfrm_state_put(struct xfrm_state *x)
863863
static inline void xfrm_state_put(struct xfrm_state *x)
864864
{
865865
if (refcount_dec_and_test(&x->refcnt))
866-
__xfrm_state_destroy(x);
866+
__xfrm_state_destroy(x, false);
867+
}
868+
869+
static inline void xfrm_state_put_sync(struct xfrm_state *x)
870+
{
871+
if (refcount_dec_and_test(&x->refcnt))
872+
__xfrm_state_destroy(x, true);
867873
}
868874

869875
static inline void xfrm_state_hold(struct xfrm_state *x)
@@ -1590,7 +1596,7 @@ struct xfrmk_spdinfo {
15901596

15911597
struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
15921598
int xfrm_state_delete(struct xfrm_state *x);
1593-
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid);
1599+
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync);
15941600
int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid);
15951601
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
15961602
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);

net/ipv4/esp4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
328328
skb->len += tailen;
329329
skb->data_len += tailen;
330330
skb->truesize += tailen;
331-
if (sk)
331+
if (sk && sk_fullsock(sk))
332332
refcount_add(tailen, &sk->sk_wmem_alloc);
333333

334334
goto out;

net/ipv6/esp6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
296296
skb->len += tailen;
297297
skb->data_len += tailen;
298298
skb->truesize += tailen;
299-
if (sk)
299+
if (sk && sk_fullsock(sk))
300300
refcount_add(tailen, &sk->sk_wmem_alloc);
301301

302302
goto out;

net/ipv6/xfrm6_tunnel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
344344
struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
345345
unsigned int i;
346346

347-
xfrm_state_flush(net, IPSEC_PROTO_ANY, false);
348347
xfrm_flush_gc();
348+
xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true);
349349

350350
for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
351351
WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i]));

net/key/af_key.c

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -196,30 +196,22 @@ static int pfkey_release(struct socket *sock)
196196
return 0;
197197
}
198198

199-
static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
200-
gfp_t allocation, struct sock *sk)
199+
static int pfkey_broadcast_one(struct sk_buff *skb, gfp_t allocation,
200+
struct sock *sk)
201201
{
202202
int err = -ENOBUFS;
203203

204-
sock_hold(sk);
205-
if (*skb2 == NULL) {
206-
if (refcount_read(&skb->users) != 1) {
207-
*skb2 = skb_clone(skb, allocation);
208-
} else {
209-
*skb2 = skb;
210-
refcount_inc(&skb->users);
211-
}
212-
}
213-
if (*skb2 != NULL) {
214-
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
215-
skb_set_owner_r(*skb2, sk);
216-
skb_queue_tail(&sk->sk_receive_queue, *skb2);
217-
sk->sk_data_ready(sk);
218-
*skb2 = NULL;
219-
err = 0;
220-
}
204+
if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
205+
return err;
206+
207+
skb = skb_clone(skb, allocation);
208+
209+
if (skb) {
210+
skb_set_owner_r(skb, sk);
211+
skb_queue_tail(&sk->sk_receive_queue, skb);
212+
sk->sk_data_ready(sk);
213+
err = 0;
221214
}
222-
sock_put(sk);
223215
return err;
224216
}
225217

@@ -234,7 +226,6 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
234226
{
235227
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
236228
struct sock *sk;
237-
struct sk_buff *skb2 = NULL;
238229
int err = -ESRCH;
239230

240231
/* XXX Do we need something like netlink_overrun? I think
@@ -253,7 +244,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
253244
* socket.
254245
*/
255246
if (pfk->promisc)
256-
pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
247+
pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
257248

258249
/* the exact target will be processed later */
259250
if (sk == one_sk)
@@ -268,7 +259,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
268259
continue;
269260
}
270261

271-
err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
262+
err2 = pfkey_broadcast_one(skb, GFP_ATOMIC, sk);
272263

273264
/* Error is cleared after successful sending to at least one
274265
* registered KM */
@@ -278,9 +269,8 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
278269
rcu_read_unlock();
279270

280271
if (one_sk != NULL)
281-
err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
272+
err = pfkey_broadcast_one(skb, allocation, one_sk);
282273

283-
kfree_skb(skb2);
284274
kfree_skb(skb);
285275
return err;
286276
}
@@ -1783,7 +1773,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_m
17831773
if (proto == 0)
17841774
return -EINVAL;
17851775

1786-
err = xfrm_state_flush(net, proto, true);
1776+
err = xfrm_state_flush(net, proto, true, false);
17871777
err2 = unicast_flush_resp(sk, hdr);
17881778
if (err || err2) {
17891779
if (err == -ESRCH) /* empty table - go quietly */

net/xfrm/xfrm_interface.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb)
7676
int ifindex;
7777
struct xfrm_if *xi;
7878

79-
if (!skb->dev)
79+
if (!secpath_exists(skb) || !skb->dev)
8080
return NULL;
8181

82-
xfrmn = net_generic(dev_net(skb->dev), xfrmi_net_id);
82+
xfrmn = net_generic(xs_net(xfrm_input_state(skb)), xfrmi_net_id);
8383
ifindex = skb->dev->ifindex;
8484

8585
for_each_xfrmi_rcu(xfrmn->xfrmi[0], xi) {

net/xfrm/xfrm_policy.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3314,8 +3314,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
33143314

33153315
if (ifcb) {
33163316
xi = ifcb->decode_session(skb);
3317-
if (xi)
3317+
if (xi) {
33183318
if_id = xi->p.if_id;
3319+
net = xi->net;
3320+
}
33193321
}
33203322
rcu_read_unlock();
33213323

net/xfrm/xfrm_state.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ void xfrm_state_free(struct xfrm_state *x)
432432
}
433433
EXPORT_SYMBOL(xfrm_state_free);
434434

435-
static void xfrm_state_gc_destroy(struct xfrm_state *x)
435+
static void ___xfrm_state_destroy(struct xfrm_state *x)
436436
{
437437
tasklet_hrtimer_cancel(&x->mtimer);
438438
del_timer_sync(&x->rtimer);
@@ -474,7 +474,7 @@ static void xfrm_state_gc_task(struct work_struct *work)
474474
synchronize_rcu();
475475

476476
hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
477-
xfrm_state_gc_destroy(x);
477+
___xfrm_state_destroy(x);
478478
}
479479

480480
static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
@@ -598,14 +598,19 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
598598
}
599599
EXPORT_SYMBOL(xfrm_state_alloc);
600600

601-
void __xfrm_state_destroy(struct xfrm_state *x)
601+
void __xfrm_state_destroy(struct xfrm_state *x, bool sync)
602602
{
603603
WARN_ON(x->km.state != XFRM_STATE_DEAD);
604604

605-
spin_lock_bh(&xfrm_state_gc_lock);
606-
hlist_add_head(&x->gclist, &xfrm_state_gc_list);
607-
spin_unlock_bh(&xfrm_state_gc_lock);
608-
schedule_work(&xfrm_state_gc_work);
605+
if (sync) {
606+
synchronize_rcu();
607+
___xfrm_state_destroy(x);
608+
} else {
609+
spin_lock_bh(&xfrm_state_gc_lock);
610+
hlist_add_head(&x->gclist, &xfrm_state_gc_list);
611+
spin_unlock_bh(&xfrm_state_gc_lock);
612+
schedule_work(&xfrm_state_gc_work);
613+
}
609614
}
610615
EXPORT_SYMBOL(__xfrm_state_destroy);
611616

@@ -708,7 +713,7 @@ xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool
708713
}
709714
#endif
710715

711-
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid)
716+
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync)
712717
{
713718
int i, err = 0, cnt = 0;
714719

@@ -730,7 +735,10 @@ int xfrm_state_flush(struct net *net, u8 proto, bool task_valid)
730735
err = xfrm_state_delete(x);
731736
xfrm_audit_state_delete(x, err ? 0 : 1,
732737
task_valid);
733-
xfrm_state_put(x);
738+
if (sync)
739+
xfrm_state_put_sync(x);
740+
else
741+
xfrm_state_put(x);
734742
if (!err)
735743
cnt++;
736744

@@ -2215,7 +2223,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x)
22152223
if (atomic_read(&t->tunnel_users) == 2)
22162224
xfrm_state_delete(t);
22172225
atomic_dec(&t->tunnel_users);
2218-
xfrm_state_put(t);
2226+
xfrm_state_put_sync(t);
22192227
x->tunnel = NULL;
22202228
}
22212229
}
@@ -2375,8 +2383,8 @@ void xfrm_state_fini(struct net *net)
23752383
unsigned int sz;
23762384

23772385
flush_work(&net->xfrm.state_hash_work);
2378-
xfrm_state_flush(net, IPSEC_PROTO_ANY, false);
23792386
flush_work(&xfrm_state_gc_work);
2387+
xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true);
23802388

23812389
WARN_ON(!list_empty(&net->xfrm.state_all));
23822390

net/xfrm/xfrm_user.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1932,7 +1932,7 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
19321932
struct xfrm_usersa_flush *p = nlmsg_data(nlh);
19331933
int err;
19341934

1935-
err = xfrm_state_flush(net, p->proto, true);
1935+
err = xfrm_state_flush(net, p->proto, true, false);
19361936
if (err) {
19371937
if (err == -ESRCH) /* empty table */
19381938
return 0;

0 commit comments

Comments
 (0)