diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 58 |
1 files changed, 43 insertions, 15 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index a31a1ba0f8ea..7958252a4d29 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -181,32 +181,60 @@ int bpf_map_precharge_memlock(u32 pages) | |||
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
183 | 183 | ||
184 | static int bpf_map_charge_memlock(struct bpf_map *map) | 184 | static int bpf_charge_memlock(struct user_struct *user, u32 pages) |
185 | { | 185 | { |
186 | struct user_struct *user = get_current_user(); | 186 | unsigned long memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; |
187 | unsigned long memlock_limit; | ||
188 | 187 | ||
189 | memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; | 188 | if (atomic_long_add_return(pages, &user->locked_vm) > memlock_limit) { |
189 | atomic_long_sub(pages, &user->locked_vm); | ||
190 | return -EPERM; | ||
191 | } | ||
192 | return 0; | ||
193 | } | ||
190 | 194 | ||
191 | atomic_long_add(map->pages, &user->locked_vm); | 195 | static void bpf_uncharge_memlock(struct user_struct *user, u32 pages) |
196 | { | ||
197 | atomic_long_sub(pages, &user->locked_vm); | ||
198 | } | ||
199 | |||
200 | static int bpf_map_init_memlock(struct bpf_map *map) | ||
201 | { | ||
202 | struct user_struct *user = get_current_user(); | ||
203 | int ret; | ||
192 | 204 | ||
193 | if (atomic_long_read(&user->locked_vm) > memlock_limit) { | 205 | ret = bpf_charge_memlock(user, map->pages); |
194 | atomic_long_sub(map->pages, &user->locked_vm); | 206 | if (ret) { |
195 | free_uid(user); | 207 | free_uid(user); |
196 | return -EPERM; | 208 | return ret; |
197 | } | 209 | } |
198 | map->user = user; | 210 | map->user = user; |
199 | return 0; | 211 | return ret; |
200 | } | 212 | } |
201 | 213 | ||
202 | static void bpf_map_uncharge_memlock(struct bpf_map *map) | 214 | static void bpf_map_release_memlock(struct bpf_map *map) |
203 | { | 215 | { |
204 | struct user_struct *user = map->user; | 216 | struct user_struct *user = map->user; |
205 | 217 | bpf_uncharge_memlock(user, map->pages); | |
206 | atomic_long_sub(map->pages, &user->locked_vm); | ||
207 | free_uid(user); | 218 | free_uid(user); |
208 | } | 219 | } |
209 | 220 | ||
221 | int bpf_map_charge_memlock(struct bpf_map *map, u32 pages) | ||
222 | { | ||
223 | int ret; | ||
224 | |||
225 | ret = bpf_charge_memlock(map->user, pages); | ||
226 | if (ret) | ||
227 | return ret; | ||
228 | map->pages += pages; | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | void bpf_map_uncharge_memlock(struct bpf_map *map, u32 pages) | ||
233 | { | ||
234 | bpf_uncharge_memlock(map->user, pages); | ||
235 | map->pages -= pages; | ||
236 | } | ||
237 | |||
210 | static int bpf_map_alloc_id(struct bpf_map *map) | 238 | static int bpf_map_alloc_id(struct bpf_map *map) |
211 | { | 239 | { |
212 | int id; | 240 | int id; |
@@ -256,7 +284,7 @@ static void bpf_map_free_deferred(struct work_struct *work) | |||
256 | { | 284 | { |
257 | struct bpf_map *map = container_of(work, struct bpf_map, work); | 285 | struct bpf_map *map = container_of(work, struct bpf_map, work); |
258 | 286 | ||
259 | bpf_map_uncharge_memlock(map); | 287 | bpf_map_release_memlock(map); |
260 | security_bpf_map_free(map); | 288 | security_bpf_map_free(map); |
261 | /* implementation dependent freeing */ | 289 | /* implementation dependent freeing */ |
262 | map->ops->map_free(map); | 290 | map->ops->map_free(map); |
@@ -492,7 +520,7 @@ static int map_create(union bpf_attr *attr) | |||
492 | if (err) | 520 | if (err) |
493 | goto free_map_nouncharge; | 521 | goto free_map_nouncharge; |
494 | 522 | ||
495 | err = bpf_map_charge_memlock(map); | 523 | err = bpf_map_init_memlock(map); |
496 | if (err) | 524 | if (err) |
497 | goto free_map_sec; | 525 | goto free_map_sec; |
498 | 526 | ||
@@ -515,7 +543,7 @@ static int map_create(union bpf_attr *attr) | |||
515 | return err; | 543 | return err; |
516 | 544 | ||
517 | free_map: | 545 | free_map: |
518 | bpf_map_uncharge_memlock(map); | 546 | bpf_map_release_memlock(map); |
519 | free_map_sec: | 547 | free_map_sec: |
520 | security_bpf_map_free(map); | 548 | security_bpf_map_free(map); |
521 | free_map_nouncharge: | 549 | free_map_nouncharge: |