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

fs, nfs: convert nfs_cache_defer_req.count 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 nfs_cache_defer_req.count 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
0896cade 81a090b9

+4 -4
+3 -3
fs/nfs/cache_lib.c
··· 66 66 */ 67 67 void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq) 68 68 { 69 - if (atomic_dec_and_test(&dreq->count)) 69 + if (refcount_dec_and_test(&dreq->count)) 70 70 kfree(dreq); 71 71 } 72 72 ··· 86 86 87 87 dreq = container_of(req, struct nfs_cache_defer_req, req); 88 88 dreq->deferred_req.revisit = nfs_dns_cache_revisit; 89 - atomic_inc(&dreq->count); 89 + refcount_inc(&dreq->count); 90 90 91 91 return &dreq->deferred_req; 92 92 } ··· 98 98 dreq = kzalloc(sizeof(*dreq), GFP_KERNEL); 99 99 if (dreq) { 100 100 init_completion(&dreq->completion); 101 - atomic_set(&dreq->count, 1); 101 + refcount_set(&dreq->count, 1); 102 102 dreq->req.defer = nfs_dns_cache_defer; 103 103 } 104 104 return dreq;
+1 -1
fs/nfs/cache_lib.h
··· 15 15 struct cache_req req; 16 16 struct cache_deferred_req deferred_req; 17 17 struct completion completion; 18 - atomic_t count; 18 + refcount_t count; 19 19 }; 20 20 21 21 extern int nfs_cache_upcall(struct cache_detail *cd, char *entry_name);