@@ -624,6 +624,83 @@ static struct bpf_prog_list *find_attach_entry(struct hlist_head *progs,
624
624
return NULL ;
625
625
}
626
626
627
+ static struct bpf_prog * get_anchor_prog (struct hlist_head * progs , struct bpf_prog * prog ,
628
+ u32 flags , u32 id_or_fd , struct bpf_prog_list * * ppltmp )
629
+ {
630
+ struct bpf_prog * anchor_prog = NULL , * pltmp_prog ;
631
+ bool preorder = flags & BPF_F_PREORDER ;
632
+ struct bpf_prog_list * pltmp ;
633
+ bool id = flags & BPF_F_ID ;
634
+ int ret = - EINVAL ;
635
+
636
+ if (id || id_or_fd ) {
637
+ /* flags must have BPF_F_BEFORE or BPF_F_AFTER */
638
+ if (!(flags & (BPF_F_BEFORE | BPF_F_AFTER )))
639
+ return ERR_PTR (- EINVAL );
640
+
641
+ if (id )
642
+ anchor_prog = bpf_prog_by_id (id_or_fd );
643
+ else
644
+ anchor_prog = bpf_prog_get (id_or_fd );
645
+ if (IS_ERR (anchor_prog ))
646
+ return anchor_prog ;
647
+ if (anchor_prog -> type != prog -> type )
648
+ goto out ;
649
+ }
650
+
651
+ if (!anchor_prog ) {
652
+ hlist_for_each_entry (pltmp , progs , node ) {
653
+ if ((flags & BPF_F_BEFORE ) && * ppltmp )
654
+ break ;
655
+ * ppltmp = pltmp ;
656
+ }
657
+ } else {
658
+ hlist_for_each_entry (pltmp , progs , node ) {
659
+ pltmp_prog = pltmp -> link ? pltmp -> link -> link .prog : pltmp -> prog ;
660
+ if (pltmp_prog != anchor_prog )
661
+ continue ;
662
+ if (!!(pltmp -> flags & BPF_F_PREORDER ) != preorder )
663
+ goto out ;
664
+ * ppltmp = pltmp ;
665
+ break ;
666
+ }
667
+ if (!* ppltmp ) {
668
+ ret = - ENOENT ;
669
+ goto out ;
670
+ }
671
+ }
672
+
673
+ return anchor_prog ;
674
+
675
+ out :
676
+ bpf_prog_put (anchor_prog );
677
+ return ERR_PTR (ret );
678
+ }
679
+
680
+ static int insert_pl_to_hlist (struct bpf_prog_list * pl , struct hlist_head * progs ,
681
+ struct bpf_prog * prog , u32 flags , u32 id_or_fd )
682
+ {
683
+ struct bpf_prog_list * pltmp = NULL ;
684
+ struct bpf_prog * anchor_prog ;
685
+
686
+ /* flags cannot have both BPF_F_BEFORE and BPF_F_AFTER */
687
+ if ((flags & BPF_F_BEFORE ) && (flags & BPF_F_AFTER ))
688
+ return - EINVAL ;
689
+
690
+ anchor_prog = get_anchor_prog (progs , prog , flags , id_or_fd , & pltmp );
691
+ if (IS_ERR (anchor_prog ))
692
+ return PTR_ERR (anchor_prog );
693
+
694
+ if (hlist_empty (progs ))
695
+ hlist_add_head (& pl -> node , progs );
696
+ else if (flags & BPF_F_BEFORE )
697
+ hlist_add_before (& pl -> node , & pltmp -> node );
698
+ else
699
+ hlist_add_behind (& pl -> node , & pltmp -> node );
700
+
701
+ return 0 ;
702
+ }
703
+
627
704
/**
628
705
* __cgroup_bpf_attach() - Attach the program or the link to a cgroup, and
629
706
* propagate the change to descendants
@@ -633,14 +710,17 @@ static struct bpf_prog_list *find_attach_entry(struct hlist_head *progs,
633
710
* @replace_prog: Previously attached program to replace if BPF_F_REPLACE is set
634
711
* @type: Type of attach operation
635
712
* @flags: Option flags
713
+ * @id_or_fd: Relative prog id or fd
714
+ * @revision: bpf_prog_list revision
636
715
*
637
716
* Exactly one of @prog or @link can be non-null.
638
717
* Must be called with cgroup_mutex held.
639
718
*/
640
719
static int __cgroup_bpf_attach (struct cgroup * cgrp ,
641
720
struct bpf_prog * prog , struct bpf_prog * replace_prog ,
642
721
struct bpf_cgroup_link * link ,
643
- enum bpf_attach_type type , u32 flags )
722
+ enum bpf_attach_type type , u32 flags , u32 id_or_fd ,
723
+ u64 revision )
644
724
{
645
725
u32 saved_flags = (flags & (BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI ));
646
726
struct bpf_prog * old_prog = NULL ;
@@ -656,16 +736,22 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
656
736
((flags & BPF_F_REPLACE ) && !(flags & BPF_F_ALLOW_MULTI )))
657
737
/* invalid combination */
658
738
return - EINVAL ;
739
+ if ((flags & BPF_F_REPLACE ) && (flags & (BPF_F_BEFORE | BPF_F_AFTER )))
740
+ /* only either replace or insertion with before/after */
741
+ return - EINVAL ;
659
742
if (link && (prog || replace_prog ))
660
743
/* only either link or prog/replace_prog can be specified */
661
744
return - EINVAL ;
662
745
if (!!replace_prog != !!(flags & BPF_F_REPLACE ))
663
746
/* replace_prog implies BPF_F_REPLACE, and vice versa */
664
747
return - EINVAL ;
665
748
749
+
666
750
atype = bpf_cgroup_atype_find (type , new_prog -> aux -> attach_btf_id );
667
751
if (atype < 0 )
668
752
return - EINVAL ;
753
+ if (revision && revision != cgrp -> bpf .revisions [atype ])
754
+ return - ESTALE ;
669
755
670
756
progs = & cgrp -> bpf .progs [atype ];
671
757
@@ -694,22 +780,18 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
694
780
if (pl ) {
695
781
old_prog = pl -> prog ;
696
782
} else {
697
- struct hlist_node * last = NULL ;
698
-
699
783
pl = kmalloc (sizeof (* pl ), GFP_KERNEL );
700
784
if (!pl ) {
701
785
bpf_cgroup_storages_free (new_storage );
702
786
return - ENOMEM ;
703
787
}
704
- if (hlist_empty (progs ))
705
- hlist_add_head (& pl -> node , progs );
706
- else
707
- hlist_for_each (last , progs ) {
708
- if (last -> next )
709
- continue ;
710
- hlist_add_behind (& pl -> node , last );
711
- break ;
712
- }
788
+
789
+ err = insert_pl_to_hlist (pl , progs , prog ? : link -> link .prog , flags , id_or_fd );
790
+ if (err ) {
791
+ kfree (pl );
792
+ bpf_cgroup_storages_free (new_storage );
793
+ return err ;
794
+ }
713
795
}
714
796
715
797
pl -> prog = prog ;
@@ -728,6 +810,7 @@ static int __cgroup_bpf_attach(struct cgroup *cgrp,
728
810
if (err )
729
811
goto cleanup_trampoline ;
730
812
813
+ cgrp -> bpf .revisions [atype ] += 1 ;
731
814
if (old_prog ) {
732
815
if (type == BPF_LSM_CGROUP )
733
816
bpf_trampoline_unlink_cgroup_shim (old_prog );
@@ -759,12 +842,13 @@ static int cgroup_bpf_attach(struct cgroup *cgrp,
759
842
struct bpf_prog * prog , struct bpf_prog * replace_prog ,
760
843
struct bpf_cgroup_link * link ,
761
844
enum bpf_attach_type type ,
762
- u32 flags )
845
+ u32 flags , u32 id_or_fd , u64 revision )
763
846
{
764
847
int ret ;
765
848
766
849
cgroup_lock ();
767
- ret = __cgroup_bpf_attach (cgrp , prog , replace_prog , link , type , flags );
850
+ ret = __cgroup_bpf_attach (cgrp , prog , replace_prog , link , type , flags ,
851
+ id_or_fd , revision );
768
852
cgroup_unlock ();
769
853
return ret ;
770
854
}
@@ -852,6 +936,7 @@ static int __cgroup_bpf_replace(struct cgroup *cgrp,
852
936
if (!found )
853
937
return - ENOENT ;
854
938
939
+ cgrp -> bpf .revisions [atype ] += 1 ;
855
940
old_prog = xchg (& link -> link .prog , new_prog );
856
941
replace_effective_prog (cgrp , atype , link );
857
942
bpf_prog_put (old_prog );
@@ -977,12 +1062,14 @@ static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog,
977
1062
* @prog: A program to detach or NULL
978
1063
* @link: A link to detach or NULL
979
1064
* @type: Type of detach operation
1065
+ * @revision: bpf_prog_list revision
980
1066
*
981
1067
* At most one of @prog or @link can be non-NULL.
982
1068
* Must be called with cgroup_mutex held.
983
1069
*/
984
1070
static int __cgroup_bpf_detach (struct cgroup * cgrp , struct bpf_prog * prog ,
985
- struct bpf_cgroup_link * link , enum bpf_attach_type type )
1071
+ struct bpf_cgroup_link * link , enum bpf_attach_type type ,
1072
+ u64 revision )
986
1073
{
987
1074
enum cgroup_bpf_attach_type atype ;
988
1075
struct bpf_prog * old_prog ;
@@ -1000,6 +1087,9 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
1000
1087
if (atype < 0 )
1001
1088
return - EINVAL ;
1002
1089
1090
+ if (revision && revision != cgrp -> bpf .revisions [atype ])
1091
+ return - ESTALE ;
1092
+
1003
1093
progs = & cgrp -> bpf .progs [atype ];
1004
1094
flags = cgrp -> bpf .flags [atype ];
1005
1095
@@ -1025,6 +1115,7 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
1025
1115
1026
1116
/* now can actually delete it from this cgroup list */
1027
1117
hlist_del (& pl -> node );
1118
+ cgrp -> bpf .revisions [atype ] += 1 ;
1028
1119
1029
1120
kfree (pl );
1030
1121
if (hlist_empty (progs ))
@@ -1040,12 +1131,12 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
1040
1131
}
1041
1132
1042
1133
static int cgroup_bpf_detach (struct cgroup * cgrp , struct bpf_prog * prog ,
1043
- enum bpf_attach_type type )
1134
+ enum bpf_attach_type type , u64 revision )
1044
1135
{
1045
1136
int ret ;
1046
1137
1047
1138
cgroup_lock ();
1048
- ret = __cgroup_bpf_detach (cgrp , prog , NULL , type );
1139
+ ret = __cgroup_bpf_detach (cgrp , prog , NULL , type , revision );
1049
1140
cgroup_unlock ();
1050
1141
return ret ;
1051
1142
}
@@ -1063,6 +1154,7 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
1063
1154
struct bpf_prog_array * effective ;
1064
1155
int cnt , ret = 0 , i ;
1065
1156
int total_cnt = 0 ;
1157
+ u64 revision = 0 ;
1066
1158
u32 flags ;
1067
1159
1068
1160
if (effective_query && prog_attach_flags )
@@ -1100,6 +1192,10 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
1100
1192
return - EFAULT ;
1101
1193
if (copy_to_user (& uattr -> query .prog_cnt , & total_cnt , sizeof (total_cnt )))
1102
1194
return - EFAULT ;
1195
+ if (!effective_query && from_atype == to_atype )
1196
+ revision = cgrp -> bpf .revisions [from_atype ];
1197
+ if (copy_to_user (& uattr -> query .revision , & revision , sizeof (revision )))
1198
+ return - EFAULT ;
1103
1199
if (attr -> query .prog_cnt == 0 || !prog_ids || !total_cnt )
1104
1200
/* return early if user requested only program count + flags */
1105
1201
return 0 ;
@@ -1182,7 +1278,8 @@ int cgroup_bpf_prog_attach(const union bpf_attr *attr,
1182
1278
}
1183
1279
1184
1280
ret = cgroup_bpf_attach (cgrp , prog , replace_prog , NULL ,
1185
- attr -> attach_type , attr -> attach_flags );
1281
+ attr -> attach_type , attr -> attach_flags ,
1282
+ attr -> relative_fd , attr -> expected_revision );
1186
1283
1187
1284
if (replace_prog )
1188
1285
bpf_prog_put (replace_prog );
@@ -1204,7 +1301,7 @@ int cgroup_bpf_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype)
1204
1301
if (IS_ERR (prog ))
1205
1302
prog = NULL ;
1206
1303
1207
- ret = cgroup_bpf_detach (cgrp , prog , attr -> attach_type );
1304
+ ret = cgroup_bpf_detach (cgrp , prog , attr -> attach_type , attr -> expected_revision );
1208
1305
if (prog )
1209
1306
bpf_prog_put (prog );
1210
1307
@@ -1233,7 +1330,7 @@ static void bpf_cgroup_link_release(struct bpf_link *link)
1233
1330
}
1234
1331
1235
1332
WARN_ON (__cgroup_bpf_detach (cg_link -> cgroup , NULL , cg_link ,
1236
- cg_link -> type ));
1333
+ cg_link -> type , 0 ));
1237
1334
if (cg_link -> type == BPF_LSM_CGROUP )
1238
1335
bpf_trampoline_unlink_cgroup_shim (cg_link -> link .prog );
1239
1336
@@ -1312,7 +1409,8 @@ int cgroup_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
1312
1409
struct cgroup * cgrp ;
1313
1410
int err ;
1314
1411
1315
- if (attr -> link_create .flags )
1412
+ if (attr -> link_create .flags &&
1413
+ (attr -> link_create .flags & (~(BPF_F_ID | BPF_F_BEFORE | BPF_F_AFTER | BPF_F_PREORDER ))))
1316
1414
return - EINVAL ;
1317
1415
1318
1416
cgrp = cgroup_get_from_fd (attr -> link_create .target_fd );
@@ -1336,7 +1434,9 @@ int cgroup_bpf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
1336
1434
}
1337
1435
1338
1436
err = cgroup_bpf_attach (cgrp , NULL , NULL , link ,
1339
- link -> type , BPF_F_ALLOW_MULTI );
1437
+ link -> type , BPF_F_ALLOW_MULTI | attr -> link_create .flags ,
1438
+ attr -> link_create .cgroup .relative_fd ,
1439
+ attr -> link_create .cgroup .expected_revision );
1340
1440
if (err ) {
1341
1441
bpf_link_cleanup (& link_primer );
1342
1442
goto out_put_cgroup ;
0 commit comments