Commit cff7cb2e authored by Elena Reshetova's avatar Elena Reshetova Committed by J. Bruce Fields

fs, nfsd: convert nfs4_cntl_odstate.co_odcount 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_cntl_odstate.co_odcount is used as pure reference counter.
Convert it to refcount_t and fix up the operations.
Suggested-by: default avatarKees Cook <keescook@chromium.org>
Reviewed-by: default avatarDavid Windsor <dwindsor@gmail.com>
Reviewed-by: default avatarHans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: default avatarElena Reshetova <elena.reshetova@intel.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent a15dfcd5
...@@ -568,7 +568,7 @@ alloc_clnt_odstate(struct nfs4_client *clp) ...@@ -568,7 +568,7 @@ alloc_clnt_odstate(struct nfs4_client *clp)
co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL);
if (co) { if (co) {
co->co_client = clp; co->co_client = clp;
atomic_set(&co->co_odcount, 1); refcount_set(&co->co_odcount, 1);
} }
return co; return co;
} }
...@@ -586,7 +586,7 @@ static inline void ...@@ -586,7 +586,7 @@ static inline void
get_clnt_odstate(struct nfs4_clnt_odstate *co) get_clnt_odstate(struct nfs4_clnt_odstate *co)
{ {
if (co) if (co)
atomic_inc(&co->co_odcount); refcount_inc(&co->co_odcount);
} }
static void static void
...@@ -598,7 +598,7 @@ put_clnt_odstate(struct nfs4_clnt_odstate *co) ...@@ -598,7 +598,7 @@ put_clnt_odstate(struct nfs4_clnt_odstate *co)
return; return;
fp = co->co_file; fp = co->co_file;
if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) {
list_del(&co->co_perfile); list_del(&co->co_perfile);
spin_unlock(&fp->fi_lock); spin_unlock(&fp->fi_lock);
......
...@@ -468,7 +468,7 @@ struct nfs4_clnt_odstate { ...@@ -468,7 +468,7 @@ struct nfs4_clnt_odstate {
struct nfs4_client *co_client; struct nfs4_client *co_client;
struct nfs4_file *co_file; struct nfs4_file *co_file;
struct list_head co_perfile; struct list_head co_perfile;
atomic_t co_odcount; refcount_t co_odcount;
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment