libc: add helper furnction to set sysctl() user.* variables

Testing had revealed that trying to retrieve the user.localbase
variable into to small a buffer would return the correct error code,
but would not fill the available buffer space with a partial result.

A partial result is of no use, but this is still a violation of the
documented behavior, which has been fixed in the previous commit to
this function.

I just checked the code for "user.cs_path" and found that it had the
same issue.

Instead of fixing the logic for each user.* sysctl string variable
individually, this commit adds a helper function set_user_str() that
implements the semantics specified in the sysctl() man page.

It is currently only used for "user.cs_path" and "user.localbase",
but it will offer a significant simplification when further such
variables will be added (as I intend to do).

MFC after:	3 days
This commit is contained in:
Stefan Eßer 2022-02-05 13:33:53 +01:00
parent 34478b73bf
commit 9535d9f104

View File

@ -46,6 +46,25 @@ __FBSDID("$FreeBSD$");
extern int __sysctl(const int *name, u_int namelen, void *oldp,
size_t *oldlenp, const void *newp, size_t newlen);
static int
set_user_str(void *dstp, size_t *dstlenp, const char *src, size_t len,
size_t maxlen)
{
int retval;
retval = 0;
if (dstp != NULL) {
if (len > maxlen) {
len = maxlen;
errno = ENOMEM;
retval = -1;
}
memcpy(dstp, src, len);
}
*dstlenp = len;
return (retval);
}
int
sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
const void *newp, size_t newlen)
@ -74,18 +93,10 @@ sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
/* Variables under CLT_USER that may be overridden by kernel values */
switch (name[1]) {
case USER_LOCALBASE:
if (oldlenp != NULL && *oldlenp == 1) {
*oldlenp = sizeof(_PATH_LOCALBASE);
if (oldp != NULL) {
if (*oldlenp > orig_oldlen) {
*oldlenp = orig_oldlen;
errno = ENOMEM;
retval = -1;
}
memmove(oldp, _PATH_LOCALBASE, *oldlenp);
}
}
return (retval);
if (oldlenp == NULL || *oldlenp > sizeof(""))
return (0);
return (set_user_str(oldp, oldlenp, _PATH_LOCALBASE,
sizeof(_PATH_LOCALBASE), orig_oldlen));
}
/* Variables under CLT_USER whose values are immutably defined below */
@ -96,14 +107,8 @@ sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
switch (name[1]) {
case USER_CS_PATH:
if (oldp != NULL && orig_oldlen < sizeof(_PATH_STDPATH)) {
errno = ENOMEM;
return (-1);
}
*oldlenp = sizeof(_PATH_STDPATH);
if (oldp != NULL)
memmove(oldp, _PATH_STDPATH, sizeof(_PATH_STDPATH));
return (0);
return (set_user_str(oldp, oldlenp, _PATH_STDPATH,
sizeof(_PATH_STDPATH), orig_oldlen));
}
if (oldp != NULL && *oldlenp < sizeof(int)) {