Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fs, nfs: convert nfs4_ff_layout_mirror.ref from atomic_t to refcount_t

atomic_t variables are currently used to implement reference
counters with the following properties:
- counter is initialized to 1 using atomic_set()
- a resource is freed upon counter reaching zero
- once counter reaches zero, its further
increments aren't allowed
- counter schema uses basic atomic operations
(set, inc, inc_not_zero, dec_and_test, etc.)

Such atomic variables should be converted to a newly provided
refcount_t type and API that prevents accidental counter overflows
and underflows. This is important since overflows and underflows
can lead to use-after-free situation and be exploitable.

The variable nfs4_ff_layout_mirror.ref is used as pure reference counter.
Convert it to refcount_t and fix up the operations.

Suggested-by: Kees Cook <keescook@chromium.org>
Reviewed-by: David Windsor <dwindsor@gmail.com>
Reviewed-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>

authored by

Elena Reshetova and committed by
Anna Schumaker
81a090b9 2b28a7be

+6 -5
+4 -4
fs/nfs/flexfilelayout/flexfilelayout.c
··· 187 187 continue; 188 188 if (!ff_mirror_match_fh(mirror, pos)) 189 189 continue; 190 - if (atomic_inc_not_zero(&pos->ref)) { 190 + if (refcount_inc_not_zero(&pos->ref)) { 191 191 spin_unlock(&inode->i_lock); 192 192 return pos; 193 193 } ··· 218 218 mirror = kzalloc(sizeof(*mirror), gfp_flags); 219 219 if (mirror != NULL) { 220 220 spin_lock_init(&mirror->lock); 221 - atomic_set(&mirror->ref, 1); 221 + refcount_set(&mirror->ref, 1); 222 222 INIT_LIST_HEAD(&mirror->mirrors); 223 223 } 224 224 return mirror; ··· 242 242 243 243 static void ff_layout_put_mirror(struct nfs4_ff_layout_mirror *mirror) 244 244 { 245 - if (mirror != NULL && atomic_dec_and_test(&mirror->ref)) 245 + if (mirror != NULL && refcount_dec_and_test(&mirror->ref)) 246 246 ff_layout_free_mirror(mirror); 247 247 } 248 248 ··· 2286 2286 if (!test_and_clear_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags)) 2287 2287 continue; 2288 2288 /* mirror refcount put in cleanup_layoutstats */ 2289 - if (!atomic_inc_not_zero(&mirror->ref)) 2289 + if (!refcount_inc_not_zero(&mirror->ref)) 2290 2290 continue; 2291 2291 dev = &mirror->mirror_ds->id_node; 2292 2292 memcpy(&devinfo->dev_id, &dev->deviceid, NFS4_DEVICEID4_SIZE);
+2 -1
fs/nfs/flexfilelayout/flexfilelayout.h
··· 13 13 #define FF_FLAGS_NO_IO_THRU_MDS 2 14 14 #define FF_FLAGS_NO_READ_IO 4 15 15 16 + #include <linux/refcount.h> 16 17 #include "../pnfs.h" 17 18 18 19 /* XXX: Let's filter out insanely large mirror count for now to avoid oom ··· 82 81 nfs4_stateid stateid; 83 82 struct rpc_cred __rcu *ro_cred; 84 83 struct rpc_cred __rcu *rw_cred; 85 - atomic_t ref; 84 + refcount_t ref; 86 85 spinlock_t lock; 87 86 unsigned long flags; 88 87 struct nfs4_ff_layoutstat read_stat;