- strings handled by the common functions sysctl_string() and sysctl_rdstring()

are handled as arrays; that is, a truncated old value is returned, alongside
  with ENOMEM, if the buffer is too small.

- in all int, quad, and single struct cases, and all specials handled inside
  this file, oldlenp semantics are now as documented in the manual page, that
  is, a NULL oldp, but non-NULL oldlenp returns the needed size

[I had to change the oldlenp handling, so I thought I should make it as
 advertized. Formerly, the subroutines would not know when a NULL oldlenp
 was passed, do the work anyway, and the value would be thrown away.]

This is needed as a first step to make gethostname() and getdomainname()
conform to its own manual page and SUSV2. (See pr 7836 by Simon Burge)
This commit is contained in:
is 1999-11-17 23:24:54 +00:00
parent cdaec29859
commit 082c2a59eb
1 changed files with 94 additions and 65 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_sysctl.c,v 1.54 1999/11/12 16:10:16 is Exp $ */
/* $NetBSD: kern_sysctl.c,v 1.55 1999/11/17 23:24:54 is Exp $ */
/*-
* Copyright (c) 1982, 1986, 1989, 1993
@ -104,6 +104,7 @@ sys___sysctl(p, v, retval)
size_t savelen = 0, oldlen = 0;
sysctlfn *fn;
int name[CTL_MAXNAME];
size_t *oldlenp;
/*
* all top-level sysctl names are non-terminal
@ -162,9 +163,12 @@ sys___sysctl(p, v, retval)
return (EOPNOTSUPP);
}
if (SCARG(uap, oldlenp) &&
(error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen))))
return (error);
oldlenp = SCARG(uap, oldlenp);
if (oldlenp) {
if ((error = copyin(oldlenp, &oldlen, sizeof(oldlen))))
return (error);
oldlenp = &oldlen;
}
if (SCARG(uap, old) != NULL) {
if (!uvm_useracc(SCARG(uap, old), oldlen, B_WRITE))
return (EFAULT);
@ -192,7 +196,7 @@ sys___sysctl(p, v, retval)
savelen = oldlen;
}
error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old),
&oldlen, SCARG(uap, new), SCARG(uap, newlen), p);
oldlenp, SCARG(uap, new), SCARG(uap, newlen), p);
if (SCARG(uap, old) != NULL) {
if (dolock)
uvm_vsunlock(p, SCARG(uap, old), savelen);
@ -574,8 +578,11 @@ proc_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
* area during the process, so we have to do it by hand.
*/
curlen = strlen(ptmp->p_limit->pl_corename) + 1;
if (oldp && *oldlenp < curlen)
if (oldlenp && *oldlenp < curlen) {
if (!oldp)
*oldlenp = curlen;
return (ENOMEM);
}
if (newp) {
if (securelevel > 2)
return EPERM;
@ -606,7 +613,7 @@ proc_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
goto cleanup;
}
}
if (oldp) {
if (oldp && oldlenp) {
*oldlenp = curlen;
error = copyout(ptmp->p_limit->pl_corename, oldp,
curlen);
@ -657,6 +664,56 @@ cleanup:
return (EINVAL);
}
/*
* Convenience macros.
*/
#define SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, len) \
if (oldlenp) { \
if (!oldp) \
*oldlenp = len; \
else { \
if (*oldlenp < len) \
return(ENOMEM); \
*oldlenp = len; \
error = copyout((caddr_t)valp, oldp, len); \
} \
}
#define SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, typ) \
SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, valp, sizeof(typ))
#define SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len) \
if (newp && newlen != len) \
return (EINVAL);
#define SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, typ) \
SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, sizeof(typ))
#define SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, len) \
if (error == 0 && newp) \
error = copyin(newp, valp, len);
#define SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, typ) \
SYSCTL_SCALAR_NEWPCOP_LEN(newp, valp, sizeof(typ))
#define SYSCTL_STRING_CORE(oldp, oldlenp, str) \
if (oldlenp) { \
len = strlen(str) + 1; \
if (!oldp) \
*oldlenp = len; \
else { \
if (*oldlenp < len) { \
err2 = ENOMEM; \
len = *oldlenp; \
} else \
*oldlenp = len; \
error = copyout(str, oldp, len);\
if (error == 0) \
error = err2; \
} \
}
/*
* Validate parameters and get old / set new parameters
* for an integer-valued sysctl function.
@ -671,18 +728,14 @@ sysctl_int(oldp, oldlenp, newp, newlen, valp)
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp && newlen != sizeof(int))
return (EINVAL);
*oldlenp = sizeof(int);
if (oldp)
error = copyout(valp, oldp, sizeof(int));
if (error == 0 && newp)
error = copyin(newp, valp, sizeof(int));
SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, int)
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, int)
SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, int)
return (error);
}
/*
* As above, but read-only.
*/
@ -695,13 +748,11 @@ sysctl_rdint(oldp, oldlenp, newp, val)
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = sizeof(int);
if (oldp)
error = copyout((caddr_t)&val, oldp, sizeof(int));
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, int)
return (error);
}
@ -719,15 +770,10 @@ sysctl_quad(oldp, oldlenp, newp, newlen, valp)
{
int error = 0;
if (oldp && *oldlenp < sizeof(quad_t))
return (ENOMEM);
if (newp && newlen != sizeof(quad_t))
return (EINVAL);
*oldlenp = sizeof(quad_t);
if (oldp)
error = copyout(valp, oldp, sizeof(quad_t));
if (error == 0 && newp)
error = copyin(newp, valp, sizeof(quad_t));
SYSCTL_SCALAR_NEWPCHECK_TYP(newp, newlen, quad_t)
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, valp, quad_t)
SYSCTL_SCALAR_NEWPCOP_TYP(newp, valp, quad_t)
return (error);
}
@ -743,17 +789,14 @@ sysctl_rdquad(oldp, oldlenp, newp, val)
{
int error = 0;
if (oldp && *oldlenp < sizeof(quad_t))
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = sizeof(quad_t);
if (oldp)
error = copyout((caddr_t)&val, oldp, sizeof(quad_t));
SYSCTL_SCALAR_CORE_TYP(oldp, oldlenp, &val, quad_t)
return (error);
}
/*
* Validate parameters and get old / set new parameters
* for a string-valued sysctl function.
@ -767,16 +810,13 @@ sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
char *str;
int maxlen;
{
int len, error = 0;
int len, error = 0, err2 = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen >= maxlen)
return (EINVAL);
*oldlenp = len;
if (oldp)
error = copyout(str, oldp, len);
SYSCTL_STRING_CORE(oldp, oldlenp, str);
if (error == 0 && newp) {
error = copyin(newp, str, newlen);
str[newlen] = 0;
@ -794,16 +834,13 @@ sysctl_rdstring(oldp, oldlenp, newp, str)
void *newp;
char *str;
{
int len, error = 0;
int len, error = 0, err2 = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(str, oldp, len);
SYSCTL_STRING_CORE(oldp, oldlenp, str);
return (error);
}
@ -822,16 +859,10 @@ sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen > len)
return (EINVAL);
if (oldp) {
*oldlenp = len;
error = copyout(sp, oldp, len);
}
if (error == 0 && newp)
error = copyin(newp, sp, len);
SYSCTL_SCALAR_NEWPCHECK_LEN(newp, newlen, len)
SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len)
SYSCTL_SCALAR_NEWPCOP_LEN(newp, sp, len)
return (error);
}
@ -848,13 +879,11 @@ sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(sp, oldp, len);
SYSCTL_SCALAR_CORE_LEN(oldp, oldlenp, sp, len)
return (error);
}