summaryrefslogtreecommitdiff
path: root/tools/lib/bpf/gen_loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib/bpf/gen_loader.c')
-rw-r--r--tools/lib/bpf/gen_loader.c81
1 files changed, 58 insertions, 23 deletions
diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
index 9478b8f78f26..40004aa3af71 100644
--- a/tools/lib/bpf/gen_loader.c
+++ b/tools/lib/bpf/gen_loader.c
@@ -398,13 +398,12 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
blob_fd_array_off(gen, i));
emit(gen, BPF_MOV64_IMM(BPF_REG_0, 0));
emit(gen, BPF_EXIT_INSN());
- if (OPTS_GET(gen->opts, gen_hash, false))
- compute_sha_update_offsets(gen);
-
- pr_debug("gen: finish %s\n", errstr(gen->error));
if (!gen->error) {
struct gen_loader_opts *opts = gen->opts;
+ if (OPTS_GET(opts, gen_hash, false))
+ compute_sha_update_offsets(gen);
+
opts->insns = gen->insn_start;
opts->insns_sz = gen->insn_cur - gen->insn_start;
opts->data = gen->data_start;
@@ -419,6 +418,7 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
bpf_insn_bswap(insn++);
}
}
+ pr_debug("gen: finish %s\n", errstr(gen->error));
return gen->error;
}
@@ -545,13 +545,22 @@ void bpf_gen__map_create(struct bpf_gen *gen,
default:
break;
}
- /* conditionally update max_entries */
- if (map_idx >= 0)
+
+ /*
+ * Conditionally update max_entries from the host-supplied loader
+ * ctx. This sizes the map at runtime, but for a signed loader
+ * (gen_hash) it would let an untrusted host re-dimension the
+ * program's maps after emit_signature_match(), outside what the
+ * signature attests to. Keep the signer-provided max_entries
+ * baked into the blob in that case.
+ */
+ if (map_idx >= 0 && !OPTS_GET(gen->opts, gen_hash, false))
move_ctx2blob(gen, attr_field(map_create_attr, max_entries), 4,
sizeof(struct bpf_loader_ctx) +
sizeof(struct bpf_map_desc) * map_idx +
offsetof(struct bpf_map_desc, max_entries),
true /* check that max_entries != 0 */);
+
/* emit MAP_CREATE command */
emit_sys_bpf(gen, BPF_MAP_CREATE, map_create_attr, attr_size);
debug_ret(gen, "map_create %s idx %d type %d value_size %d value_btf_id %d",
@@ -585,6 +594,23 @@ static void emit_signature_match(struct bpf_gen *gen)
__s64 off;
int i;
+ /*
+ * Reject if the metadata map is not exclusive. Without exclusivity
+ * the cached map->sha[] verified above can be stale: another BPF
+ * program with map access could have mutated the contents between
+ * BPF_OBJ_GET_INFO_BY_FD and loader execution.
+ */
+ emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
+ 0, 0, 0, 0));
+ emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, SHA256_DIGEST_LENGTH));
+ off = -(gen->insn_cur - gen->insn_start - gen->cleanup_label) / 8 - 2;
+ if (is_simm16(off)) {
+ emit(gen, BPF_MOV64_IMM(BPF_REG_7, -EINVAL));
+ emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 1, off));
+ } else {
+ gen->error = -ERANGE;
+ }
+
for (i = 0; i < SHA256_DWORD_SIZE; i++) {
emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX,
0, 0, 0, 0));
@@ -1053,7 +1079,7 @@ void bpf_gen__prog_load(struct bpf_gen *gen,
prog_idx, prog_type, insns_off, insn_cnt, license_off);
/* convert blob insns to target endianness */
- if (gen->swapped_endian) {
+ if (gen->swapped_endian && !gen->error) {
struct bpf_insn *insn = gen->data_start + insns_off;
int i;
@@ -1091,7 +1117,7 @@ void bpf_gen__prog_load(struct bpf_gen *gen,
sizeof(struct bpf_core_relo));
/* convert all info blobs to target endianness */
- if (gen->swapped_endian)
+ if (gen->swapped_endian && !gen->error)
info_blob_bswap(gen, func_info, line_info, core_relos, load_attr);
libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name));
@@ -1169,27 +1195,36 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue,
value = add_data(gen, pvalue, value_size);
key = add_data(gen, &zero, sizeof(zero));
- /* if (map_desc[map_idx].initial_value) {
+ /*
+ * if (map_desc[map_idx].initial_value) {
* if (ctx->flags & BPF_SKEL_KERNEL)
* bpf_probe_read_kernel(value, value_size, initial_value);
* else
* bpf_copy_from_user(value, value_size, initial_value);
* }
+ *
+ * The runtime initial_value comes from the host-supplied loader
+ * ctx and would overwrite the blob value after emit_signature_match()
+ * has already validated map->sha[]. For a signed loader (gen_hash)
+ * the attested blob value must be authoritative, so skip the override
+ * and leave the hashed value in place.
*/
- emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_6,
- sizeof(struct bpf_loader_ctx) +
- sizeof(struct bpf_map_desc) * map_idx +
- offsetof(struct bpf_map_desc, initial_value)));
- emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 8));
- emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
- 0, 0, 0, value));
- emit(gen, BPF_MOV64_IMM(BPF_REG_2, value_size));
- emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6,
- offsetof(struct bpf_loader_ctx, flags)));
- emit(gen, BPF_JMP_IMM(BPF_JSET, BPF_REG_0, BPF_SKEL_KERNEL, 2));
- emit(gen, BPF_EMIT_CALL(BPF_FUNC_copy_from_user));
- emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1));
- emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
+ if (!OPTS_GET(gen->opts, gen_hash, false)) {
+ emit(gen, BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_6,
+ sizeof(struct bpf_loader_ctx) +
+ sizeof(struct bpf_map_desc) * map_idx +
+ offsetof(struct bpf_map_desc, initial_value)));
+ emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_3, 0, 8));
+ emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_1, BPF_PSEUDO_MAP_IDX_VALUE,
+ 0, 0, 0, value));
+ emit(gen, BPF_MOV64_IMM(BPF_REG_2, value_size));
+ emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6,
+ offsetof(struct bpf_loader_ctx, flags)));
+ emit(gen, BPF_JMP_IMM(BPF_JSET, BPF_REG_0, BPF_SKEL_KERNEL, 2));
+ emit(gen, BPF_EMIT_CALL(BPF_FUNC_copy_from_user));
+ emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1));
+ emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel));
+ }
map_update_attr = add_data(gen, &attr, attr_size);
pr_debug("gen: map_update_elem: idx %d, value: off %d size %d, attr: off %d size %d\n",