@@ -703,15 +703,23 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog)
703
703
return id > 0 ? 0 : id ;
704
704
}
705
705
706
- static void bpf_prog_free_id (struct bpf_prog * prog )
706
+ static void bpf_prog_free_id (struct bpf_prog * prog , bool do_idr_lock )
707
707
{
708
708
/* cBPF to eBPF migrations are currently not in the idr store. */
709
709
if (!prog -> aux -> id )
710
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
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
717
725
static void __bpf_prog_put_rcu (struct rcu_head * rcu )
@@ -723,16 +731,21 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
723
731
bpf_prog_free (aux -> prog );
724
732
}
725
733
726
- void bpf_prog_put (struct bpf_prog * prog )
734
+ static void __bpf_prog_put (struct bpf_prog * prog , bool do_idr_lock )
727
735
{
728
736
if (atomic_dec_and_test (& prog -> aux -> refcnt )) {
729
737
trace_bpf_prog_put_rcu (prog );
730
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
740
bpf_prog_kallsyms_del (prog );
733
741
call_rcu (& prog -> aux -> rcu , __bpf_prog_put_rcu );
734
742
}
735
743
}
744
+
745
+ void bpf_prog_put (struct bpf_prog * prog )
746
+ {
747
+ __bpf_prog_put (prog , true);
748
+ }
736
749
EXPORT_SYMBOL_GPL (bpf_prog_put );
737
750
738
751
static 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
}
815
828
EXPORT_SYMBOL_GPL (bpf_prog_inc );
816
829
830
+ /* prog_idr_lock should have been held */
831
+ static 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
+
817
848
static struct bpf_prog * __bpf_prog_get (u32 ufd , enum bpf_prog_type * type )
818
849
{
819
850
struct fd f = fdget (ufd );
@@ -928,16 +959,21 @@ static int bpf_prog_load(union bpf_attr *attr)
928
959
goto free_used_maps ;
929
960
930
961
err = bpf_prog_new_fd (prog );
931
- if (err < 0 )
932
- /* failed to allocate fd */
933
- goto free_id ;
962
+ if (err < 0 ) {
963
+ /* failed to allocate fd.
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
973
bpf_prog_kallsyms_add (prog );
936
974
trace_bpf_prog_load (prog , err );
937
975
return err ;
938
976
939
- free_id :
940
- bpf_prog_free_id (prog );
941
977
free_used_maps :
942
978
free_used_maps (prog -> aux );
943
979
free_prog :
@@ -1099,6 +1135,38 @@ static int bpf_obj_get_next_id(const union bpf_attr *attr,
1099
1135
return err ;
1100
1136
}
1101
1137
1138
+ #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
1139
+
1140
+ static 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
+
1102
1170
SYSCALL_DEFINE3 (bpf , int , cmd , union bpf_attr __user * , uattr , unsigned int , size )
1103
1171
{
1104
1172
union bpf_attr attr = {};
@@ -1184,6 +1252,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
1184
1252
err = bpf_obj_get_next_id (& attr , uattr ,
1185
1253
& map_idr , & map_idr_lock );
1186
1254
break ;
1255
+ case BPF_PROG_GET_FD_BY_ID :
1256
+ err = bpf_prog_get_fd_by_id (& attr );
1257
+ break ;
1187
1258
default :
1188
1259
err = - EINVAL ;
1189
1260
break ;
0 commit comments