Don't bother calling vslock() and vsunlock() if oldlen is zero.
If vslock() returns ENOMEM, sysctl_wire_old_buffer() should set wiredlen to zero and return zero (success) so that the handler will operate according to sysctl(3): The size of the buffer is given by the location specified by oldlenp before the call, and that location gives the amount of data copied after a successful call and after a call that returns with the error code ENOMEM. The handler will return an ENOMEM error because the zero length buffer will overflow.
This commit is contained in:
parent
12adb9e4a7
commit
2b0bda9870
@ -999,7 +999,7 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
|
||||
error = sysctl_root(0, name, namelen, &req);
|
||||
|
||||
if (req.lock == REQ_WIRED)
|
||||
if (req.lock == REQ_WIRED && req.wiredlen > 0)
|
||||
vsunlock(req.oldptr, req.wiredlen);
|
||||
|
||||
SYSCTL_UNLOCK();
|
||||
@ -1102,13 +1102,15 @@ sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
|
||||
ret = 0;
|
||||
if (req->lock == REQ_LOCKED && req->oldptr &&
|
||||
req->oldfunc == sysctl_old_user) {
|
||||
ret = vslock(req->oldptr, wiredlen);
|
||||
if (ret == 0) {
|
||||
req->lock = REQ_WIRED;
|
||||
req->wiredlen = wiredlen;
|
||||
if (wiredlen != 0) {
|
||||
ret = vslock(req->oldptr, wiredlen);
|
||||
if (ret != 0 && ret != ENOMEM)
|
||||
return (ret);
|
||||
}
|
||||
req->lock = REQ_WIRED;
|
||||
req->wiredlen = wiredlen;
|
||||
}
|
||||
return (ret);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
@ -1317,7 +1319,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
|
||||
} while (error == EAGAIN);
|
||||
|
||||
req = req2;
|
||||
if (req.lock == REQ_WIRED)
|
||||
if (req.lock == REQ_WIRED && req.wiredlen > 0)
|
||||
vsunlock(req.oldptr, req.wiredlen);
|
||||
|
||||
SYSCTL_UNLOCK();
|
||||
|
Loading…
x
Reference in New Issue
Block a user