diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 45 |
1 files changed, 42 insertions, 3 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 84470d1480aa..797a99c7493e 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -463,7 +463,7 @@ int map_check_no_btf(const struct bpf_map *map, | |||
463 | return -ENOTSUPP; | 463 | return -ENOTSUPP; |
464 | } | 464 | } |
465 | 465 | ||
466 | static int map_check_btf(const struct bpf_map *map, const struct btf *btf, | 466 | static int map_check_btf(struct bpf_map *map, const struct btf *btf, |
467 | u32 btf_key_id, u32 btf_value_id) | 467 | u32 btf_key_id, u32 btf_value_id) |
468 | { | 468 | { |
469 | const struct btf_type *key_type, *value_type; | 469 | const struct btf_type *key_type, *value_type; |
@@ -478,6 +478,22 @@ static int map_check_btf(const struct bpf_map *map, const struct btf *btf, | |||
478 | if (!value_type || value_size != map->value_size) | 478 | if (!value_type || value_size != map->value_size) |
479 | return -EINVAL; | 479 | return -EINVAL; |
480 | 480 | ||
481 | map->spin_lock_off = btf_find_spin_lock(btf, value_type); | ||
482 | |||
483 | if (map_value_has_spin_lock(map)) { | ||
484 | if (map->map_type != BPF_MAP_TYPE_HASH && | ||
485 | map->map_type != BPF_MAP_TYPE_ARRAY && | ||
486 | map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE) | ||
487 | return -ENOTSUPP; | ||
488 | if (map->spin_lock_off + sizeof(struct bpf_spin_lock) > | ||
489 | map->value_size) { | ||
490 | WARN_ONCE(1, | ||
491 | "verifier bug spin_lock_off %d value_size %d\n", | ||
492 | map->spin_lock_off, map->value_size); | ||
493 | return -EFAULT; | ||
494 | } | ||
495 | } | ||
496 | |||
481 | if (map->ops->map_check_btf) | 497 | if (map->ops->map_check_btf) |
482 | ret = map->ops->map_check_btf(map, btf, key_type, value_type); | 498 | ret = map->ops->map_check_btf(map, btf, key_type, value_type); |
483 | 499 | ||
@@ -542,6 +558,8 @@ static int map_create(union bpf_attr *attr) | |||
542 | map->btf = btf; | 558 | map->btf = btf; |
543 | map->btf_key_type_id = attr->btf_key_type_id; | 559 | map->btf_key_type_id = attr->btf_key_type_id; |
544 | map->btf_value_type_id = attr->btf_value_type_id; | 560 | map->btf_value_type_id = attr->btf_value_type_id; |
561 | } else { | ||
562 | map->spin_lock_off = -EINVAL; | ||
545 | } | 563 | } |
546 | 564 | ||
547 | err = security_bpf_map_alloc(map); | 565 | err = security_bpf_map_alloc(map); |
@@ -664,7 +682,7 @@ static void *__bpf_copy_key(void __user *ukey, u64 key_size) | |||
664 | } | 682 | } |
665 | 683 | ||
666 | /* last field in 'union bpf_attr' used by this command */ | 684 | /* last field in 'union bpf_attr' used by this command */ |
667 | #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value | 685 | #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags |
668 | 686 | ||
669 | static int map_lookup_elem(union bpf_attr *attr) | 687 | static int map_lookup_elem(union bpf_attr *attr) |
670 | { | 688 | { |
@@ -680,6 +698,9 @@ static int map_lookup_elem(union bpf_attr *attr) | |||
680 | if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) | 698 | if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) |
681 | return -EINVAL; | 699 | return -EINVAL; |
682 | 700 | ||
701 | if (attr->flags & ~BPF_F_LOCK) | ||
702 | return -EINVAL; | ||
703 | |||
683 | f = fdget(ufd); | 704 | f = fdget(ufd); |
684 | map = __bpf_map_get(f); | 705 | map = __bpf_map_get(f); |
685 | if (IS_ERR(map)) | 706 | if (IS_ERR(map)) |
@@ -690,6 +711,12 @@ static int map_lookup_elem(union bpf_attr *attr) | |||
690 | goto err_put; | 711 | goto err_put; |
691 | } | 712 | } |
692 | 713 | ||
714 | if ((attr->flags & BPF_F_LOCK) && | ||
715 | !map_value_has_spin_lock(map)) { | ||
716 | err = -EINVAL; | ||
717 | goto err_put; | ||
718 | } | ||
719 | |||
693 | key = __bpf_copy_key(ukey, map->key_size); | 720 | key = __bpf_copy_key(ukey, map->key_size); |
694 | if (IS_ERR(key)) { | 721 | if (IS_ERR(key)) { |
695 | err = PTR_ERR(key); | 722 | err = PTR_ERR(key); |
@@ -745,7 +772,13 @@ static int map_lookup_elem(union bpf_attr *attr) | |||
745 | err = -ENOENT; | 772 | err = -ENOENT; |
746 | } else { | 773 | } else { |
747 | err = 0; | 774 | err = 0; |
748 | memcpy(value, ptr, value_size); | 775 | if (attr->flags & BPF_F_LOCK) |
776 | /* lock 'ptr' and copy everything but lock */ | ||
777 | copy_map_value_locked(map, value, ptr, true); | ||
778 | else | ||
779 | copy_map_value(map, value, ptr); | ||
780 | /* mask lock, since value wasn't zero inited */ | ||
781 | check_and_init_map_lock(map, value); | ||
749 | } | 782 | } |
750 | rcu_read_unlock(); | 783 | rcu_read_unlock(); |
751 | } | 784 | } |
@@ -808,6 +841,12 @@ static int map_update_elem(union bpf_attr *attr) | |||
808 | goto err_put; | 841 | goto err_put; |
809 | } | 842 | } |
810 | 843 | ||
844 | if ((attr->flags & BPF_F_LOCK) && | ||
845 | !map_value_has_spin_lock(map)) { | ||
846 | err = -EINVAL; | ||
847 | goto err_put; | ||
848 | } | ||
849 | |||
811 | key = __bpf_copy_key(ukey, map->key_size); | 850 | key = __bpf_copy_key(ukey, map->key_size); |
812 | if (IS_ERR(key)) { | 851 | if (IS_ERR(key)) { |
813 | err = PTR_ERR(key); | 852 | err = PTR_ERR(key); |