@@ -18865,6 +18865,58 @@ static bool bpf_map_is_cgroup_storage(struct bpf_map *map)
18865
18865
map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE);
18866
18866
}
18867
18867
18868
+ /* Add map behind fd to used maps list, if it's not already there, and return
18869
+ * its index. Also set *reused to true if this map was already in the list of
18870
+ * used maps.
18871
+ * Returns <0 on error, or >= 0 index, on success.
18872
+ */
18873
+ static int add_used_map_from_fd(struct bpf_verifier_env *env, int fd, bool *reused)
18874
+ {
18875
+ struct fd f = fdget(fd);
18876
+ struct bpf_map *map;
18877
+ int i;
18878
+
18879
+ map = __bpf_map_get(f);
18880
+ if (IS_ERR(map)) {
18881
+ verbose(env, "fd %d is not pointing to valid bpf_map\n", fd);
18882
+ return PTR_ERR(map);
18883
+ }
18884
+
18885
+ /* check whether we recorded this map already */
18886
+ for (i = 0; i < env->used_map_cnt; i++) {
18887
+ if (env->used_maps[i] == map) {
18888
+ *reused = true;
18889
+ fdput(f);
18890
+ return i;
18891
+ }
18892
+ }
18893
+
18894
+ if (env->used_map_cnt >= MAX_USED_MAPS) {
18895
+ verbose(env, "The total number of maps per program has reached the limit of %u\n",
18896
+ MAX_USED_MAPS);
18897
+ fdput(f);
18898
+ return -E2BIG;
18899
+ }
18900
+
18901
+ if (env->prog->sleepable)
18902
+ atomic64_inc(&map->sleepable_refcnt);
18903
+
18904
+ /* hold the map. If the program is rejected by verifier,
18905
+ * the map will be released by release_maps() or it
18906
+ * will be used by the valid program until it's unloaded
18907
+ * and all maps are released in bpf_free_used_maps()
18908
+ */
18909
+ bpf_map_inc(map);
18910
+
18911
+ *reused = false;
18912
+ env->used_maps[env->used_map_cnt++] = map;
18913
+
18914
+ fdput(f);
18915
+
18916
+ return env->used_map_cnt - 1;
18917
+
18918
+ }
18919
+
18868
18920
/* find and rewrite pseudo imm in ld_imm64 instructions:
18869
18921
*
18870
18922
* 1. if it accesses map FD, replace it with actual map pointer.
@@ -18876,7 +18928,7 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
18876
18928
{
18877
18929
struct bpf_insn *insn = env->prog->insnsi;
18878
18930
int insn_cnt = env->prog->len;
18879
- int i, j, err;
18931
+ int i, err;
18880
18932
18881
18933
err = bpf_prog_calc_tag(env->prog);
18882
18934
if (err)
@@ -18893,9 +18945,10 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
18893
18945
if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW)) {
18894
18946
struct bpf_insn_aux_data *aux;
18895
18947
struct bpf_map *map;
18896
- struct fd f ;
18948
+ int map_idx ;
18897
18949
u64 addr;
18898
18950
u32 fd;
18951
+ bool reused;
18899
18952
18900
18953
if (i == insn_cnt - 1 || insn[1].code != 0 ||
18901
18954
insn[1].dst_reg != 0 || insn[1].src_reg != 0 ||
@@ -18956,20 +19009,18 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
18956
19009
break;
18957
19010
}
18958
19011
18959
- f = fdget(fd);
18960
- map = __bpf_map_get(f);
18961
- if (IS_ERR(map)) {
18962
- verbose(env, "fd %d is not pointing to valid bpf_map\n", fd);
18963
- return PTR_ERR(map);
18964
- }
19012
+ map_idx = add_used_map_from_fd(env, fd, &reused);
19013
+ if (map_idx < 0)
19014
+ return map_idx;
19015
+ map = env->used_maps[map_idx];
19016
+
19017
+ aux = &env->insn_aux_data[i];
19018
+ aux->map_index = map_idx;
18965
19019
18966
19020
err = check_map_prog_compatibility(env, map, env->prog);
18967
- if (err) {
18968
- fdput(f);
19021
+ if (err)
18969
19022
return err;
18970
- }
18971
19023
18972
- aux = &env->insn_aux_data[i];
18973
19024
if (insn[0].src_reg == BPF_PSEUDO_MAP_FD ||
18974
19025
insn[0].src_reg == BPF_PSEUDO_MAP_IDX) {
18975
19026
addr = (unsigned long)map;
@@ -18978,21 +19029,18 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
18978
19029
18979
19030
if (off >= BPF_MAX_VAR_OFF) {
18980
19031
verbose(env, "direct value offset of %u is not allowed\n", off);
18981
- fdput(f);
18982
19032
return -EINVAL;
18983
19033
}
18984
19034
18985
19035
if (!map->ops->map_direct_value_addr) {
18986
19036
verbose(env, "no direct value access support for this map type\n");
18987
- fdput(f);
18988
19037
return -EINVAL;
18989
19038
}
18990
19039
18991
19040
err = map->ops->map_direct_value_addr(map, &addr, off);
18992
19041
if (err) {
18993
19042
verbose(env, "invalid access to map value pointer, value_size=%u off=%u\n",
18994
19043
map->value_size, off);
18995
- fdput(f);
18996
19044
return err;
18997
19045
}
18998
19046
@@ -19003,70 +19051,39 @@ static int resolve_pseudo_ldimm64(struct bpf_verifier_env *env)
19003
19051
insn[0].imm = (u32)addr;
19004
19052
insn[1].imm = addr >> 32;
19005
19053
19006
- /* check whether we recorded this map already */
19007
- for (j = 0; j < env->used_map_cnt; j++) {
19008
- if (env->used_maps[j] == map) {
19009
- aux->map_index = j;
19010
- fdput(f);
19011
- goto next_insn;
19012
- }
19013
- }
19014
-
19015
- if (env->used_map_cnt >= MAX_USED_MAPS) {
19016
- verbose(env, "The total number of maps per program has reached the limit of %u\n",
19017
- MAX_USED_MAPS);
19018
- fdput(f);
19019
- return -E2BIG;
19020
- }
19021
-
19022
- if (env->prog->sleepable)
19023
- atomic64_inc(&map->sleepable_refcnt);
19024
- /* hold the map. If the program is rejected by verifier,
19025
- * the map will be released by release_maps() or it
19026
- * will be used by the valid program until it's unloaded
19027
- * and all maps are released in bpf_free_used_maps()
19028
- */
19029
- bpf_map_inc(map);
19030
-
19031
- aux->map_index = env->used_map_cnt;
19032
- env->used_maps[env->used_map_cnt++] = map;
19054
+ /* proceed with extra checks only if its newly added used map */
19055
+ if (reused)
19056
+ goto next_insn;
19033
19057
19034
19058
if (bpf_map_is_cgroup_storage(map) &&
19035
19059
bpf_cgroup_storage_assign(env->prog->aux, map)) {
19036
19060
verbose(env, "only one cgroup storage of each type is allowed\n");
19037
- fdput(f);
19038
19061
return -EBUSY;
19039
19062
}
19040
19063
if (map->map_type == BPF_MAP_TYPE_ARENA) {
19041
19064
if (env->prog->aux->arena) {
19042
19065
verbose(env, "Only one arena per program\n");
19043
- fdput(f);
19044
19066
return -EBUSY;
19045
19067
}
19046
19068
if (!env->allow_ptr_leaks || !env->bpf_capable) {
19047
19069
verbose(env, "CAP_BPF and CAP_PERFMON are required to use arena\n");
19048
- fdput(f);
19049
19070
return -EPERM;
19050
19071
}
19051
19072
if (!env->prog->jit_requested) {
19052
19073
verbose(env, "JIT is required to use arena\n");
19053
- fdput(f);
19054
19074
return -EOPNOTSUPP;
19055
19075
}
19056
19076
if (!bpf_jit_supports_arena()) {
19057
19077
verbose(env, "JIT doesn't support arena\n");
19058
- fdput(f);
19059
19078
return -EOPNOTSUPP;
19060
19079
}
19061
19080
env->prog->aux->arena = (void *)map;
19062
19081
if (!bpf_arena_get_user_vm_start(env->prog->aux->arena)) {
19063
19082
verbose(env, "arena's user address must be set via map_extra or mmap()\n");
19064
- fdput(f);
19065
19083
return -EINVAL;
19066
19084
}
19067
19085
}
19068
19086
19069
- fdput(f);
19070
19087
next_insn:
19071
19088
insn++;
19072
19089
i++;
0 commit comments