Apply patch from Robert Elz in PR kern/10113. This fixes two problems

with procfs's cmdline - from the PR:

	The cmdline implementation in procfs is bogus.  It's possible that
	part of the fix is a workaround of a UVM problem - that is, when
	(internally) accessing the top of the process VM (the end of the
	args) a request for I/0 of a PAGE_SIZE'd block starting at less
	than a PAGE_SIZE from the end of the mem space returns EINVAL
	rather than the data that is available.  Whether this is a bug
	in UVM or not depends upon how it is defined to work, and I was
	unable to determine that.   (Simon Burge found that problem, and
	provided the basis of the workaround/fix).

	Then, the cmdline function is unable to read more than one
	page of args, and a good thing too, as the way it is written
	attempting to get more than that would reference into lala land.

	And, on an attempt to read a lot of data when the above is
	fixed, most of the data won't be returned, only the final block
	of any read.

Tested on alpha, pmax, i386 and sparc.
This commit is contained in:
simonb 2000-05-16 13:45:25 +00:00
parent f26609f174
commit 0c59b3c325

View File

@ -1,4 +1,4 @@
/* $NetBSD: procfs_cmdline.c,v 1.6 1999/07/22 18:13:38 thorpej Exp $ */
/* $NetBSD: procfs_cmdline.c,v 1.7 2000/05/16 13:45:25 simonb Exp $ */
/*
* Copyright (c) 1999 Jaromir Dolecek <dolecek@ics.muni.cz>
@ -62,8 +62,8 @@ procfs_docmdline(curp, p, pfs, uio)
struct uio *uio;
{
struct ps_strings pss;
int xlen, count, error, i;
size_t len, upper_bound;
int count, error, i;
size_t len, xlen, upper_bound;
struct uio auio;
struct iovec aiov;
vaddr_t argv;
@ -85,7 +85,14 @@ procfs_docmdline(curp, p, pfs, uio)
*/
if (P_ZOMBIE(p) || (p->p_flag & P_SYSTEM) != 0) {
len = snprintf(arg, PAGE_SIZE, "(%s)", p->p_comm);
goto doio;
xlen = len - uio->uio_offset;
if (xlen <= 0)
error = 0;
else
error = uiomove(arg, xlen, uio);
free(arg, M_TEMP);
return (error);
}
/*
@ -142,14 +149,15 @@ procfs_docmdline(curp, p, pfs, uio)
*/
len = 0;
count = pss.ps_nargvstr;
upper_bound = round_page(uio->uio_offset + 1);
for (; count && len < upper_bound; len += PAGE_SIZE) {
upper_bound = round_page(uio->uio_offset + uio->uio_resid);
for (; count && len < upper_bound; len += xlen) {
aiov.iov_base = arg;
aiov.iov_len = PAGE_SIZE;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = argv + len;
auio.uio_resid = PAGE_SIZE;
xlen = PAGE_SIZE - ((argv + len) & PAGE_MASK);
auio.uio_resid = xlen;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_rw = UIO_READ;
auio.uio_procp = NULL;
@ -157,39 +165,30 @@ procfs_docmdline(curp, p, pfs, uio)
if (error)
goto bad;
for (i = len; i < (len + PAGE_SIZE) && count != 0; i++) {
for (i = 0; i < xlen && count != 0; i++) {
if (arg[i] == '\0')
count--; /* one full string */
}
if (count == 0) {
/* No more argv strings, set up len and break. */
len = i;
break;
if (count == 0)
i--; /* exclude the final NUL */
if (len + i > uio->uio_offset) {
/* Have data in this page, copy it out */
error = uiomove(arg + uio->uio_offset - len,
i + len - uio->uio_offset, uio);
if (error || uio->uio_resid <= 0)
break;
}
}
if (len > 0)
len--; /* exclude last NUL */
bad:
/*
* Release the process.
*/
PRELE(p);
uvmspace_free(p->p_vmspace);
doio:
xlen = len - uio->uio_offset;
if (xlen <= 0)
error = 0;
else
error = uiomove(arg + trunc_page(len), xlen, uio);
free(arg, M_TEMP);
return (error);
bad:
PRELE(p);
uvmspace_free(p->p_vmspace);
free(arg, M_TEMP);
return (error);
}