@@ -357,6 +357,7 @@ enum libbpf_map_type {
357
357
};
358
358
359
359
struct bpf_map {
360
+ struct bpf_object * obj ;
360
361
char * name ;
361
362
/* real_name is defined for special internal maps (.rodata*,
362
363
* .data*, .bss, .kconfig) and preserves their original ELF section
@@ -386,7 +387,7 @@ struct bpf_map {
386
387
char * pin_path ;
387
388
bool pinned ;
388
389
bool reused ;
389
- bool skipped ;
390
+ bool autocreate ;
390
391
__u64 map_extra ;
391
392
};
392
393
@@ -1433,36 +1434,21 @@ static int find_elf_var_offset(const struct bpf_object *obj, const char *name, _
1433
1434
1434
1435
static struct bpf_map * bpf_object__add_map (struct bpf_object * obj )
1435
1436
{
1436
- struct bpf_map * new_maps ;
1437
- size_t new_cap ;
1438
- int i ;
1439
-
1440
- if (obj -> nr_maps < obj -> maps_cap )
1441
- return & obj -> maps [obj -> nr_maps ++ ];
1442
-
1443
- new_cap = max ((size_t )4 , obj -> maps_cap * 3 / 2 );
1444
- new_maps = libbpf_reallocarray (obj -> maps , new_cap , sizeof (* obj -> maps ));
1445
- if (!new_maps ) {
1446
- pr_warn ("alloc maps for object failed\n" );
1447
- return ERR_PTR (- ENOMEM );
1448
- }
1437
+ struct bpf_map * map ;
1438
+ int err ;
1449
1439
1450
- obj -> maps_cap = new_cap ;
1451
- obj -> maps = new_maps ;
1440
+ err = libbpf_ensure_mem ((void * * )& obj -> maps , & obj -> maps_cap ,
1441
+ sizeof (* obj -> maps ), obj -> nr_maps + 1 );
1442
+ if (err )
1443
+ return ERR_PTR (err );
1452
1444
1453
- /* zero out new maps */
1454
- memset (obj -> maps + obj -> nr_maps , 0 ,
1455
- (obj -> maps_cap - obj -> nr_maps ) * sizeof (* obj -> maps ));
1456
- /*
1457
- * fill all fd with -1 so won't close incorrect fd (fd=0 is stdin)
1458
- * when failure (zclose won't close negative fd)).
1459
- */
1460
- for (i = obj -> nr_maps ; i < obj -> maps_cap ; i ++ ) {
1461
- obj -> maps [i ].fd = -1 ;
1462
- obj -> maps [i ].inner_map_fd = -1 ;
1463
- }
1445
+ map = & obj -> maps [obj -> nr_maps ++ ];
1446
+ map -> obj = obj ;
1447
+ map -> fd = -1 ;
1448
+ map -> inner_map_fd = -1 ;
1449
+ map -> autocreate = true;
1464
1450
1465
- return & obj -> maps [ obj -> nr_maps ++ ] ;
1451
+ return map ;
1466
1452
}
1467
1453
1468
1454
static size_t bpf_map_mmap_sz (const struct bpf_map * map )
@@ -4324,6 +4310,20 @@ static int bpf_get_map_info_from_fdinfo(int fd, struct bpf_map_info *info)
4324
4310
return 0 ;
4325
4311
}
4326
4312
4313
+ bool bpf_map__autocreate (const struct bpf_map * map )
4314
+ {
4315
+ return map -> autocreate ;
4316
+ }
4317
+
4318
+ int bpf_map__set_autocreate (struct bpf_map * map , bool autocreate )
4319
+ {
4320
+ if (map -> obj -> loaded )
4321
+ return libbpf_err (- EBUSY );
4322
+
4323
+ map -> autocreate = autocreate ;
4324
+ return 0 ;
4325
+ }
4326
+
4327
4327
int bpf_map__reuse_fd (struct bpf_map * map , int fd )
4328
4328
{
4329
4329
struct bpf_map_info info = {};
@@ -5180,9 +5180,11 @@ bpf_object__create_maps(struct bpf_object *obj)
5180
5180
* bpf_object loading will succeed just fine even on old
5181
5181
* kernels.
5182
5182
*/
5183
- if (bpf_map__is_internal (map ) &&
5184
- !kernel_supports (obj , FEAT_GLOBAL_DATA )) {
5185
- map -> skipped = true;
5183
+ if (bpf_map__is_internal (map ) && !kernel_supports (obj , FEAT_GLOBAL_DATA ))
5184
+ map -> autocreate = false;
5185
+
5186
+ if (!map -> autocreate ) {
5187
+ pr_debug ("map '%s': skipped auto-creating...\n" , map -> name );
5186
5188
continue ;
5187
5189
}
5188
5190
@@ -5805,6 +5807,36 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path)
5805
5807
return err ;
5806
5808
}
5807
5809
5810
+ /* base map load ldimm64 special constant, used also for log fixup logic */
5811
+ #define MAP_LDIMM64_POISON_BASE 2001000000
5812
+ #define MAP_LDIMM64_POISON_PFX "200100"
5813
+
5814
+ static void poison_map_ldimm64 (struct bpf_program * prog , int relo_idx ,
5815
+ int insn_idx , struct bpf_insn * insn ,
5816
+ int map_idx , const struct bpf_map * map )
5817
+ {
5818
+ int i ;
5819
+
5820
+ pr_debug ("prog '%s': relo #%d: poisoning insn #%d that loads map #%d '%s'\n" ,
5821
+ prog -> name , relo_idx , insn_idx , map_idx , map -> name );
5822
+
5823
+ /* we turn single ldimm64 into two identical invalid calls */
5824
+ for (i = 0 ; i < 2 ; i ++ ) {
5825
+ insn -> code = BPF_JMP | BPF_CALL ;
5826
+ insn -> dst_reg = 0 ;
5827
+ insn -> src_reg = 0 ;
5828
+ insn -> off = 0 ;
5829
+ /* if this instruction is reachable (not a dead code),
5830
+ * verifier will complain with something like:
5831
+ * invalid func unknown#2001000123
5832
+ * where lower 123 is map index into obj->maps[] array
5833
+ */
5834
+ insn -> imm = MAP_LDIMM64_POISON_BASE + map_idx ;
5835
+
5836
+ insn ++ ;
5837
+ }
5838
+ }
5839
+
5808
5840
/* Relocate data references within program code:
5809
5841
* - map references;
5810
5842
* - global variable references;
@@ -5818,33 +5850,35 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog)
5818
5850
for (i = 0 ; i < prog -> nr_reloc ; i ++ ) {
5819
5851
struct reloc_desc * relo = & prog -> reloc_desc [i ];
5820
5852
struct bpf_insn * insn = & prog -> insns [relo -> insn_idx ];
5853
+ const struct bpf_map * map ;
5821
5854
struct extern_desc * ext ;
5822
5855
5823
5856
switch (relo -> type ) {
5824
5857
case RELO_LD64 :
5858
+ map = & obj -> maps [relo -> map_idx ];
5825
5859
if (obj -> gen_loader ) {
5826
5860
insn [0 ].src_reg = BPF_PSEUDO_MAP_IDX ;
5827
5861
insn [0 ].imm = relo -> map_idx ;
5828
- } else {
5862
+ } else if ( map -> autocreate ) {
5829
5863
insn [0 ].src_reg = BPF_PSEUDO_MAP_FD ;
5830
- insn [0 ].imm = obj -> maps [relo -> map_idx ].fd ;
5864
+ insn [0 ].imm = map -> fd ;
5865
+ } else {
5866
+ poison_map_ldimm64 (prog , i , relo -> insn_idx , insn ,
5867
+ relo -> map_idx , map );
5831
5868
}
5832
5869
break ;
5833
5870
case RELO_DATA :
5871
+ map = & obj -> maps [relo -> map_idx ];
5834
5872
insn [1 ].imm = insn [0 ].imm + relo -> sym_off ;
5835
5873
if (obj -> gen_loader ) {
5836
5874
insn [0 ].src_reg = BPF_PSEUDO_MAP_IDX_VALUE ;
5837
5875
insn [0 ].imm = relo -> map_idx ;
5838
- } else {
5839
- const struct bpf_map * map = & obj -> maps [relo -> map_idx ];
5840
-
5841
- if (map -> skipped ) {
5842
- pr_warn ("prog '%s': relo #%d: kernel doesn't support global data\n" ,
5843
- prog -> name , i );
5844
- return - ENOTSUP ;
5845
- }
5876
+ } else if (map -> autocreate ) {
5846
5877
insn [0 ].src_reg = BPF_PSEUDO_MAP_VALUE ;
5847
- insn [0 ].imm = obj -> maps [relo -> map_idx ].fd ;
5878
+ insn [0 ].imm = map -> fd ;
5879
+ } else {
5880
+ poison_map_ldimm64 (prog , i , relo -> insn_idx , insn ,
5881
+ relo -> map_idx , map );
5848
5882
}
5849
5883
break ;
5850
5884
case RELO_EXTERN_VAR :
@@ -6962,7 +6996,7 @@ static void fixup_log_failed_core_relo(struct bpf_program *prog,
6962
6996
const struct bpf_core_relo * relo ;
6963
6997
struct bpf_core_spec spec ;
6964
6998
char patch [512 ], spec_buf [256 ];
6965
- int insn_idx , err ;
6999
+ int insn_idx , err , spec_len ;
6966
7000
6967
7001
if (sscanf (line1 , "%d: (%*d) call unknown#195896080\n" , & insn_idx ) != 1 )
6968
7002
return ;
@@ -6975,11 +7009,44 @@ static void fixup_log_failed_core_relo(struct bpf_program *prog,
6975
7009
if (err )
6976
7010
return ;
6977
7011
6978
- bpf_core_format_spec (spec_buf , sizeof (spec_buf ), & spec );
7012
+ spec_len = bpf_core_format_spec (spec_buf , sizeof (spec_buf ), & spec );
6979
7013
snprintf (patch , sizeof (patch ),
6980
7014
"%d: <invalid CO-RE relocation>\n"
6981
- "failed to resolve CO-RE relocation %s\n" ,
6982
- insn_idx , spec_buf );
7015
+ "failed to resolve CO-RE relocation %s%s\n" ,
7016
+ insn_idx , spec_buf , spec_len >= sizeof (spec_buf ) ? "..." : "" );
7017
+
7018
+ patch_log (buf , buf_sz , log_sz , line1 , line3 - line1 , patch );
7019
+ }
7020
+
7021
+ static void fixup_log_missing_map_load (struct bpf_program * prog ,
7022
+ char * buf , size_t buf_sz , size_t log_sz ,
7023
+ char * line1 , char * line2 , char * line3 )
7024
+ {
7025
+ /* Expected log for failed and not properly guarded CO-RE relocation:
7026
+ * line1 -> 123: (85) call unknown#2001000345
7027
+ * line2 -> invalid func unknown#2001000345
7028
+ * line3 -> <anything else or end of buffer>
7029
+ *
7030
+ * "123" is the index of the instruction that was poisoned.
7031
+ * "345" in "2001000345" are map index in obj->maps to fetch map name.
7032
+ */
7033
+ struct bpf_object * obj = prog -> obj ;
7034
+ const struct bpf_map * map ;
7035
+ int insn_idx , map_idx ;
7036
+ char patch [128 ];
7037
+
7038
+ if (sscanf (line1 , "%d: (%*d) call unknown#%d\n" , & insn_idx , & map_idx ) != 2 )
7039
+ return ;
7040
+
7041
+ map_idx -= MAP_LDIMM64_POISON_BASE ;
7042
+ if (map_idx < 0 || map_idx >= obj -> nr_maps )
7043
+ return ;
7044
+ map = & obj -> maps [map_idx ];
7045
+
7046
+ snprintf (patch , sizeof (patch ),
7047
+ "%d: <invalid BPF map reference>\n"
7048
+ "BPF map '%s' is referenced but wasn't created\n" ,
7049
+ insn_idx , map -> name );
6983
7050
6984
7051
patch_log (buf , buf_sz , log_sz , line1 , line3 - line1 , patch );
6985
7052
}
@@ -7012,6 +7079,14 @@ static void fixup_verifier_log(struct bpf_program *prog, char *buf, size_t buf_s
7012
7079
fixup_log_failed_core_relo (prog , buf , buf_sz , log_sz ,
7013
7080
prev_line , cur_line , next_line );
7014
7081
return ;
7082
+ } else if (str_has_pfx (cur_line , "invalid func unknown#" MAP_LDIMM64_POISON_PFX )) {
7083
+ prev_line = find_prev_line (buf , cur_line );
7084
+ if (!prev_line )
7085
+ continue ;
7086
+
7087
+ fixup_log_missing_map_load (prog , buf , buf_sz , log_sz ,
7088
+ prev_line , cur_line , next_line );
7089
+ return ;
7015
7090
}
7016
7091
}
7017
7092
}
@@ -8200,7 +8275,7 @@ int bpf_object__pin_maps(struct bpf_object *obj, const char *path)
8200
8275
char * pin_path = NULL ;
8201
8276
char buf [PATH_MAX ];
8202
8277
8203
- if (map -> skipped )
8278
+ if (! map -> autocreate )
8204
8279
continue ;
8205
8280
8206
8281
if (path ) {
0 commit comments