diff options
author | Kinglong Mee <kinglongmee@gmail.com> | 2014-07-07 10:10:56 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-07-23 10:31:56 -0400 |
commit | f98bac5a30b60a2fca854dd5ee7256221d8ccf0a (patch) | |
tree | de5ccad7c101e5f307f7cd3686477675de40b81c /fs | |
parent | c3a4561796cffae6996264876ffca147b5c3709a (diff) |
NFSD: Fix crash encoding lock reply on 32-bit
Commit 8c7424cff6 "nfsd4: don't try to encode conflicting owner if low
on space" forgot to free conf->data in nfsd4_encode_lockt and before
sign conf->data to NULL in nfsd4_encode_lock_denied, causing a leak.
Worse, kfree() can be called on an uninitialized pointer in the case of
a succesful lock (or one that fails for a reason other than a conflict).
(Note that lock->lk_denied.ld_owner.data appears it should be zero here,
until you notice that it's one arm of a union the other arm of which is
written to in the succesful case by the
memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
sizeof(stateid_t));
in nfsd4_lock(). In the 32-bit case this overwrites ld_owner.data.)
Signed-off-by: Kinglong Mee <kinglongmee@gmail.com>
Fixes: 8c7424cff6 ""nfsd4: don't try to encode conflicting owner if low on space"
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b56b1cc02718..944275c8f56d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -2879,6 +2879,7 @@ again: | |||
2879 | * return the conflicting open: | 2879 | * return the conflicting open: |
2880 | */ | 2880 | */ |
2881 | if (conf->len) { | 2881 | if (conf->len) { |
2882 | kfree(conf->data); | ||
2882 | conf->len = 0; | 2883 | conf->len = 0; |
2883 | conf->data = NULL; | 2884 | conf->data = NULL; |
2884 | goto again; | 2885 | goto again; |
@@ -2891,6 +2892,7 @@ again: | |||
2891 | if (conf->len) { | 2892 | if (conf->len) { |
2892 | p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8); | 2893 | p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8); |
2893 | p = xdr_encode_opaque(p, conf->data, conf->len); | 2894 | p = xdr_encode_opaque(p, conf->data, conf->len); |
2895 | kfree(conf->data); | ||
2894 | } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ | 2896 | } else { /* non - nfsv4 lock in conflict, no clientid nor owner */ |
2895 | p = xdr_encode_hyper(p, (u64)0); /* clientid */ | 2897 | p = xdr_encode_hyper(p, (u64)0); /* clientid */ |
2896 | *p++ = cpu_to_be32(0); /* length of owner name */ | 2898 | *p++ = cpu_to_be32(0); /* length of owner name */ |
@@ -2907,7 +2909,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo | |||
2907 | nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid); | 2909 | nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid); |
2908 | else if (nfserr == nfserr_denied) | 2910 | else if (nfserr == nfserr_denied) |
2909 | nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied); | 2911 | nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied); |
2910 | kfree(lock->lk_denied.ld_owner.data); | 2912 | |
2911 | return nfserr; | 2913 | return nfserr; |
2912 | } | 2914 | } |
2913 | 2915 | ||