@@ -345,7 +345,6 @@ struct bpf_object {
345
345
346
346
bool loaded ;
347
347
bool has_pseudo_calls ;
348
- bool relaxed_core_relocs ;
349
348
350
349
/*
351
350
* Information when doing elf related work. Only valid if fd
@@ -4238,25 +4237,38 @@ static int bpf_core_calc_field_relo(const struct bpf_program *prog,
4238
4237
*/
4239
4238
static int bpf_core_reloc_insn (struct bpf_program * prog ,
4240
4239
const struct bpf_field_reloc * relo ,
4240
+ int relo_idx ,
4241
4241
const struct bpf_core_spec * local_spec ,
4242
4242
const struct bpf_core_spec * targ_spec )
4243
4243
{
4244
- bool failed = false, validate = true;
4245
4244
__u32 orig_val , new_val ;
4246
4245
struct bpf_insn * insn ;
4246
+ bool validate = true;
4247
4247
int insn_idx , err ;
4248
4248
__u8 class ;
4249
4249
4250
4250
if (relo -> insn_off % sizeof (struct bpf_insn ))
4251
4251
return - EINVAL ;
4252
4252
insn_idx = relo -> insn_off / sizeof (struct bpf_insn );
4253
+ insn = & prog -> insns [insn_idx ];
4254
+ class = BPF_CLASS (insn -> code );
4253
4255
4254
4256
if (relo -> kind == BPF_FIELD_EXISTS ) {
4255
4257
orig_val = 1 ; /* can't generate EXISTS relo w/o local field */
4256
4258
new_val = targ_spec ? 1 : 0 ;
4257
4259
} else if (!targ_spec ) {
4258
- failed = true;
4259
- new_val = (__u32 )- 1 ;
4260
+ pr_debug ("prog '%s': relo #%d: substituting insn #%d w/ invalid insn\n" ,
4261
+ bpf_program__title (prog , false), relo_idx , insn_idx );
4262
+ insn -> code = BPF_JMP | BPF_CALL ;
4263
+ insn -> dst_reg = 0 ;
4264
+ insn -> src_reg = 0 ;
4265
+ insn -> off = 0 ;
4266
+ /* if this instruction is reachable (not a dead code),
4267
+ * verifier will complain with the following message:
4268
+ * invalid func unknown#195896080
4269
+ */
4270
+ insn -> imm = 195896080 ; /* => 0xbad2310 => "bad relo" */
4271
+ return 0 ;
4260
4272
} else {
4261
4273
err = bpf_core_calc_field_relo (prog , relo , local_spec ,
4262
4274
& orig_val , & validate );
@@ -4268,50 +4280,47 @@ static int bpf_core_reloc_insn(struct bpf_program *prog,
4268
4280
return err ;
4269
4281
}
4270
4282
4271
- insn = & prog -> insns [insn_idx ];
4272
- class = BPF_CLASS (insn -> code );
4273
-
4274
4283
switch (class ) {
4275
4284
case BPF_ALU :
4276
4285
case BPF_ALU64 :
4277
4286
if (BPF_SRC (insn -> code ) != BPF_K )
4278
4287
return - EINVAL ;
4279
- if (! failed && validate && insn -> imm != orig_val ) {
4280
- pr_warn ("prog '%s': unexpected insn #%d (ALU/ALU64) value: got %u, exp %u -> %u\n" ,
4281
- bpf_program__title (prog , false), insn_idx ,
4282
- insn -> imm , orig_val , new_val );
4288
+ if (validate && insn -> imm != orig_val ) {
4289
+ pr_warn ("prog '%s': relo #%d: unexpected insn #%d (ALU/ALU64) value: got %u, exp %u -> %u\n" ,
4290
+ bpf_program__title (prog , false), relo_idx ,
4291
+ insn_idx , insn -> imm , orig_val , new_val );
4283
4292
return - EINVAL ;
4284
4293
}
4285
4294
orig_val = insn -> imm ;
4286
4295
insn -> imm = new_val ;
4287
- pr_debug ("prog '%s': patched insn #%d (ALU/ALU64)%s imm %u -> %u\n" ,
4288
- bpf_program__title (prog , false), insn_idx ,
4289
- failed ? " w/ failed reloc" : "" , orig_val , new_val );
4296
+ pr_debug ("prog '%s': relo #%d: patched insn #%d (ALU/ALU64) imm %u -> %u\n" ,
4297
+ bpf_program__title (prog , false), relo_idx , insn_idx ,
4298
+ orig_val , new_val );
4290
4299
break ;
4291
4300
case BPF_LDX :
4292
4301
case BPF_ST :
4293
4302
case BPF_STX :
4294
- if (! failed && validate && insn -> off != orig_val ) {
4295
- pr_warn ("prog '%s': unexpected insn #%d (LD/LDX/ST/STX) value: got %u, exp %u -> %u\n" ,
4296
- bpf_program__title (prog , false), insn_idx ,
4297
- insn -> off , orig_val , new_val );
4303
+ if (validate && insn -> off != orig_val ) {
4304
+ pr_warn ("prog '%s': relo #%d: unexpected insn #%d (LD/LDX/ST/STX) value: got %u, exp %u -> %u\n" ,
4305
+ bpf_program__title (prog , false), relo_idx ,
4306
+ insn_idx , insn -> off , orig_val , new_val );
4298
4307
return - EINVAL ;
4299
4308
}
4300
4309
if (new_val > SHRT_MAX ) {
4301
- pr_warn ("prog '%s': insn #%d (LD/ LDX/ST/STX) value too big: %u\n" ,
4302
- bpf_program__title (prog , false), insn_idx ,
4303
- new_val );
4310
+ pr_warn ("prog '%s': relo #%d: insn #%d (LDX/ST/STX) value too big: %u\n" ,
4311
+ bpf_program__title (prog , false), relo_idx ,
4312
+ insn_idx , new_val );
4304
4313
return - ERANGE ;
4305
4314
}
4306
4315
orig_val = insn -> off ;
4307
4316
insn -> off = new_val ;
4308
- pr_debug ("prog '%s': patched insn #%d (LD/ LDX/ST/STX)%s off %u -> %u\n" ,
4309
- bpf_program__title (prog , false), insn_idx ,
4310
- failed ? " w/ failed reloc" : "" , orig_val , new_val );
4317
+ pr_debug ("prog '%s': relo #%d: patched insn #%d (LDX/ST/STX) off %u -> %u\n" ,
4318
+ bpf_program__title (prog , false), relo_idx , insn_idx ,
4319
+ orig_val , new_val );
4311
4320
break ;
4312
4321
default :
4313
- pr_warn ("prog '%s': trying to relocate unrecognized insn #%d, code:%x, src:%x, dst:%x, off:%x, imm:%x\n" ,
4314
- bpf_program__title (prog , false),
4322
+ pr_warn ("prog '%s': relo #%d: trying to relocate unrecognized insn #%d, code:%x, src:%x, dst:%x, off:%x, imm:%x\n" ,
4323
+ bpf_program__title (prog , false), relo_idx ,
4315
4324
insn_idx , insn -> code , insn -> src_reg , insn -> dst_reg ,
4316
4325
insn -> off , insn -> imm );
4317
4326
return - EINVAL ;
@@ -4510,24 +4519,33 @@ static int bpf_core_reloc_field(struct bpf_program *prog,
4510
4519
}
4511
4520
4512
4521
/*
4513
- * For BPF_FIELD_EXISTS relo or when relaxed CO-RE reloc mode is
4514
- * requested, it's expected that we might not find any candidates.
4515
- * In this case, if field wasn't found in any candidate, the list of
4516
- * candidates shouldn't change at all, we'll just handle relocating
4517
- * appropriately, depending on relo's kind.
4522
+ * For BPF_FIELD_EXISTS relo or when used BPF program has field
4523
+ * existence checks or kernel version/config checks, it's expected
4524
+ * that we might not find any candidates. In this case, if field
4525
+ * wasn't found in any candidate, the list of candidates shouldn't
4526
+ * change at all, we'll just handle relocating appropriately,
4527
+ * depending on relo's kind.
4518
4528
*/
4519
4529
if (j > 0 )
4520
4530
cand_ids -> len = j ;
4521
4531
4522
- if (j == 0 && !prog -> obj -> relaxed_core_relocs &&
4523
- relo -> kind != BPF_FIELD_EXISTS ) {
4524
- pr_warn ("prog '%s': relo #%d: no matching targets found for [%d] %s + %s\n" ,
4525
- prog_name , relo_idx , local_id , local_name , spec_str );
4526
- return - ESRCH ;
4527
- }
4532
+ /*
4533
+ * If no candidates were found, it might be both a programmer error,
4534
+ * as well as expected case, depending whether instruction w/
4535
+ * relocation is guarded in some way that makes it unreachable (dead
4536
+ * code) if relocation can't be resolved. This is handled in
4537
+ * bpf_core_reloc_insn() uniformly by replacing that instruction with
4538
+ * BPF helper call insn (using invalid helper ID). If that instruction
4539
+ * is indeed unreachable, then it will be ignored and eliminated by
4540
+ * verifier. If it was an error, then verifier will complain and point
4541
+ * to a specific instruction number in its log.
4542
+ */
4543
+ if (j == 0 )
4544
+ pr_debug ("prog '%s': relo #%d: no matching targets found for [%d] %s + %s\n" ,
4545
+ prog_name , relo_idx , local_id , local_name , spec_str );
4528
4546
4529
4547
/* bpf_core_reloc_insn should know how to handle missing targ_spec */
4530
- err = bpf_core_reloc_insn (prog , relo , & local_spec ,
4548
+ err = bpf_core_reloc_insn (prog , relo , relo_idx , & local_spec ,
4531
4549
j ? & targ_spec : NULL );
4532
4550
if (err ) {
4533
4551
pr_warn ("prog '%s': relo #%d: failed to patch insn at offset %d: %d\n" ,
@@ -5057,7 +5075,6 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
5057
5075
if (IS_ERR (obj ))
5058
5076
return obj ;
5059
5077
5060
- obj -> relaxed_core_relocs = OPTS_GET (opts , relaxed_core_relocs , false);
5061
5078
kconfig = OPTS_GET (opts , kconfig , NULL );
5062
5079
if (kconfig ) {
5063
5080
obj -> kconfig = strdup (kconfig );
0 commit comments