Skip to content

Commit 0885eac

Browse files
committed
Merge tag 'nfsd-5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
Pull nfsd fixes from Chuck Lever: "Notable changes: - There is now a backup maintainer for NFSD Notable fixes: - Prevent array overruns in svc_rdma_build_writes() - Prevent buffer overruns when encoding NFSv3 READDIR results - Fix a potential UAF in nfsd_file_put()" * tag 'nfsd-5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: SUNRPC: Remove pointer type casts from xdr_get_next_encode_buffer() SUNRPC: Clean up xdr_get_next_encode_buffer() SUNRPC: Clean up xdr_commit_encode() SUNRPC: Optimize xdr_reserve_space() SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer() SUNRPC: Trap RDMA segment overflows NFSD: Fix potential use-after-free in nfsd_file_put() MAINTAINERS: reciprocal co-maintainership for file locking and nfsd
2 parents 90add6d + da9e94f commit 0885eac

File tree

5 files changed

+47
-21
lines changed

5 files changed

+47
-21
lines changed

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7654,6 +7654,7 @@ F: include/uapi/scsi/fc/
76547654

76557655
FILE LOCKING (flock() and fcntl()/lockf())
76567656
M: Jeff Layton <jlayton@kernel.org>
7657+
M: Chuck Lever <chuck.lever@oracle.com>
76577658
L: linux-fsdevel@vger.kernel.org
76587659
S: Maintained
76597660
F: fs/fcntl.c
@@ -10746,6 +10747,7 @@ W: http://kernelnewbies.org/KernelJanitors
1074610747

1074710748
KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
1074810749
M: Chuck Lever <chuck.lever@oracle.com>
10750+
M: Jeff Layton <jlayton@kernel.org>
1074910751
L: linux-nfs@vger.kernel.org
1075010752
S: Supported
1075110753
W: http://nfs.sourceforge.net/

fs/nfsd/filecache.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,11 +309,12 @@ nfsd_file_put(struct nfsd_file *nf)
309309
if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) {
310310
nfsd_file_flush(nf);
311311
nfsd_file_put_noref(nf);
312-
} else {
312+
} else if (nf->nf_file) {
313313
nfsd_file_put_noref(nf);
314-
if (nf->nf_file)
315-
nfsd_file_schedule_laundrette();
316-
}
314+
nfsd_file_schedule_laundrette();
315+
} else
316+
nfsd_file_put_noref(nf);
317+
317318
if (atomic_long_read(&nfsd_filecache_count) >= NFSD_FILE_LRU_LIMIT)
318319
nfsd_file_gc();
319320
}

include/linux/sunrpc/xdr.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,
243243
extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
244244
extern int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec,
245245
size_t nbytes);
246-
extern void xdr_commit_encode(struct xdr_stream *xdr);
246+
extern void __xdr_commit_encode(struct xdr_stream *xdr);
247247
extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
248248
extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen);
249249
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
@@ -306,6 +306,20 @@ xdr_reset_scratch_buffer(struct xdr_stream *xdr)
306306
xdr_set_scratch_buffer(xdr, NULL, 0);
307307
}
308308

309+
/**
310+
* xdr_commit_encode - Ensure all data is written to xdr->buf
311+
* @xdr: pointer to xdr_stream
312+
*
313+
* Handle encoding across page boundaries by giving the caller a
314+
* temporary location to write to, then later copying the data into
315+
* place. __xdr_commit_encode() does that copying.
316+
*/
317+
static inline void xdr_commit_encode(struct xdr_stream *xdr)
318+
{
319+
if (unlikely(xdr->scratch.iov_len))
320+
__xdr_commit_encode(xdr);
321+
}
322+
309323
/**
310324
* xdr_stream_remaining - Return the number of bytes remaining in the stream
311325
* @xdr: pointer to struct xdr_stream

net/sunrpc/xdr.c

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,
919919
EXPORT_SYMBOL_GPL(xdr_init_encode);
920920

921921
/**
922-
* xdr_commit_encode - Ensure all data is written to buffer
922+
* __xdr_commit_encode - Ensure all data is written to buffer
923923
* @xdr: pointer to xdr_stream
924924
*
925925
* We handle encoding across page boundaries by giving the caller a
@@ -931,26 +931,29 @@ EXPORT_SYMBOL_GPL(xdr_init_encode);
931931
* required at the end of encoding, or any other time when the xdr_buf
932932
* data might be read.
933933
*/
934-
inline void xdr_commit_encode(struct xdr_stream *xdr)
934+
void __xdr_commit_encode(struct xdr_stream *xdr)
935935
{
936-
int shift = xdr->scratch.iov_len;
936+
size_t shift = xdr->scratch.iov_len;
937937
void *page;
938938

939-
if (shift == 0)
940-
return;
941939
page = page_address(*xdr->page_ptr);
942940
memcpy(xdr->scratch.iov_base, page, shift);
943941
memmove(page, page + shift, (void *)xdr->p - page);
944942
xdr_reset_scratch_buffer(xdr);
945943
}
946-
EXPORT_SYMBOL_GPL(xdr_commit_encode);
944+
EXPORT_SYMBOL_GPL(__xdr_commit_encode);
947945

948-
static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
949-
size_t nbytes)
946+
/*
947+
* The buffer space to be reserved crosses the boundary between
948+
* xdr->buf->head and xdr->buf->pages, or between two pages
949+
* in xdr->buf->pages.
950+
*/
951+
static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
952+
size_t nbytes)
950953
{
951-
__be32 *p;
952954
int space_left;
953955
int frag1bytes, frag2bytes;
956+
void *p;
954957

955958
if (nbytes > PAGE_SIZE)
956959
goto out_overflow; /* Bigger buffers require special handling */
@@ -964,6 +967,7 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
964967
xdr->buf->page_len += frag1bytes;
965968
xdr->page_ptr++;
966969
xdr->iov = NULL;
970+
967971
/*
968972
* If the last encode didn't end exactly on a page boundary, the
969973
* next one will straddle boundaries. Encode into the next
@@ -972,14 +976,19 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
972976
* space at the end of the previous buffer:
973977
*/
974978
xdr_set_scratch_buffer(xdr, xdr->p, frag1bytes);
975-
p = page_address(*xdr->page_ptr);
979+
976980
/*
977-
* Note this is where the next encode will start after we've
978-
* shifted this one back:
981+
* xdr->p is where the next encode will start after
982+
* xdr_commit_encode() has shifted this one back:
979983
*/
980-
xdr->p = (void *)p + frag2bytes;
984+
p = page_address(*xdr->page_ptr);
985+
xdr->p = p + frag2bytes;
981986
space_left = xdr->buf->buflen - xdr->buf->len;
982-
xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
987+
if (space_left - nbytes >= PAGE_SIZE)
988+
xdr->end = p + PAGE_SIZE;
989+
else
990+
xdr->end = p + space_left - frag1bytes;
991+
983992
xdr->buf->page_len += frag2bytes;
984993
xdr->buf->len += nbytes;
985994
return p;

net/sunrpc/xprtrdma/svc_rdma_rw.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,10 +478,10 @@ svc_rdma_build_writes(struct svc_rdma_write_info *info,
478478
unsigned int write_len;
479479
u64 offset;
480480

481-
seg = &info->wi_chunk->ch_segments[info->wi_seg_no];
482-
if (!seg)
481+
if (info->wi_seg_no >= info->wi_chunk->ch_segcount)
483482
goto out_overflow;
484483

484+
seg = &info->wi_chunk->ch_segments[info->wi_seg_no];
485485
write_len = min(remaining, seg->rs_length - info->wi_seg_off);
486486
if (!write_len)
487487
goto out_overflow;

0 commit comments

Comments
 (0)