@@ -5615,21 +5615,46 @@ static u8 bpf_ctx_convert_map[] = {
5615
5615
#undef BPF_MAP_TYPE
5616
5616
#undef BPF_LINK_TYPE
5617
5617
5618
- const struct btf_member *
5619
- btf_get_prog_ctx_type (struct bpf_verifier_log * log , const struct btf * btf ,
5620
- const struct btf_type * t , enum bpf_prog_type prog_type ,
5621
- int arg )
5618
+ static const struct btf_type * find_canonical_prog_ctx_type (enum bpf_prog_type prog_type )
5622
5619
{
5623
5620
const struct btf_type * conv_struct ;
5624
- const struct btf_type * ctx_struct ;
5625
5621
const struct btf_member * ctx_type ;
5626
- const char * tname , * ctx_tname ;
5627
5622
5628
5623
conv_struct = bpf_ctx_convert .t ;
5629
- if (!conv_struct ) {
5630
- bpf_log (log , "btf_vmlinux is malformed\n" );
5624
+ if (!conv_struct )
5631
5625
return NULL ;
5632
- }
5626
+ /* prog_type is valid bpf program type. No need for bounds check. */
5627
+ ctx_type = btf_type_member (conv_struct ) + bpf_ctx_convert_map [prog_type ] * 2 ;
5628
+ /* ctx_type is a pointer to prog_ctx_type in vmlinux.
5629
+ * Like 'struct __sk_buff'
5630
+ */
5631
+ return btf_type_by_id (btf_vmlinux , ctx_type -> type );
5632
+ }
5633
+
5634
+ static int find_kern_ctx_type_id (enum bpf_prog_type prog_type )
5635
+ {
5636
+ const struct btf_type * conv_struct ;
5637
+ const struct btf_member * ctx_type ;
5638
+
5639
+ conv_struct = bpf_ctx_convert .t ;
5640
+ if (!conv_struct )
5641
+ return - EFAULT ;
5642
+ /* prog_type is valid bpf program type. No need for bounds check. */
5643
+ ctx_type = btf_type_member (conv_struct ) + bpf_ctx_convert_map [prog_type ] * 2 + 1 ;
5644
+ /* ctx_type is a pointer to prog_ctx_type in vmlinux.
5645
+ * Like 'struct sk_buff'
5646
+ */
5647
+ return ctx_type -> type ;
5648
+ }
5649
+
5650
+ const struct btf_type *
5651
+ btf_get_prog_ctx_type (struct bpf_verifier_log * log , const struct btf * btf ,
5652
+ const struct btf_type * t , enum bpf_prog_type prog_type ,
5653
+ int arg )
5654
+ {
5655
+ const struct btf_type * ctx_type ;
5656
+ const char * tname , * ctx_tname ;
5657
+
5633
5658
t = btf_type_by_id (btf , t -> type );
5634
5659
while (btf_type_is_modifier (t ))
5635
5660
t = btf_type_by_id (btf , t -> type );
@@ -5646,17 +5671,15 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
5646
5671
bpf_log (log , "arg#%d struct doesn't have a name\n" , arg );
5647
5672
return NULL ;
5648
5673
}
5649
- /* prog_type is valid bpf program type. No need for bounds check. */
5650
- ctx_type = btf_type_member (conv_struct ) + bpf_ctx_convert_map [prog_type ] * 2 ;
5651
- /* ctx_struct is a pointer to prog_ctx_type in vmlinux.
5652
- * Like 'struct __sk_buff'
5653
- */
5654
- ctx_struct = btf_type_by_id (btf_vmlinux , ctx_type -> type );
5655
- if (!ctx_struct )
5674
+
5675
+ ctx_type = find_canonical_prog_ctx_type (prog_type );
5676
+ if (!ctx_type ) {
5677
+ bpf_log (log , "btf_vmlinux is malformed\n" );
5656
5678
/* should not happen */
5657
5679
return NULL ;
5680
+ }
5658
5681
again :
5659
- ctx_tname = btf_name_by_offset (btf_vmlinux , ctx_struct -> name_off );
5682
+ ctx_tname = btf_name_by_offset (btf_vmlinux , ctx_type -> name_off );
5660
5683
if (!ctx_tname ) {
5661
5684
/* should not happen */
5662
5685
bpf_log (log , "Please fix kernel include/linux/bpf_types.h\n" );
@@ -5677,28 +5700,167 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
5677
5700
/* bpf_user_pt_regs_t is a typedef, so resolve it to
5678
5701
* underlying struct and check name again
5679
5702
*/
5680
- if (!btf_type_is_modifier (ctx_struct ))
5703
+ if (!btf_type_is_modifier (ctx_type ))
5681
5704
return NULL ;
5682
- while (btf_type_is_modifier (ctx_struct ))
5683
- ctx_struct = btf_type_by_id (btf_vmlinux , ctx_struct -> type );
5705
+ while (btf_type_is_modifier (ctx_type ))
5706
+ ctx_type = btf_type_by_id (btf_vmlinux , ctx_type -> type );
5684
5707
goto again ;
5685
5708
}
5686
5709
return ctx_type ;
5687
5710
}
5688
5711
5712
+ /* forward declarations for arch-specific underlying types of
5713
+ * bpf_user_pt_regs_t; this avoids the need for arch-specific #ifdef
5714
+ * compilation guards below for BPF_PROG_TYPE_PERF_EVENT checks, but still
5715
+ * works correctly with __builtin_types_compatible_p() on respective
5716
+ * architectures
5717
+ */
5718
+ struct user_regs_struct ;
5719
+ struct user_pt_regs ;
5720
+
5721
+ static int btf_validate_prog_ctx_type (struct bpf_verifier_log * log , const struct btf * btf ,
5722
+ const struct btf_type * t , int arg ,
5723
+ enum bpf_prog_type prog_type ,
5724
+ enum bpf_attach_type attach_type )
5725
+ {
5726
+ const struct btf_type * ctx_type ;
5727
+ const char * tname , * ctx_tname ;
5728
+
5729
+ if (!btf_is_ptr (t )) {
5730
+ bpf_log (log , "arg#%d type isn't a pointer\n" , arg );
5731
+ return - EINVAL ;
5732
+ }
5733
+ t = btf_type_by_id (btf , t -> type );
5734
+
5735
+ /* KPROBE and PERF_EVENT programs allow bpf_user_pt_regs_t typedef */
5736
+ if (prog_type == BPF_PROG_TYPE_KPROBE || prog_type == BPF_PROG_TYPE_PERF_EVENT ) {
5737
+ while (btf_type_is_modifier (t ) && !btf_type_is_typedef (t ))
5738
+ t = btf_type_by_id (btf , t -> type );
5739
+
5740
+ if (btf_type_is_typedef (t )) {
5741
+ tname = btf_name_by_offset (btf , t -> name_off );
5742
+ if (tname && strcmp (tname , "bpf_user_pt_regs_t" ) == 0 )
5743
+ return 0 ;
5744
+ }
5745
+ }
5746
+
5747
+ /* all other program types don't use typedefs for context type */
5748
+ while (btf_type_is_modifier (t ))
5749
+ t = btf_type_by_id (btf , t -> type );
5750
+
5751
+ /* `void *ctx __arg_ctx` is always valid */
5752
+ if (btf_type_is_void (t ))
5753
+ return 0 ;
5754
+
5755
+ tname = btf_name_by_offset (btf , t -> name_off );
5756
+ if (str_is_empty (tname )) {
5757
+ bpf_log (log , "arg#%d type doesn't have a name\n" , arg );
5758
+ return - EINVAL ;
5759
+ }
5760
+
5761
+ /* special cases */
5762
+ switch (prog_type ) {
5763
+ case BPF_PROG_TYPE_KPROBE :
5764
+ if (__btf_type_is_struct (t ) && strcmp (tname , "pt_regs" ) == 0 )
5765
+ return 0 ;
5766
+ break ;
5767
+ case BPF_PROG_TYPE_PERF_EVENT :
5768
+ if (__builtin_types_compatible_p (bpf_user_pt_regs_t , struct pt_regs ) &&
5769
+ __btf_type_is_struct (t ) && strcmp (tname , "pt_regs" ) == 0 )
5770
+ return 0 ;
5771
+ if (__builtin_types_compatible_p (bpf_user_pt_regs_t , struct user_pt_regs ) &&
5772
+ __btf_type_is_struct (t ) && strcmp (tname , "user_pt_regs" ) == 0 )
5773
+ return 0 ;
5774
+ if (__builtin_types_compatible_p (bpf_user_pt_regs_t , struct user_regs_struct ) &&
5775
+ __btf_type_is_struct (t ) && strcmp (tname , "user_regs_struct" ) == 0 )
5776
+ return 0 ;
5777
+ break ;
5778
+ case BPF_PROG_TYPE_RAW_TRACEPOINT :
5779
+ case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE :
5780
+ /* allow u64* as ctx */
5781
+ if (btf_is_int (t ) && t -> size == 8 )
5782
+ return 0 ;
5783
+ break ;
5784
+ case BPF_PROG_TYPE_TRACING :
5785
+ switch (attach_type ) {
5786
+ case BPF_TRACE_RAW_TP :
5787
+ /* tp_btf program is TRACING, so need special case here */
5788
+ if (__btf_type_is_struct (t ) &&
5789
+ strcmp (tname , "bpf_raw_tracepoint_args" ) == 0 )
5790
+ return 0 ;
5791
+ /* allow u64* as ctx */
5792
+ if (btf_is_int (t ) && t -> size == 8 )
5793
+ return 0 ;
5794
+ break ;
5795
+ case BPF_TRACE_ITER :
5796
+ /* allow struct bpf_iter__xxx types only */
5797
+ if (__btf_type_is_struct (t ) &&
5798
+ strncmp (tname , "bpf_iter__" , sizeof ("bpf_iter__" ) - 1 ) == 0 )
5799
+ return 0 ;
5800
+ break ;
5801
+ case BPF_TRACE_FENTRY :
5802
+ case BPF_TRACE_FEXIT :
5803
+ case BPF_MODIFY_RETURN :
5804
+ /* allow u64* as ctx */
5805
+ if (btf_is_int (t ) && t -> size == 8 )
5806
+ return 0 ;
5807
+ break ;
5808
+ default :
5809
+ break ;
5810
+ }
5811
+ break ;
5812
+ case BPF_PROG_TYPE_LSM :
5813
+ case BPF_PROG_TYPE_STRUCT_OPS :
5814
+ /* allow u64* as ctx */
5815
+ if (btf_is_int (t ) && t -> size == 8 )
5816
+ return 0 ;
5817
+ break ;
5818
+ case BPF_PROG_TYPE_TRACEPOINT :
5819
+ case BPF_PROG_TYPE_SYSCALL :
5820
+ case BPF_PROG_TYPE_EXT :
5821
+ return 0 ; /* anything goes */
5822
+ default :
5823
+ break ;
5824
+ }
5825
+
5826
+ ctx_type = find_canonical_prog_ctx_type (prog_type );
5827
+ if (!ctx_type ) {
5828
+ /* should not happen */
5829
+ bpf_log (log , "btf_vmlinux is malformed\n" );
5830
+ return - EINVAL ;
5831
+ }
5832
+
5833
+ /* resolve typedefs and check that underlying structs are matching as well */
5834
+ while (btf_type_is_modifier (ctx_type ))
5835
+ ctx_type = btf_type_by_id (btf_vmlinux , ctx_type -> type );
5836
+
5837
+ /* if program type doesn't have distinctly named struct type for
5838
+ * context, then __arg_ctx argument can only be `void *`, which we
5839
+ * already checked above
5840
+ */
5841
+ if (!__btf_type_is_struct (ctx_type )) {
5842
+ bpf_log (log , "arg#%d should be void pointer\n" , arg );
5843
+ return - EINVAL ;
5844
+ }
5845
+
5846
+ ctx_tname = btf_name_by_offset (btf_vmlinux , ctx_type -> name_off );
5847
+ if (!__btf_type_is_struct (t ) || strcmp (ctx_tname , tname ) != 0 ) {
5848
+ bpf_log (log , "arg#%d should be `struct %s *`\n" , arg , ctx_tname );
5849
+ return - EINVAL ;
5850
+ }
5851
+
5852
+ return 0 ;
5853
+ }
5854
+
5689
5855
static int btf_translate_to_vmlinux (struct bpf_verifier_log * log ,
5690
5856
struct btf * btf ,
5691
5857
const struct btf_type * t ,
5692
5858
enum bpf_prog_type prog_type ,
5693
5859
int arg )
5694
5860
{
5695
- const struct btf_member * prog_ctx_type , * kern_ctx_type ;
5696
-
5697
- prog_ctx_type = btf_get_prog_ctx_type (log , btf , t , prog_type , arg );
5698
- if (!prog_ctx_type )
5861
+ if (!btf_get_prog_ctx_type (log , btf , t , prog_type , arg ))
5699
5862
return - ENOENT ;
5700
- kern_ctx_type = prog_ctx_type + 1 ;
5701
- return kern_ctx_type -> type ;
5863
+ return find_kern_ctx_type_id (prog_type );
5702
5864
}
5703
5865
5704
5866
int get_kern_ctx_btf_id (struct bpf_verifier_log * log , enum bpf_prog_type prog_type )
@@ -6934,6 +7096,23 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
6934
7096
return - EINVAL ;
6935
7097
}
6936
7098
7099
+ for (i = 0 ; i < nargs ; i ++ ) {
7100
+ const char * tag ;
7101
+
7102
+ if (sub -> args [i ].arg_type != ARG_PTR_TO_CTX )
7103
+ continue ;
7104
+
7105
+ /* check if arg has "arg:ctx" tag */
7106
+ t = btf_type_by_id (btf , args [i ].type );
7107
+ tag = btf_find_decl_tag_value (btf , fn_t , i , "arg:" );
7108
+ if (IS_ERR_OR_NULL (tag ) || strcmp (tag , "ctx" ) != 0 )
7109
+ continue ;
7110
+
7111
+ if (btf_validate_prog_ctx_type (log , btf , t , i , prog_type ,
7112
+ prog -> expected_attach_type ))
7113
+ return - EINVAL ;
7114
+ }
7115
+
6937
7116
sub -> arg_cnt = nargs ;
6938
7117
sub -> args_cached = true;
6939
7118
0 commit comments