Put on my peril sensitive sunglasses and add a flags field to the internal

sysctl routines and state.  Add some code to use it for signalling the need
to downconvert a data structure to 32 bits on a 64 bit OS when requested by
a 32 bit app.

I tried to do this in a generic abi wrapper that intercepted the sysctl
oid's, or looked up the format string etc, but it was a real can of worms
that turned into a fragile mess before I even got it partially working.

With this, we can now run 'sysctl -a' on a 32 bit sysctl binary and have
it not abort.  Things like netstat, ps, etc have a long way to go.

This also fixes a bug in the kern.ps_strings and kern.usrstack hacks.
These do matter very much because they are used by libc_r and other things.
This commit is contained in:
Peter Wemm 2004-10-11 22:04:16 +00:00
parent 731239920f
commit a7bc3102c4
7 changed files with 84 additions and 33 deletions

View File

@ -1203,25 +1203,21 @@ freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
return (EINVAL);
error = copyin(uap->name, &name, uap->namelen * sizeof(int));
error = copyin(uap->name, name, uap->namelen * sizeof(int));
if (error)
return (error);
mtx_lock(&Giant);
if (uap->oldlenp)
oldlen = fuword32(uap->oldlenp);
else
oldlen = 0;
error = userland_sysctl(td, name, uap->namelen,
uap->old, &oldlen, 1,
uap->new, uap->newlen, &j);
uap->new, uap->newlen, &j, SCTL_MASK32);
if (error && error != ENOMEM)
goto done2;
if (uap->oldlenp) {
if (uap->oldlenp)
suword32(uap->oldlenp, j);
}
done2:
mtx_unlock(&Giant);
return (error);

View File

@ -104,8 +104,8 @@ sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS)
int error;
p = curproc;
#if defined(__amd64__) || defined(__ia64__)
if (req->oldlen == sizeof(unsigned int)) {
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
unsigned int val;
val = (unsigned int)p->p_sysent->sv_psstrings;
error = SYSCTL_OUT(req, &val, sizeof(val));
@ -123,8 +123,8 @@ sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS)
int error;
p = curproc;
#if defined(__amd64__) || defined(__ia64__)
if (req->oldlen == sizeof(unsigned int)) {
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
unsigned int val;
val = (unsigned int)p->p_sysent->sv_usrstack;
error = SYSCTL_OUT(req, &val, sizeof(val));

View File

@ -828,20 +828,35 @@ int
sysctl_handle_long(SYSCTL_HANDLER_ARGS)
{
int error = 0;
long tmpout;
long tmplong;
#ifdef SCTL_MASK32
int tmpint;
#endif
/*
* Attempt to get a coherent snapshot by making a copy of the data.
*/
if (!arg1)
return (EINVAL);
tmpout = *(long *)arg1;
error = SYSCTL_OUT(req, &tmpout, sizeof(long));
tmplong = *(long *)arg1;
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
tmpint = tmplong;
error = SYSCTL_OUT(req, &tmpint, sizeof(int));
} else
#endif
error = SYSCTL_OUT(req, &tmplong, sizeof(long));
if (error || !req->newptr)
return (error);
error = SYSCTL_IN(req, arg1, sizeof(long));
#ifdef SCTL_MASK32
if (req->flags & SCTL_MASK32) {
error = SYSCTL_IN(req, &tmpint, sizeof(int));
*(long *)arg1 = (long)tmpint;
} else
#endif
error = SYSCTL_IN(req, arg1, sizeof(long));
return (error);
}
@ -965,7 +980,7 @@ sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
int
kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
size_t *oldlenp, void *new, size_t newlen, size_t *retval)
size_t *oldlenp, void *new, size_t newlen, size_t *retval, int flags)
{
int error = 0;
struct sysctl_req req;
@ -973,6 +988,7 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
bzero(&req, sizeof req);
req.td = td;
req.flags = flags;
if (oldlenp) {
req.oldlen = *oldlenp;
@ -1015,7 +1031,7 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
int
kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
void *new, size_t newlen, size_t *retval)
void *new, size_t newlen, size_t *retval, int flags)
{
int oid[CTL_MAXNAME];
size_t oidlen, plen;
@ -1026,12 +1042,12 @@ kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
oidlen = sizeof(oid);
error = kernel_sysctl(td, oid, 2, oid, &oidlen,
(void *)name, strlen(name), &plen);
(void *)name, strlen(name), &plen, flags);
if (error)
return (error);
error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
new, newlen, retval);
new, newlen, retval, flags);
return (error);
}
@ -1256,7 +1272,7 @@ __sysctl(struct thread *td, struct sysctl_args *uap)
error = userland_sysctl(td, name, uap->namelen,
uap->old, uap->oldlenp, 0,
uap->new, uap->newlen, &j);
uap->new, uap->newlen, &j, 0);
if (error && error != ENOMEM)
goto done2;
if (uap->oldlenp) {
@ -1275,7 +1291,8 @@ __sysctl(struct thread *td, struct sysctl_args *uap)
*/
int
userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval,
int flags)
{
int error = 0;
struct sysctl_req req;
@ -1283,6 +1300,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
bzero(&req, sizeof req);
req.td = td;
req.flags = flags;
if (oldlenp) {
if (inkernel) {

View File

@ -92,8 +92,9 @@ time_t time_uptime = 0;
static struct bintime boottimebin;
struct timeval boottime;
SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD,
&boottime, timeval, "System boottime");
static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime");
SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
@ -116,6 +117,20 @@ TC_STATS(nsetclock);
static void tc_windup(void);
static int
sysctl_kern_boottime(SYSCTL_HANDLER_ARGS)
{
#ifdef SCTL_MASK32
int tv[2];
if (req->flags & SCTL_MASK32) {
tv[0] = boottime.tv_sec;
tv[1] = boottime.tv_usec;
return SYSCTL_OUT(req, tv, sizeof(tv));
} else
#endif
return SYSCTL_OUT(req, &boottime, sizeof(boottime));
}
/*
* Return the difference between the timehands' counter value now and what
* was when we copied it to the timehands' offset_count.

View File

@ -192,7 +192,7 @@ uname(td, uap)
len = sizeof (uap->name->sysname);
mtx_lock(&Giant);
error = userland_sysctl(td, name, 2, uap->name->sysname, &len,
1, 0, 0, 0);
1, 0, 0, 0, 0);
if (error)
goto done2;
subyte( uap->name->sysname + sizeof(uap->name->sysname) - 1, 0);
@ -200,7 +200,7 @@ uname(td, uap)
name[1] = KERN_HOSTNAME;
len = sizeof uap->name->nodename;
error = userland_sysctl(td, name, 2, uap->name->nodename, &len,
1, 0, 0, 0);
1, 0, 0, 0, 0);
if (error)
goto done2;
subyte( uap->name->nodename + sizeof(uap->name->nodename) - 1, 0);
@ -208,7 +208,7 @@ uname(td, uap)
name[1] = KERN_OSRELEASE;
len = sizeof uap->name->release;
error = userland_sysctl(td, name, 2, uap->name->release, &len,
1, 0, 0, 0);
1, 0, 0, 0, 0);
if (error)
goto done2;
subyte( uap->name->release + sizeof(uap->name->release) - 1, 0);
@ -217,7 +217,7 @@ uname(td, uap)
name = KERN_VERSION;
len = sizeof uap->name->version;
error = userland_sysctl(td, name, 2, uap->name->version, &len,
1, 0, 0, 0);
1, 0, 0, 0, 0);
if (error)
goto done2;
subyte( uap->name->version + sizeof(uap->name->version) - 1, 0);
@ -241,7 +241,7 @@ uname(td, uap)
name[1] = HW_MACHINE;
len = sizeof uap->name->machine;
error = userland_sysctl(td, name, 2, uap->name->machine, &len,
1, 0, 0, 0);
1, 0, 0, 0, 0);
if (error)
goto done2;
subyte( uap->name->machine + sizeof(uap->name->machine) - 1, 0);

View File

@ -120,6 +120,11 @@ struct ctlname {
#define REQ_LOCKED 1 /* locked and not wired */
#define REQ_WIRED 2 /* locked and wired */
/* definitions for sysctl_req 'flags' member */
#if defined(__amd64__) || defined(__ia64__)
#define SCTL_MASK32 1 /* 32 bit emulation */
#endif
/*
* This describes the access space for a sysctl request. This is needed
* so that we can use the interface from the kernel or from user-space.
@ -136,6 +141,7 @@ struct sysctl_req {
size_t newidx;
int (*newfunc)(struct sysctl_req *, void *, size_t);
size_t validlen;
int flags;
};
SLIST_HEAD(sysctl_oid_list, sysctl_oid);
@ -617,13 +623,13 @@ int sysctl_ctx_entry_del(struct sysctl_ctx_list *clist,
int kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
size_t *oldlenp, void *new, size_t newlen,
size_t *retval);
size_t *retval, int flags);
int kernel_sysctlbyname(struct thread *td, char *name,
void *old, size_t *oldlenp, void *new, size_t newlen,
size_t *retval);
size_t *retval, int flags);
int userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
size_t *oldlenp, int inkernel, void *new, size_t newlen,
size_t *retval);
size_t *retval, int flags);
int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
int *nindx, struct sysctl_req *req);
int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len);

View File

@ -85,8 +85,24 @@ SYSCTL_UINT(_vm, VM_V_PAGEOUT_FREE_MIN, v_pageout_free_min,
SYSCTL_UINT(_vm, OID_AUTO, v_free_severe,
CTLFLAG_RW, &cnt.v_free_severe, 0, "");
SYSCTL_STRUCT(_vm, VM_LOADAVG, loadavg, CTLFLAG_RD,
&averunnable, loadavg, "Machine loadaverage history");
static int
sysctl_vm_loadavg(SYSCTL_HANDLER_ARGS)
{
#ifdef SCTL_MASK32
u_int32_t la[4];
if (req->flags & SCTL_MASK32) {
la[0] = averunnable.ldavg[0];
la[1] = averunnable.ldavg[1];
la[2] = averunnable.ldavg[2];
la[3] = averunnable.fscale;
return SYSCTL_OUT(req, la, sizeof(la));
} else
#endif
return SYSCTL_OUT(req, &averunnable, sizeof(averunnable));
}
SYSCTL_PROC(_vm, VM_LOADAVG, loadavg, CTLTYPE_STRUCT|CTLFLAG_RD,
NULL, 0, sysctl_vm_loadavg, "S,loadavg", "Machine loadaverage history");
static int
vmtotal(SYSCTL_HANDLER_ARGS)