mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
lockd: Avoid hashing uninitialized bytes in nlm4svc_lookup_file()
file_hash() digests the first LOCKD_FH_HASH_SIZE bytes of nfs_fh.data when bucketing nlm_files[], independent of fh.size. Commit3de744ee4e("lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure") set .pc_argzero to zero for the converted procedures and moved file-handle population into nlm4svc_lookup_file(), which copies only xdr_lock->fh.len bytes into lock->fh.data. When an NLMv4 client presents a file handle shorter than LOCKD_FH_HASH_SIZE, bytes fh.len..31 retain whatever the argument buffer held from an earlier request. The same wire handle then hashes to different buckets across calls; nlm_lookup_file() misses the existing nlm_file entry, and lock-state lookups fail. Zero only the tail bytes that file_hash() would otherwise consume. Handles of LOCKD_FH_HASH_SIZE or larger already populate every byte that file_hash() reads. Reported-by: Jeff Layton <jlayton@kernel.org> Closes: https://lore.kernel.org/r/5229a9746d723a3f830120c0b966510f75badfc2.camel@kernel.org Fixes:3de744ee4e("lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure") Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
70a38f87be
commit
6e4c62caec
|
|
@ -52,6 +52,14 @@
|
|||
*/
|
||||
#define LOCKD_DFLT_TIMEO 10
|
||||
|
||||
/*
|
||||
* Number of leading bytes of nfs_fh.data that file_hash()
|
||||
* digests when bucketing nlm_files[]. Sized for historical
|
||||
* NFSv2 handles; nfs_fh.data must be initialized at least
|
||||
* this far before lookup, regardless of fh.size.
|
||||
*/
|
||||
#define LOCKD_FH_HASH_SIZE 32
|
||||
|
||||
/* error codes new to NLMv4 */
|
||||
#define nlm4_deadlock cpu_to_be32(NLM_DEADLCK)
|
||||
#define nlm4_rofs cpu_to_be32(NLM_ROFS)
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
|||
return nlm_lck_denied_nolocks;
|
||||
lock->fh.size = xdr_lock->fh.len;
|
||||
memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len);
|
||||
if (xdr_lock->fh.len < LOCKD_FH_HASH_SIZE)
|
||||
memset(lock->fh.data + xdr_lock->fh.len, 0,
|
||||
LOCKD_FH_HASH_SIZE - xdr_lock->fh.len);
|
||||
|
||||
lock->oh.len = xdr_lock->oh.len;
|
||||
lock->oh.data = xdr_lock->oh.data;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/sunrpc/addr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mount.h>
|
||||
#include <uapi/linux/nfs2.h>
|
||||
|
||||
#include "lockd.h"
|
||||
#include "share.h"
|
||||
|
|
@ -67,7 +66,7 @@ static inline unsigned int file_hash(struct nfs_fh *f)
|
|||
{
|
||||
unsigned int tmp=0;
|
||||
int i;
|
||||
for (i=0; i<NFS2_FHSIZE;i++)
|
||||
for (i = 0; i < LOCKD_FH_HASH_SIZE; i++)
|
||||
tmp += f->data[i];
|
||||
return tmp & (FILE_NRHASH - 1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user