25
25
(keyring)->payload.subscriptions, \
26
26
rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
27
27
28
+ #define rcu_deref_link_locked (klist , index , keyring ) \
29
+ (rcu_dereference_protected( \
30
+ (klist)->keys[index], \
31
+ rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
32
+
28
33
#define KEY_LINK_FIXQUOTA 1UL
29
34
30
35
/*
@@ -138,6 +143,11 @@ static int keyring_match(const struct key *keyring, const void *description)
138
143
/*
139
144
* Clean up a keyring when it is destroyed. Unpublish its name if it had one
140
145
* and dispose of its data.
146
+ *
147
+ * The garbage collector detects the final key_put(), removes the keyring from
148
+ * the serial number tree and then does RCU synchronisation before coming here,
149
+ * so we shouldn't need to worry about code poking around here with the RCU
150
+ * readlock held by this time.
141
151
*/
142
152
static void keyring_destroy (struct key * keyring )
143
153
{
@@ -154,11 +164,10 @@ static void keyring_destroy(struct key *keyring)
154
164
write_unlock (& keyring_name_lock );
155
165
}
156
166
157
- klist = rcu_dereference_check (keyring -> payload .subscriptions ,
158
- atomic_read (& keyring -> usage ) == 0 );
167
+ klist = rcu_access_pointer (keyring -> payload .subscriptions );
159
168
if (klist ) {
160
169
for (loop = klist -> nkeys - 1 ; loop >= 0 ; loop -- )
161
- key_put (klist -> keys [loop ]);
170
+ key_put (rcu_access_pointer ( klist -> keys [loop ]) );
162
171
kfree (klist );
163
172
}
164
173
}
@@ -214,7 +223,8 @@ static long keyring_read(const struct key *keyring,
214
223
ret = - EFAULT ;
215
224
216
225
for (loop = 0 ; loop < klist -> nkeys ; loop ++ ) {
217
- key = klist -> keys [loop ];
226
+ key = rcu_deref_link_locked (klist , loop ,
227
+ keyring );
218
228
219
229
tmp = sizeof (key_serial_t );
220
230
if (tmp > buflen )
@@ -383,7 +393,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
383
393
nkeys = keylist -> nkeys ;
384
394
smp_rmb ();
385
395
for (kix = 0 ; kix < nkeys ; kix ++ ) {
386
- key = keylist -> keys [kix ];
396
+ key = rcu_dereference ( keylist -> keys [kix ]) ;
387
397
kflags = key -> flags ;
388
398
389
399
/* ignore keys not of this type */
@@ -426,7 +436,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
426
436
nkeys = keylist -> nkeys ;
427
437
smp_rmb ();
428
438
for (; kix < nkeys ; kix ++ ) {
429
- key = keylist -> keys [kix ];
439
+ key = rcu_dereference ( keylist -> keys [kix ]) ;
430
440
if (key -> type != & key_type_keyring )
431
441
continue ;
432
442
@@ -531,8 +541,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
531
541
nkeys = klist -> nkeys ;
532
542
smp_rmb ();
533
543
for (loop = 0 ; loop < nkeys ; loop ++ ) {
534
- key = klist -> keys [loop ];
535
-
544
+ key = rcu_dereference (klist -> keys [loop ]);
536
545
if (key -> type == ktype &&
537
546
(!key -> type -> match ||
538
547
key -> type -> match (key , description )) &&
@@ -654,7 +663,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
654
663
nkeys = keylist -> nkeys ;
655
664
smp_rmb ();
656
665
for (; kix < nkeys ; kix ++ ) {
657
- key = keylist -> keys [kix ];
666
+ key = rcu_dereference ( keylist -> keys [kix ]) ;
658
667
659
668
if (key == A )
660
669
goto cycle_detected ;
@@ -711,7 +720,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
711
720
container_of (rcu , struct keyring_list , rcu );
712
721
713
722
if (klist -> delkey != USHRT_MAX )
714
- key_put (klist -> keys [klist -> delkey ]);
723
+ key_put (rcu_access_pointer ( klist -> keys [klist -> delkey ]) );
715
724
kfree (klist );
716
725
}
717
726
@@ -749,24 +758,16 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
749
758
/* see if there's a matching key we can displace */
750
759
if (klist && klist -> nkeys > 0 ) {
751
760
for (loop = klist -> nkeys - 1 ; loop >= 0 ; loop -- ) {
752
- if (klist -> keys [loop ]-> type == type &&
753
- strcmp (klist -> keys [loop ]-> description ,
754
- description ) == 0
755
- ) {
756
- /* found a match - we'll replace this one with
757
- * the new key */
758
- size = sizeof (struct key * ) * klist -> maxkeys ;
759
- size += sizeof (* klist );
760
- BUG_ON (size > PAGE_SIZE );
761
-
762
- ret = - ENOMEM ;
763
- nklist = kmemdup (klist , size , GFP_KERNEL );
764
- if (!nklist )
765
- goto error_sem ;
766
-
767
- /* note replacement slot */
768
- klist -> delkey = nklist -> delkey = loop ;
769
- prealloc = (unsigned long )nklist ;
761
+ struct key * key = rcu_deref_link_locked (klist , loop ,
762
+ keyring );
763
+ if (key -> type == type &&
764
+ strcmp (key -> description , description ) == 0 ) {
765
+ /* Found a match - we'll replace the link with
766
+ * one to the new key. We record the slot
767
+ * position.
768
+ */
769
+ klist -> delkey = loop ;
770
+ prealloc = 0 ;
770
771
goto done ;
771
772
}
772
773
}
@@ -780,7 +781,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
780
781
781
782
if (klist && klist -> nkeys < klist -> maxkeys ) {
782
783
/* there's sufficient slack space to append directly */
783
- nklist = NULL ;
784
+ klist -> delkey = klist -> nkeys ;
784
785
prealloc = KEY_LINK_FIXQUOTA ;
785
786
} else {
786
787
/* grow the key list */
@@ -813,10 +814,10 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
813
814
}
814
815
815
816
/* add the key into the new space */
816
- nklist -> keys [nklist -> delkey ] = NULL ;
817
+ RCU_INIT_POINTER (nklist -> keys [nklist -> delkey ], NULL );
818
+ prealloc = (unsigned long )nklist | KEY_LINK_FIXQUOTA ;
817
819
}
818
820
819
- prealloc = (unsigned long )nklist | KEY_LINK_FIXQUOTA ;
820
821
done :
821
822
* _prealloc = prealloc ;
822
823
kleave (" = 0" );
@@ -862,6 +863,7 @@ void __key_link(struct key *keyring, struct key *key,
862
863
unsigned long * _prealloc )
863
864
{
864
865
struct keyring_list * klist , * nklist ;
866
+ struct key * discard ;
865
867
866
868
nklist = (struct keyring_list * )(* _prealloc & ~KEY_LINK_FIXQUOTA );
867
869
* _prealloc = 0 ;
@@ -875,10 +877,10 @@ void __key_link(struct key *keyring, struct key *key,
875
877
/* there's a matching key we can displace or an empty slot in a newly
876
878
* allocated list we can fill */
877
879
if (nklist ) {
878
- kdebug ("replace %hu/%hu/%hu" ,
880
+ kdebug ("reissue %hu/%hu/%hu" ,
879
881
nklist -> delkey , nklist -> nkeys , nklist -> maxkeys );
880
882
881
- nklist -> keys [nklist -> delkey ] = key ;
883
+ RCU_INIT_POINTER ( nklist -> keys [nklist -> delkey ], key ) ;
882
884
883
885
rcu_assign_pointer (keyring -> payload .subscriptions , nklist );
884
886
@@ -889,9 +891,23 @@ void __key_link(struct key *keyring, struct key *key,
889
891
klist -> delkey , klist -> nkeys , klist -> maxkeys );
890
892
call_rcu (& klist -> rcu , keyring_unlink_rcu_disposal );
891
893
}
894
+ } else if (klist -> delkey < klist -> nkeys ) {
895
+ kdebug ("replace %hu/%hu/%hu" ,
896
+ klist -> delkey , klist -> nkeys , klist -> maxkeys );
897
+
898
+ discard = rcu_dereference_protected (
899
+ klist -> keys [klist -> delkey ],
900
+ rwsem_is_locked (& keyring -> sem ));
901
+ rcu_assign_pointer (klist -> keys [klist -> delkey ], key );
902
+ /* The garbage collector will take care of RCU
903
+ * synchronisation */
904
+ key_put (discard );
892
905
} else {
893
906
/* there's sufficient slack space to append directly */
894
- klist -> keys [klist -> nkeys ] = key ;
907
+ kdebug ("append %hu/%hu/%hu" ,
908
+ klist -> delkey , klist -> nkeys , klist -> maxkeys );
909
+
910
+ RCU_INIT_POINTER (klist -> keys [klist -> delkey ], key );
895
911
smp_wmb ();
896
912
klist -> nkeys ++ ;
897
913
}
@@ -998,7 +1014,7 @@ int key_unlink(struct key *keyring, struct key *key)
998
1014
if (klist ) {
999
1015
/* search the keyring for the key */
1000
1016
for (loop = 0 ; loop < klist -> nkeys ; loop ++ )
1001
- if (klist -> keys [loop ] == key )
1017
+ if (rcu_access_pointer ( klist -> keys [loop ]) == key )
1002
1018
goto key_is_present ;
1003
1019
}
1004
1020
@@ -1061,7 +1077,7 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
1061
1077
klist = container_of (rcu , struct keyring_list , rcu );
1062
1078
1063
1079
for (loop = klist -> nkeys - 1 ; loop >= 0 ; loop -- )
1064
- key_put (klist -> keys [loop ]);
1080
+ key_put (rcu_access_pointer ( klist -> keys [loop ]) );
1065
1081
1066
1082
kfree (klist );
1067
1083
}
@@ -1161,7 +1177,8 @@ void keyring_gc(struct key *keyring, time_t limit)
1161
1177
/* work out how many subscriptions we're keeping */
1162
1178
keep = 0 ;
1163
1179
for (loop = klist -> nkeys - 1 ; loop >= 0 ; loop -- )
1164
- if (!key_is_dead (klist -> keys [loop ], limit ))
1180
+ if (!key_is_dead (rcu_deref_link_locked (klist , loop , keyring ),
1181
+ limit ))
1165
1182
keep ++ ;
1166
1183
1167
1184
if (keep == klist -> nkeys )
@@ -1182,11 +1199,11 @@ void keyring_gc(struct key *keyring, time_t limit)
1182
1199
*/
1183
1200
keep = 0 ;
1184
1201
for (loop = klist -> nkeys - 1 ; loop >= 0 ; loop -- ) {
1185
- key = klist -> keys [ loop ] ;
1202
+ key = rcu_deref_link_locked ( klist , loop , keyring ) ;
1186
1203
if (!key_is_dead (key , limit )) {
1187
1204
if (keep >= max )
1188
1205
goto discard_new ;
1189
- new -> keys [keep ++ ] = key_get (key );
1206
+ RCU_INIT_POINTER ( new -> keys [keep ++ ], key_get (key ) );
1190
1207
}
1191
1208
}
1192
1209
new -> nkeys = keep ;
0 commit comments