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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'nfsd-5.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull more nfsd fixes from Chuck Lever:
"Ensure that NFS clients cannot send file size or offset values that
can cause the NFS server to crash or to return incorrect or surprising
results.

In particular, fix how the NFS server handles values larger than
OFFSET_MAX"

* tag 'nfsd-5.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
NFSD: Deprecate NFS_OFFSET_MAX
NFSD: Fix offset type in I/O trace points
NFSD: COMMIT operations must not return NFS?ERR_INVAL
NFSD: Clamp WRITE offsets
NFSD: Fix NFSv3 SETATTR/CREATE's handling of large file sizes
NFSD: Fix ia_size underflow
NFSD: Fix the behavior of READ near OFFSET_MAX

+74 -55
+11 -8
fs/nfsd/nfs3proc.c
··· 150 150 unsigned int len; 151 151 int v; 152 152 153 - argp->count = min_t(u32, argp->count, max_blocksize); 154 - 155 153 dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n", 156 154 SVCFH_fmt(&argp->fh), 157 155 (unsigned long) argp->count, 158 156 (unsigned long long) argp->offset); 157 + 158 + argp->count = min_t(u32, argp->count, max_blocksize); 159 + if (argp->offset > (u64)OFFSET_MAX) 160 + argp->offset = (u64)OFFSET_MAX; 161 + if (argp->offset + argp->count > (u64)OFFSET_MAX) 162 + argp->count = (u64)OFFSET_MAX - argp->offset; 159 163 160 164 v = 0; 161 165 len = argp->count; ··· 202 198 argp->len, 203 199 (unsigned long long) argp->offset, 204 200 argp->stable? " stable" : ""); 201 + 202 + resp->status = nfserr_fbig; 203 + if (argp->offset > (u64)OFFSET_MAX || 204 + argp->offset + argp->len > (u64)OFFSET_MAX) 205 + return rpc_success; 205 206 206 207 fh_copy(&resp->fh, &argp->fh); 207 208 resp->committed = argp->stable; ··· 660 651 argp->count, 661 652 (unsigned long long) argp->offset); 662 653 663 - if (argp->offset > NFS_OFFSET_MAX) { 664 - resp->status = nfserr_inval; 665 - goto out; 666 - } 667 - 668 654 fh_copy(&resp->fh, &argp->fh); 669 655 resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset, 670 656 argp->count, resp->verf); 671 - out: 672 657 return rpc_success; 673 658 } 674 659
+2 -2
fs/nfsd/nfs3xdr.c
··· 254 254 if (xdr_stream_decode_u64(xdr, &newsize) < 0) 255 255 return false; 256 256 iap->ia_valid |= ATTR_SIZE; 257 - iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX); 257 + iap->ia_size = newsize; 258 258 } 259 259 if (xdr_stream_decode_u32(xdr, &set_it) < 0) 260 260 return false; ··· 1060 1060 return false; 1061 1061 /* cookie */ 1062 1062 resp->cookie_offset = dirlist->len; 1063 - if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0) 1063 + if (xdr_stream_encode_u64(xdr, OFFSET_MAX) < 0) 1064 1064 return false; 1065 1065 1066 1066 return true;
+9 -4
fs/nfsd/nfs4proc.c
··· 782 782 __be32 status; 783 783 784 784 read->rd_nf = NULL; 785 - if (read->rd_offset >= OFFSET_MAX) 786 - return nfserr_inval; 787 785 788 786 trace_nfsd_read_start(rqstp, &cstate->current_fh, 789 787 read->rd_offset, read->rd_length); 788 + 789 + read->rd_length = min_t(u32, read->rd_length, svc_max_payload(rqstp)); 790 + if (read->rd_offset > (u64)OFFSET_MAX) 791 + read->rd_offset = (u64)OFFSET_MAX; 792 + if (read->rd_offset + read->rd_length > (u64)OFFSET_MAX) 793 + read->rd_length = (u64)OFFSET_MAX - read->rd_offset; 790 794 791 795 /* 792 796 * If we do a zero copy read, then a client will see read data ··· 1022 1018 unsigned long cnt; 1023 1019 int nvecs; 1024 1020 1025 - if (write->wr_offset >= OFFSET_MAX) 1026 - return nfserr_inval; 1021 + if (write->wr_offset > (u64)OFFSET_MAX || 1022 + write->wr_offset + write->wr_buflen > (u64)OFFSET_MAX) 1023 + return nfserr_fbig; 1027 1024 1028 1025 cnt = write->wr_buflen; 1029 1026 trace_nfsd_write_start(rqstp, &cstate->current_fh,
+3 -7
fs/nfsd/nfs4xdr.c
··· 3495 3495 p = xdr_reserve_space(xdr, 3*4 + namlen); 3496 3496 if (!p) 3497 3497 goto fail; 3498 - p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ 3498 + p = xdr_encode_hyper(p, OFFSET_MAX); /* offset of next entry */ 3499 3499 p = xdr_encode_array(p, name, namlen); /* name length & name */ 3500 3500 3501 3501 nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen); ··· 3986 3986 } 3987 3987 xdr_commit_encode(xdr); 3988 3988 3989 - maxcount = svc_max_payload(resp->rqstp); 3990 - maxcount = min_t(unsigned long, maxcount, 3989 + maxcount = min_t(unsigned long, read->rd_length, 3991 3990 (xdr->buf->buflen - xdr->buf->len)); 3992 - maxcount = min_t(unsigned long, maxcount, read->rd_length); 3993 3991 3994 3992 if (file->f_op->splice_read && 3995 3993 test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) ··· 4824 4826 return nfserr_resource; 4825 4827 xdr_commit_encode(xdr); 4826 4828 4827 - maxcount = svc_max_payload(resp->rqstp); 4828 - maxcount = min_t(unsigned long, maxcount, 4829 + maxcount = min_t(unsigned long, read->rd_length, 4829 4830 (xdr->buf->buflen - xdr->buf->len)); 4830 - maxcount = min_t(unsigned long, maxcount, read->rd_length); 4831 4831 count = maxcount; 4832 4832 4833 4833 eof = read->rd_offset >= i_size_read(file_inode(file));
+7 -7
fs/nfsd/trace.h
··· 306 306 DECLARE_EVENT_CLASS(nfsd_io_class, 307 307 TP_PROTO(struct svc_rqst *rqstp, 308 308 struct svc_fh *fhp, 309 - loff_t offset, 310 - unsigned long len), 309 + u64 offset, 310 + u32 len), 311 311 TP_ARGS(rqstp, fhp, offset, len), 312 312 TP_STRUCT__entry( 313 313 __field(u32, xid) 314 314 __field(u32, fh_hash) 315 - __field(loff_t, offset) 316 - __field(unsigned long, len) 315 + __field(u64, offset) 316 + __field(u32, len) 317 317 ), 318 318 TP_fast_assign( 319 319 __entry->xid = be32_to_cpu(rqstp->rq_xid); ··· 321 321 __entry->offset = offset; 322 322 __entry->len = len; 323 323 ), 324 - TP_printk("xid=0x%08x fh_hash=0x%08x offset=%lld len=%lu", 324 + TP_printk("xid=0x%08x fh_hash=0x%08x offset=%llu len=%u", 325 325 __entry->xid, __entry->fh_hash, 326 326 __entry->offset, __entry->len) 327 327 ) ··· 330 330 DEFINE_EVENT(nfsd_io_class, nfsd_##name, \ 331 331 TP_PROTO(struct svc_rqst *rqstp, \ 332 332 struct svc_fh *fhp, \ 333 - loff_t offset, \ 334 - unsigned long len), \ 333 + u64 offset, \ 334 + u32 len), \ 335 335 TP_ARGS(rqstp, fhp, offset, len)) 336 336 337 337 DEFINE_NFSD_IO_EVENT(read_start);
+40 -17
fs/nfsd/vfs.c
··· 435 435 .ia_size = iap->ia_size, 436 436 }; 437 437 438 + host_err = -EFBIG; 439 + if (iap->ia_size < 0) 440 + goto out_unlock; 441 + 438 442 host_err = notify_change(&init_user_ns, dentry, &size_attr, NULL); 439 443 if (host_err) 440 444 goto out_unlock; ··· 1114 1110 } 1115 1111 1116 1112 #ifdef CONFIG_NFSD_V3 1117 - /* 1118 - * Commit all pending writes to stable storage. 1113 + /** 1114 + * nfsd_commit - Commit pending writes to stable storage 1115 + * @rqstp: RPC request being processed 1116 + * @fhp: NFS filehandle 1117 + * @offset: raw offset from beginning of file 1118 + * @count: raw count of bytes to sync 1119 + * @verf: filled in with the server's current write verifier 1119 1120 * 1120 - * Note: we only guarantee that data that lies within the range specified 1121 - * by the 'offset' and 'count' parameters will be synced. 1121 + * Note: we guarantee that data that lies within the range specified 1122 + * by the 'offset' and 'count' parameters will be synced. The server 1123 + * is permitted to sync data that lies outside this range at the 1124 + * same time. 1122 1125 * 1123 1126 * Unfortunately we cannot lock the file to make sure we return full WCC 1124 1127 * data to the client, as locking happens lower down in the filesystem. 1128 + * 1129 + * Return values: 1130 + * An nfsstat value in network byte order. 1125 1131 */ 1126 1132 __be32 1127 - nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, 1128 - loff_t offset, unsigned long count, __be32 *verf) 1133 + nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, 1134 + u32 count, __be32 *verf) 1129 1135 { 1136 + u64 maxbytes; 1137 + loff_t start, end; 1130 1138 struct nfsd_net *nn; 1131 1139 struct nfsd_file *nf; 1132 - loff_t end = LLONG_MAX; 1133 - __be32 err = nfserr_inval; 1134 - 1135 - if (offset < 0) 1136 - goto out; 1137 - if (count != 0) { 1138 - end = offset + (loff_t)count - 1; 1139 - if (end < offset) 1140 - goto out; 1141 - } 1140 + __be32 err; 1142 1141 1143 1142 err = nfsd_file_acquire(rqstp, fhp, 1144 1143 NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); 1145 1144 if (err) 1146 1145 goto out; 1146 + 1147 + /* 1148 + * Convert the client-provided (offset, count) range to a 1149 + * (start, end) range. If the client-provided range falls 1150 + * outside the maximum file size of the underlying FS, 1151 + * clamp the sync range appropriately. 1152 + */ 1153 + start = 0; 1154 + end = LLONG_MAX; 1155 + maxbytes = (u64)fhp->fh_dentry->d_sb->s_maxbytes; 1156 + if (offset < maxbytes) { 1157 + start = offset; 1158 + if (count && (offset + count - 1 < maxbytes)) 1159 + end = offset + count - 1; 1160 + } 1161 + 1147 1162 nn = net_generic(nf->nf_net, nfsd_net_id); 1148 1163 if (EX_ISSYNC(fhp->fh_export)) { 1149 1164 errseq_t since = READ_ONCE(nf->nf_file->f_wb_err); 1150 1165 int err2; 1151 1166 1152 - err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); 1167 + err2 = vfs_fsync_range(nf->nf_file, start, end, 0); 1153 1168 switch (err2) { 1154 1169 case 0: 1155 1170 nfsd_copy_write_verifier(verf, nn);
+2 -2
fs/nfsd/vfs.h
··· 74 74 char *name, int len, struct iattr *attrs, 75 75 struct svc_fh *res, int createmode, 76 76 u32 *verifier, bool *truncp, bool *created); 77 - __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, 78 - loff_t, unsigned long, __be32 *verf); 77 + __be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp, 78 + u64 offset, u32 count, __be32 *verf); 79 79 #endif /* CONFIG_NFSD_V3 */ 80 80 #ifdef CONFIG_NFSD_V4 81 81 __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
-8
include/linux/nfs.h
··· 36 36 memcpy(target->data, source->data, source->size); 37 37 } 38 38 39 - 40 - /* 41 - * This is really a general kernel constant, but since nothing like 42 - * this is defined in the kernel headers, I have to do it here. 43 - */ 44 - #define NFS_OFFSET_MAX ((__s64)((~(__u64)0) >> 1)) 45 - 46 - 47 39 enum nfs3_stable_how { 48 40 NFS_UNSTABLE = 0, 49 41 NFS_DATA_SYNC = 1,