sendfile: Ensure that sfio->npages is initialized
We initialize sfio->npages only when some I/O is required to satisfy the request. However, sendfile_iodone() contains an INVARIANTS-only check that references sfio->npages, and this check is executed even if no I/O is performed, so the check may use an uninitialized value. Fix the problem by initializing sfio->npages earlier. Note that sendfile_swapin() always initializes the page array. In some rare cases we need to trim the page array so ensure that sfio->npages gets updated accordingly. Reported by: syzkaller (with KASAN) Reviewed by: kib Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D27726
This commit is contained in:
parent
5d58f959d3
commit
26b23f07fb
@ -413,12 +413,13 @@ sendfile_iodone(void *arg, vm_page_t *pa, int count, int error)
|
||||
*/
|
||||
static int
|
||||
sendfile_swapin(vm_object_t obj, struct sf_io *sfio, int *nios, off_t off,
|
||||
off_t len, int npages, int rhpages, int flags)
|
||||
off_t len, int rhpages, int flags)
|
||||
{
|
||||
vm_page_t *pa;
|
||||
int a, count, count1, grabbed, i, j, rv;
|
||||
int a, count, count1, grabbed, i, j, npages, rv;
|
||||
|
||||
pa = sfio->pa;
|
||||
npages = sfio->npages;
|
||||
*nios = 0;
|
||||
flags = (flags & SF_NODISKIO) ? VM_ALLOC_NOWAIT : 0;
|
||||
sfio->pindex0 = OFF_TO_IDX(off);
|
||||
@ -905,6 +906,7 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
sfio->obj = obj;
|
||||
sfio->error = 0;
|
||||
sfio->m = NULL;
|
||||
sfio->npages = npages;
|
||||
#ifdef KERN_TLS
|
||||
/*
|
||||
* This doesn't use ktls_hold() because sfio->m will
|
||||
@ -914,8 +916,8 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
sfio->tls = tls;
|
||||
#endif
|
||||
vm_object_pip_add(obj, 1);
|
||||
error = sendfile_swapin(obj, sfio, &nios, off, space, npages,
|
||||
rhpages, flags);
|
||||
error = sendfile_swapin(obj, sfio, &nios, off, space, rhpages,
|
||||
flags);
|
||||
if (error != 0) {
|
||||
if (vp != NULL)
|
||||
VOP_UNLOCK(vp);
|
||||
@ -963,7 +965,7 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
if (pa[i] == NULL) {
|
||||
SFSTAT_INC(sf_busy);
|
||||
fixspace(npages, i, off, &space);
|
||||
npages = i;
|
||||
sfio->npages = i;
|
||||
softerr = EBUSY;
|
||||
break;
|
||||
}
|
||||
@ -1042,12 +1044,14 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
if (sf == NULL) {
|
||||
SFSTAT_INC(sf_allocfail);
|
||||
sendfile_iowait(sfio, "sfnosf");
|
||||
for (int j = i; j < npages; j++)
|
||||
for (int j = i; j < npages; j++) {
|
||||
vm_page_unwire(pa[j], PQ_INACTIVE);
|
||||
pa[j] = NULL;
|
||||
}
|
||||
if (m == NULL)
|
||||
softerr = ENOBUFS;
|
||||
fixspace(npages, i, off, &space);
|
||||
npages = i;
|
||||
sfio->npages = i;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1152,7 +1156,6 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
} else {
|
||||
sfio->so = so;
|
||||
sfio->m = m0;
|
||||
sfio->npages = npages;
|
||||
soref(so);
|
||||
error = (*so->so_proto->pr_usrreqs->pru_send)
|
||||
(so, PRUS_NOTREADY, m, NULL, NULL, td);
|
||||
|
Loading…
Reference in New Issue
Block a user