@@ -660,20 +660,29 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_memb_release, KF_RELEASE)
660660BTF_KFUNCS_END (test_sk_check_kfunc_ids )
661661
662662static void * bpf_test_init (const union bpf_attr * kattr , u32 user_size ,
663- u32 size , u32 headroom , u32 tailroom )
663+ u32 size , u32 headroom , u32 tailroom , bool nonlinear )
664664{
665665 void __user * data_in = u64_to_user_ptr (kattr -> test .data_in );
666- void * data ;
666+ void * data , * dst ;
667667
668668 if (user_size < ETH_HLEN || user_size > PAGE_SIZE - headroom - tailroom )
669669 return ERR_PTR (- EINVAL );
670670
671- size = SKB_DATA_ALIGN (size );
672- data = kzalloc (size + headroom + tailroom , GFP_USER );
671+ /* In non-linear case, data_in is copied to the paged data */
672+ if (nonlinear ) {
673+ data = alloc_page (GFP_USER );
674+ } else {
675+ size = SKB_DATA_ALIGN (size );
676+ data = kzalloc (size + headroom + tailroom , GFP_USER );
677+ }
673678 if (!data )
674679 return ERR_PTR (- ENOMEM );
675680
676- if (copy_from_user (data + headroom , data_in , user_size )) {
681+ if (nonlinear )
682+ dst = page_address (data );
683+ else
684+ dst = data + headroom ;
685+ if (copy_from_user (dst , data_in , user_size )) {
677686 kfree (data );
678687 return ERR_PTR (- EFAULT );
679688 }
@@ -910,6 +919,12 @@ static int convert___skb_to_skb(struct sk_buff *skb, struct __sk_buff *__skb)
910919 /* cb is allowed */
911920
912921 if (!range_is_zero (__skb , offsetofend (struct __sk_buff , cb ),
922+ offsetof(struct __sk_buff , data_end )))
923+ return - EINVAL ;
924+
925+ /* data_end is allowed, but not copied to skb */
926+
927+ if (!range_is_zero (__skb , offsetofend (struct __sk_buff , data_end ),
913928 offsetof(struct __sk_buff , tstamp )))
914929 return - EINVAL ;
915930
@@ -984,7 +999,7 @@ static struct proto bpf_dummy_proto = {
984999int bpf_prog_test_run_skb (struct bpf_prog * prog , const union bpf_attr * kattr ,
9851000 union bpf_attr __user * uattr )
9861001{
987- bool is_l2 = false, is_direct_pkt_access = false;
1002+ bool is_l2 = false, is_direct_pkt_access = false, is_nonlinear = false ;
9881003 struct net * net = current -> nsproxy -> net_ns ;
9891004 struct net_device * dev = net -> loopback_dev ;
9901005 u32 size = kattr -> test .data_size_in ;
@@ -994,25 +1009,14 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
9941009 struct sock * sk = NULL ;
9951010 u32 retval , duration ;
9961011 int hh_len = ETH_HLEN ;
1012+ int linear_size , ret ;
9971013 void * data ;
998- int ret ;
9991014
1000- if ((kattr -> test .flags & ~BPF_F_TEST_SKB_CHECKSUM_COMPLETE ) ||
1015+ if ((kattr -> test .flags & ~( BPF_F_TEST_SKB_CHECKSUM_COMPLETE | BPF_F_TEST_SKB_NON_LINEAR ) ) ||
10011016 kattr -> test .cpu || kattr -> test .batch_size )
10021017 return - EINVAL ;
10031018
1004- data = bpf_test_init (kattr , kattr -> test .data_size_in ,
1005- size , NET_SKB_PAD + NET_IP_ALIGN ,
1006- SKB_DATA_ALIGN (sizeof (struct skb_shared_info )));
1007- if (IS_ERR (data ))
1008- return PTR_ERR (data );
1009-
1010- ctx = bpf_ctx_init (kattr , sizeof (struct __sk_buff ));
1011- if (IS_ERR (ctx )) {
1012- ret = PTR_ERR (ctx );
1013- ctx = NULL ;
1014- goto out ;
1015- }
1019+ is_nonlinear = kattr -> test .flags & BPF_F_TEST_SKB_NON_LINEAR ;
10161020
10171021 switch (prog -> type ) {
10181022 case BPF_PROG_TYPE_SCHED_CLS :
@@ -1029,22 +1033,60 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
10291033 break ;
10301034 }
10311035
1036+ if (is_nonlinear && !is_l2 )
1037+ return - EINVAL ;
1038+
1039+ data = bpf_test_init (kattr , kattr -> test .data_size_in ,
1040+ size , NET_SKB_PAD + NET_IP_ALIGN ,
1041+ SKB_DATA_ALIGN (sizeof (struct skb_shared_info )),
1042+ is_nonlinear );
1043+ if (IS_ERR (data ))
1044+ return PTR_ERR (data );
1045+
1046+ ctx = bpf_ctx_init (kattr , sizeof (struct __sk_buff ));
1047+ if (IS_ERR (ctx )) {
1048+ ret = PTR_ERR (ctx );
1049+ ctx = NULL ;
1050+ goto out ;
1051+ }
1052+
1053+ linear_size = hh_len ;
1054+ if (is_nonlinear && ctx && ctx -> data_end > linear_size )
1055+ linear_size = ctx -> data_end ;
1056+
10321057 sk = sk_alloc (net , AF_UNSPEC , GFP_USER , & bpf_dummy_proto , 1 );
10331058 if (!sk ) {
10341059 ret = - ENOMEM ;
10351060 goto out ;
10361061 }
10371062 sock_init_data (NULL , sk );
10381063
1039- skb = slab_build_skb (data );
1064+ if (is_nonlinear )
1065+ skb = alloc_skb (NET_SKB_PAD + NET_IP_ALIGN + size +
1066+ SKB_DATA_ALIGN (sizeof (struct skb_shared_info )),
1067+ GFP_USER );
1068+ else
1069+ skb = slab_build_skb (data );
10401070 if (!skb ) {
10411071 ret = - ENOMEM ;
10421072 goto out ;
10431073 }
1074+
10441075 skb -> sk = sk ;
10451076
10461077 skb_reserve (skb , NET_SKB_PAD + NET_IP_ALIGN );
1047- __skb_put (skb , size );
1078+
1079+ if (is_nonlinear ) {
1080+ skb_fill_page_desc (skb , 0 , data , 0 , size );
1081+ skb -> truesize += PAGE_SIZE ;
1082+ skb -> data_len = size ;
1083+ skb -> len = size ;
1084+
1085+ /* eth_type_trans expects the Ethernet header in the linear area. */
1086+ __pskb_pull_tail (skb , linear_size );
1087+ } else {
1088+ __skb_put (skb , size );
1089+ }
10481090
10491091 data = NULL ; /* data released via kfree_skb */
10501092
@@ -1127,9 +1169,11 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
11271169 convert_skb_to___skb (skb , ctx );
11281170
11291171 size = skb -> len ;
1130- /* bpf program can never convert linear skb to non-linear */
1131- if (WARN_ON_ONCE (skb_is_nonlinear (skb )))
1172+ if (skb_is_nonlinear (skb )) {
1173+ /* bpf program can never convert linear skb to non-linear */
1174+ WARN_ON_ONCE (!is_nonlinear );
11321175 size = skb_headlen (skb );
1176+ }
11331177 ret = bpf_test_finish (kattr , uattr , skb -> data , NULL , size , retval ,
11341178 duration );
11351179 if (!ret )
@@ -1139,7 +1183,8 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
11391183 if (dev && dev != net -> loopback_dev )
11401184 dev_put (dev );
11411185 kfree_skb (skb );
1142- kfree (data );
1186+ if (data )
1187+ is_nonlinear ? __free_page (data ) : kfree (data );
11431188 if (sk )
11441189 sk_free (sk );
11451190 kfree (ctx );
@@ -1265,7 +1310,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
12651310 size = max_data_sz ;
12661311 }
12671312
1268- data = bpf_test_init (kattr , size , max_data_sz , headroom , tailroom );
1313+ data = bpf_test_init (kattr , size , max_data_sz , headroom , tailroom , false );
12691314 if (IS_ERR (data )) {
12701315 ret = PTR_ERR (data );
12711316 goto free_ctx ;
@@ -1388,7 +1433,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
13881433 if (size < ETH_HLEN )
13891434 return - EINVAL ;
13901435
1391- data = bpf_test_init (kattr , kattr -> test .data_size_in , size , 0 , 0 );
1436+ data = bpf_test_init (kattr , kattr -> test .data_size_in , size , 0 , 0 , false );
13921437 if (IS_ERR (data ))
13931438 return PTR_ERR (data );
13941439
@@ -1661,7 +1706,8 @@ int bpf_prog_test_run_nf(struct bpf_prog *prog,
16611706
16621707 data = bpf_test_init (kattr , kattr -> test .data_size_in , size ,
16631708 NET_SKB_PAD + NET_IP_ALIGN ,
1664- SKB_DATA_ALIGN (sizeof (struct skb_shared_info )));
1709+ SKB_DATA_ALIGN (sizeof (struct skb_shared_info )),
1710+ false);
16651711 if (IS_ERR (data ))
16661712 return PTR_ERR (data );
16671713
0 commit comments