summaryrefslogtreecommitdiff
path: root/kernel/bpf/map_iter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/map_iter.c')
-rw-r--r--kernel/bpf/map_iter.c83
1 files changed, 62 insertions, 21 deletions
diff --git a/kernel/bpf/map_iter.c b/kernel/bpf/map_iter.c
index c19b360bad9e..a58c148692e6 100644
--- a/kernel/bpf/map_iter.c
+++ b/kernel/bpf/map_iter.c
@@ -97,13 +97,57 @@ static struct bpf_iter_reg bpf_map_reg_info = {
.seq_info = &bpf_map_seq_info,
};
+/*
+ * For an iterator that hands the live map value to the program as a writable
+ * buffer: the verifier knows nothing of the map, so the special fields of the
+ * value have to lie outside of what the program may write.
+ */
+int bpf_iter_map_check_value_write(const struct bpf_prog *prog,
+ const struct bpf_map *map)
+{
+ const struct btf_record *rec = map->record;
+ const struct btf_field *field;
+ u32 i;
+
+ if (IS_ERR_OR_NULL(rec) || !prog->aux->max_rdwr_write)
+ return 0;
+
+ for (i = 0; i < rec->cnt; i++) {
+ field = &rec->fields[i];
+ if (field->offset < prog->aux->max_rdwr_write &&
+ field->offset + field->size > prog->aux->min_rdwr_write)
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,
+ const struct bpf_iter_aux_info *aux)
+{
+ const struct bpf_map *map = aux->map;
+ u32 value_size = map->value_size;
+ bool is_percpu;
+
+ is_percpu = map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
+ map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
+ map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
+ if (is_percpu)
+ value_size = round_up(value_size, 8) * num_possible_cpus();
+
+ if (prog->aux->max_rdonly_access > map->key_size ||
+ prog->aux->max_rdwr_access > value_size)
+ return -EACCES;
+
+ /* the program gets a copy of a per-cpu value */
+ return is_percpu ? 0 : bpf_iter_map_check_value_write(prog, map);
+}
+
static int bpf_iter_attach_map(struct bpf_prog *prog,
union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux)
{
- u32 key_acc_size, value_acc_size, key_size, value_size;
struct bpf_map *map;
- bool is_percpu = false;
int err = -EINVAL;
if (!linfo->map.map_fd)
@@ -117,30 +161,26 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
goto put_map;
}
- if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
- is_percpu = true;
- else if (map->map_type != BPF_MAP_TYPE_HASH &&
- map->map_type != BPF_MAP_TYPE_LRU_HASH &&
- map->map_type != BPF_MAP_TYPE_ARRAY &&
- map->map_type != BPF_MAP_TYPE_RHASH)
+ /* The value ctx arg is writable and aliases the live element. */
+ if (btf_record_has_field(map->record, BPF_RCU_HEAD)) {
+ err = -EOPNOTSUPP;
goto put_map;
+ }
- key_acc_size = prog->aux->max_rdonly_access;
- value_acc_size = prog->aux->max_rdwr_access;
- key_size = map->key_size;
- if (!is_percpu)
- value_size = map->value_size;
- else
- value_size = round_up(map->value_size, 8) * num_possible_cpus();
-
- if (key_acc_size > key_size || value_acc_size > value_size) {
- err = -EACCES;
+ if (map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
+ map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH &&
+ map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY &&
+ map->map_type != BPF_MAP_TYPE_HASH &&
+ map->map_type != BPF_MAP_TYPE_LRU_HASH &&
+ map->map_type != BPF_MAP_TYPE_ARRAY &&
+ map->map_type != BPF_MAP_TYPE_RHASH)
goto put_map;
- }
aux->map = map;
+ err = bpf_iter_map_check_prog(prog, aux);
+ if (err)
+ goto put_map;
+
return 0;
put_map:
@@ -173,6 +213,7 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = {
.target = "bpf_map_elem",
.attach_target = bpf_iter_attach_map,
.detach_target = bpf_iter_detach_map,
+ .check_prog = bpf_iter_map_check_prog,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
.ctx_arg_info_size = 2,