@@ -180,6 +180,8 @@ enum kern_feature_id {
180180 FEAT_ARRAY_MMAP ,
181181 /* kernel support for expected_attach_type in BPF_PROG_LOAD */
182182 FEAT_EXP_ATTACH_TYPE ,
183+ /* bpf_probe_read_{kernel,user}[_str] helpers */
184+ FEAT_PROBE_READ_KERN ,
183185 __FEAT_CNT ,
184186};
185187
@@ -3591,6 +3593,27 @@ static int probe_kern_exp_attach_type(void)
35913593 return probe_fd (bpf_load_program_xattr (& attr , NULL , 0 ));
35923594}
35933595
3596+ static int probe_kern_probe_read_kernel (void )
3597+ {
3598+ struct bpf_load_program_attr attr ;
3599+ struct bpf_insn insns [] = {
3600+ BPF_MOV64_REG (BPF_REG_1 , BPF_REG_10 ), /* r1 = r10 (fp) */
3601+ BPF_ALU64_IMM (BPF_ADD , BPF_REG_1 , -8 ), /* r1 += -8 */
3602+ BPF_MOV64_IMM (BPF_REG_2 , 8 ), /* r2 = 8 */
3603+ BPF_MOV64_IMM (BPF_REG_3 , 0 ), /* r3 = 0 */
3604+ BPF_RAW_INSN (BPF_JMP | BPF_CALL , 0 , 0 , 0 , BPF_FUNC_probe_read_kernel ),
3605+ BPF_EXIT_INSN (),
3606+ };
3607+
3608+ memset (& attr , 0 , sizeof (attr ));
3609+ attr .prog_type = BPF_PROG_TYPE_KPROBE ;
3610+ attr .insns = insns ;
3611+ attr .insns_cnt = ARRAY_SIZE (insns );
3612+ attr .license = "GPL" ;
3613+
3614+ return probe_fd (bpf_load_program_xattr (& attr , NULL , 0 ));
3615+ }
3616+
35943617enum kern_feature_result {
35953618 FEAT_UNKNOWN = 0 ,
35963619 FEAT_SUPPORTED = 1 ,
@@ -3626,6 +3649,9 @@ static struct kern_feature_desc {
36263649 "BPF_PROG_LOAD expected_attach_type attribute" ,
36273650 probe_kern_exp_attach_type ,
36283651 },
3652+ [FEAT_PROBE_READ_KERN ] = {
3653+ "bpf_probe_read_kernel() helper" , probe_kern_probe_read_kernel ,
3654+ }
36293655};
36303656
36313657static bool kernel_supports (enum kern_feature_id feat_id )
@@ -5335,6 +5361,53 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
53355361 return 0 ;
53365362}
53375363
5364+ static bool insn_is_helper_call (struct bpf_insn * insn , enum bpf_func_id * func_id )
5365+ {
5366+ __u8 class = BPF_CLASS (insn -> code );
5367+
5368+ if ((class == BPF_JMP || class == BPF_JMP32 ) &&
5369+ BPF_OP (insn -> code ) == BPF_CALL &&
5370+ BPF_SRC (insn -> code ) == BPF_K &&
5371+ insn -> src_reg == 0 && insn -> dst_reg == 0 ) {
5372+ if (func_id )
5373+ * func_id = insn -> imm ;
5374+ return true;
5375+ }
5376+ return false;
5377+ }
5378+
5379+ static int bpf_object__sanitize_prog (struct bpf_object * obj , struct bpf_program * prog )
5380+ {
5381+ struct bpf_insn * insn = prog -> insns ;
5382+ enum bpf_func_id func_id ;
5383+ int i ;
5384+
5385+ for (i = 0 ; i < prog -> insns_cnt ; i ++ , insn ++ ) {
5386+ if (!insn_is_helper_call (insn , & func_id ))
5387+ continue ;
5388+
5389+ /* on kernels that don't yet support
5390+ * bpf_probe_read_{kernel,user}[_str] helpers, fall back
5391+ * to bpf_probe_read() which works well for old kernels
5392+ */
5393+ switch (func_id ) {
5394+ case BPF_FUNC_probe_read_kernel :
5395+ case BPF_FUNC_probe_read_user :
5396+ if (!kernel_supports (FEAT_PROBE_READ_KERN ))
5397+ insn -> imm = BPF_FUNC_probe_read ;
5398+ break ;
5399+ case BPF_FUNC_probe_read_kernel_str :
5400+ case BPF_FUNC_probe_read_user_str :
5401+ if (!kernel_supports (FEAT_PROBE_READ_KERN ))
5402+ insn -> imm = BPF_FUNC_probe_read_str ;
5403+ break ;
5404+ default :
5405+ break ;
5406+ }
5407+ }
5408+ return 0 ;
5409+ }
5410+
53385411static int
53395412load_program (struct bpf_program * prog , struct bpf_insn * insns , int insns_cnt ,
53405413 char * license , __u32 kern_version , int * pfd )
@@ -5549,6 +5622,13 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level)
55495622 size_t i ;
55505623 int err ;
55515624
5625+ for (i = 0 ; i < obj -> nr_programs ; i ++ ) {
5626+ prog = & obj -> programs [i ];
5627+ err = bpf_object__sanitize_prog (obj , prog );
5628+ if (err )
5629+ return err ;
5630+ }
5631+
55525632 for (i = 0 ; i < obj -> nr_programs ; i ++ ) {
55535633 prog = & obj -> programs [i ];
55545634 if (bpf_program__is_function_storage (prog , obj ))
0 commit comments