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

lockd: set file_lock start and end when decoding nlm4 testargs

Commit 6930bcbfb6ce dropped the setting of the file_lock range when
decoding a nlm_lock off the wire. This causes the client side grant
callback to miss matching blocks and reject the lock, only to rerequest
it 30s later.

Add a helper function to set the file_lock range from the start and end
values that the protocol uses, and have the nlm_lock decoder call that to
set up the file_lock args properly.

Fixes: 6930bcbfb6ce ("lockd: detect and reject lock arguments that overflow")
Reported-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Tested-by: Amir Goldstein <amir73il@gmail.com>
Cc: stable@vger.kernel.org #6.0
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>

authored by

Jeff Layton and committed by
Anna Schumaker
7ff84910 9c88ea00

+14 -9
+1 -8
fs/lockd/clnt4xdr.c
··· 261 261 u32 exclusive; 262 262 int error; 263 263 __be32 *p; 264 - s32 end; 265 264 266 265 memset(lock, 0, sizeof(*lock)); 267 266 locks_init_lock(fl); ··· 284 285 fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; 285 286 p = xdr_decode_hyper(p, &l_offset); 286 287 xdr_decode_hyper(p, &l_len); 287 - end = l_offset + l_len - 1; 288 - 289 - fl->fl_start = (loff_t)l_offset; 290 - if (l_len == 0 || end < 0) 291 - fl->fl_end = OFFSET_MAX; 292 - else 293 - fl->fl_end = (loff_t)end; 288 + nlm4svc_set_file_lock_range(fl, l_offset, l_len); 294 289 error = 0; 295 290 out: 296 291 return error;
+12 -1
fs/lockd/xdr4.c
··· 33 33 return res; 34 34 } 35 35 36 + void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len) 37 + { 38 + s64 end = off + len - 1; 39 + 40 + fl->fl_start = off; 41 + if (len == 0 || end < 0) 42 + fl->fl_end = OFFSET_MAX; 43 + else 44 + fl->fl_end = end; 45 + } 46 + 36 47 /* 37 48 * NLM file handles are defined by specification to be a variable-length 38 49 * XDR opaque no longer than 1024 bytes. However, this implementation ··· 91 80 locks_init_lock(fl); 92 81 fl->fl_flags = FL_POSIX; 93 82 fl->fl_type = F_RDLCK; 94 - 83 + nlm4svc_set_file_lock_range(fl, lock->lock_start, lock->lock_len); 95 84 return true; 96 85 } 97 86
+1
include/linux/lockd/xdr4.h
··· 22 22 #define nlm4_fbig cpu_to_be32(NLM_FBIG) 23 23 #define nlm4_failed cpu_to_be32(NLM_FAILED) 24 24 25 + void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len); 25 26 bool nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 26 27 bool nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 27 28 bool nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);