aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2017-06-05 15:15:49 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-06 15:41:23 -0400
commitb16d9aa4c2b90af8d2c3201e245150f8c430c3bc (patch)
tree2fc2f74214723830c29d5f7370870507a97b7387 /kernel/bpf/syscall.c
parent34ad5580f8f9c86cb273ebea25c149613cd1667e (diff)
bpf: Add BPF_PROG_GET_FD_BY_ID
Add BPF_PROG_GET_FD_BY_ID command to allow user to get a fd from a bpf_prog's ID. bpf_prog_inc_not_zero() is added and is called with prog_idr_lock held. __bpf_prog_put() is also added which has the 'bool do_idr_lock' param to decide if the prog_idr_lock should be acquired when freeing the prog->id. In the error path of bpf_prog_inc_not_zero(), it may have to call __bpf_prog_put(map, false) which does not need to take the prog_idr_lock when freeing the prog->id. It is currently limited to CAP_SYS_ADMIN which we can consider to lift it in followup patches. Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Alexei Starovoitov <ast@fb.com> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r--kernel/bpf/syscall.c91
1 files changed, 81 insertions, 10 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 2405feedb8c1..dc6253bb8ebb 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -703,15 +703,23 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog)
703 return id > 0 ? 0 : id; 703 return id > 0 ? 0 : id;
704} 704}
705 705
706static void bpf_prog_free_id(struct bpf_prog *prog) 706static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
707{ 707{
708 /* cBPF to eBPF migrations are currently not in the idr store. */ 708 /* cBPF to eBPF migrations are currently not in the idr store. */
709 if (!prog->aux->id) 709 if (!prog->aux->id)
710 return; 710 return;
711 711
712 spin_lock_bh(&prog_idr_lock); 712 if (do_idr_lock)
713 spin_lock_bh(&prog_idr_lock);
714 else
715 __acquire(&prog_idr_lock);
716
713 idr_remove(&prog_idr, prog->aux->id); 717 idr_remove(&prog_idr, prog->aux->id);
714 spin_unlock_bh(&prog_idr_lock); 718
719 if (do_idr_lock)
720 spin_unlock_bh(&prog_idr_lock);
721 else
722 __release(&prog_idr_lock);
715} 723}
716 724
717static void __bpf_prog_put_rcu(struct rcu_head *rcu) 725static void __bpf_prog_put_rcu(struct rcu_head *rcu)
@@ -723,16 +731,21 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
723 bpf_prog_free(aux->prog); 731 bpf_prog_free(aux->prog);
724} 732}
725 733
726void bpf_prog_put(struct bpf_prog *prog) 734static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
727{ 735{
728 if (atomic_dec_and_test(&prog->aux->refcnt)) { 736 if (atomic_dec_and_test(&prog->aux->refcnt)) {
729 trace_bpf_prog_put_rcu(prog); 737 trace_bpf_prog_put_rcu(prog);
730 /* bpf_prog_free_id() must be called first */ 738 /* bpf_prog_free_id() must be called first */
731 bpf_prog_free_id(prog); 739 bpf_prog_free_id(prog, do_idr_lock);
732 bpf_prog_kallsyms_del(prog); 740 bpf_prog_kallsyms_del(prog);
733 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); 741 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
734 } 742 }
735} 743}
744
745void bpf_prog_put(struct bpf_prog *prog)
746{
747 __bpf_prog_put(prog, true);
748}
736EXPORT_SYMBOL_GPL(bpf_prog_put); 749EXPORT_SYMBOL_GPL(bpf_prog_put);
737 750
738static int bpf_prog_release(struct inode *inode, struct file *filp) 751static int bpf_prog_release(struct inode *inode, struct file *filp)
@@ -814,6 +827,24 @@ struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
814} 827}
815EXPORT_SYMBOL_GPL(bpf_prog_inc); 828EXPORT_SYMBOL_GPL(bpf_prog_inc);
816 829
830/* prog_idr_lock should have been held */
831static struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
832{
833 int refold;
834
835 refold = __atomic_add_unless(&prog->aux->refcnt, 1, 0);
836
837 if (refold >= BPF_MAX_REFCNT) {
838 __bpf_prog_put(prog, false);
839 return ERR_PTR(-EBUSY);
840 }
841
842 if (!refold)
843 return ERR_PTR(-ENOENT);
844
845 return prog;
846}
847
817static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type) 848static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type)
818{ 849{
819 struct fd f = fdget(ufd); 850 struct fd f = fdget(ufd);
@@ -928,16 +959,21 @@ static int bpf_prog_load(union bpf_attr *attr)
928 goto free_used_maps; 959 goto free_used_maps;
929 960
930 err = bpf_prog_new_fd(prog); 961 err = bpf_prog_new_fd(prog);
931 if (err < 0) 962 if (err < 0) {
932 /* failed to allocate fd */ 963 /* failed to allocate fd.
933 goto free_id; 964 * bpf_prog_put() is needed because the above
965 * bpf_prog_alloc_id() has published the prog
966 * to the userspace and the userspace may
967 * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID.
968 */
969 bpf_prog_put(prog);
970 return err;
971 }
934 972
935 bpf_prog_kallsyms_add(prog); 973 bpf_prog_kallsyms_add(prog);
936 trace_bpf_prog_load(prog, err); 974 trace_bpf_prog_load(prog, err);
937 return err; 975 return err;
938 976
939free_id:
940 bpf_prog_free_id(prog);
941free_used_maps: 977free_used_maps:
942 free_used_maps(prog->aux); 978 free_used_maps(prog->aux);
943free_prog: 979free_prog:
@@ -1099,6 +1135,38 @@ static int bpf_obj_get_next_id(const union bpf_attr *attr,
1099 return err; 1135 return err;
1100} 1136}
1101 1137
1138#define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
1139
1140static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
1141{
1142 struct bpf_prog *prog;
1143 u32 id = attr->prog_id;
1144 int fd;
1145
1146 if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
1147 return -EINVAL;
1148
1149 if (!capable(CAP_SYS_ADMIN))
1150 return -EPERM;
1151
1152 spin_lock_bh(&prog_idr_lock);
1153 prog = idr_find(&prog_idr, id);
1154 if (prog)
1155 prog = bpf_prog_inc_not_zero(prog);
1156 else
1157 prog = ERR_PTR(-ENOENT);
1158 spin_unlock_bh(&prog_idr_lock);
1159
1160 if (IS_ERR(prog))
1161 return PTR_ERR(prog);
1162
1163 fd = bpf_prog_new_fd(prog);
1164 if (fd < 0)
1165 bpf_prog_put(prog);
1166
1167 return fd;
1168}
1169
1102SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) 1170SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
1103{ 1171{
1104 union bpf_attr attr = {}; 1172 union bpf_attr attr = {};
@@ -1184,6 +1252,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
1184 err = bpf_obj_get_next_id(&attr, uattr, 1252 err = bpf_obj_get_next_id(&attr, uattr,
1185 &map_idr, &map_idr_lock); 1253 &map_idr, &map_idr_lock);
1186 break; 1254 break;
1255 case BPF_PROG_GET_FD_BY_ID:
1256 err = bpf_prog_get_fd_by_id(&attr);
1257 break;
1187 default: 1258 default:
1188 err = -EINVAL; 1259 err = -EINVAL;
1189 break; 1260 break;