diff options
author | kib <kib@FreeBSD.org> | 2009-05-14 10:54:57 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-05-14 10:54:57 +0000 |
commit | 7361db22793eeb694f1f01d466272bd47bac53d9 (patch) | |
tree | 045421c3780e4bded99ea72d2698157e8d6f2f89 /sys/kern | |
parent | e420c3ccc5cbe952d1fc43d6e05eb9f25a67bd5b (diff) | |
download | FreeBSD-src-7361db22793eeb694f1f01d466272bd47bac53d9.zip FreeBSD-src-7361db22793eeb694f1f01d466272bd47bac53d9.tar.gz |
Do not advance req->oldidx when sysctl_old_user returning an
error due to copyout failure or short buffer.
The later breaks the usermode iterators of the sysctl results that pack
arbitrary number of variable-sized structures. Iterator expects that
kernel filled exactly oldlen bytes, and tries to interpret half-filled
or garbage structure at the end of the buffer. In particular,
kinfo_getfile(3) segfaulted.
Reported and tested by: pho
MFC after: 3 weeks
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_sysctl.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index b69ac8f..89fbb9a 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1221,9 +1221,9 @@ sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l) if (i > 0) bcopy(p, (char *)req->oldptr + req->oldidx, i); } - req->oldidx += l; if (req->oldptr && i != l) return (ENOMEM); + req->oldidx += l; return (0); } @@ -1320,9 +1320,10 @@ sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) size_t i, len, origidx; origidx = req->oldidx; - req->oldidx += l; - if (req->oldptr == NULL) + if (req->oldptr == NULL) { + req->oldidx += l; return (0); + } /* * If we have not wired the user supplied buffer and we are currently * holding locks, drop a witness warning, as it's possible that @@ -1344,6 +1345,7 @@ sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) return (error); if (i < l) return (ENOMEM); + req->oldidx += l; return (0); } |