Date: Wed, 20 Jun 2018 20:04:20 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r335461 - in head/sys: kern sys Message-ID: <201806202004.w5KK4KN2077781@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Wed Jun 20 20:04:20 2018 New Revision: 335461 URL: https://svnweb.freebsd.org/changeset/base/335461 Log: Permit the kernel environment to set an array of numeric values for a single sysctl(9) node. Reviewed by: kib@, imp@, jhb@ Differential Revision: https://reviews.freebsd.org/D15802 MFC after: 1 week Sponsored by: Mellanox Technologies Modified: head/sys/kern/kern_environment.c head/sys/kern/kern_sysctl.c head/sys/sys/systm.h Modified: head/sys/kern/kern_environment.c ============================================================================== --- head/sys/kern/kern_environment.c Wed Jun 20 19:45:04 2018 (r335460) +++ head/sys/kern/kern_environment.c Wed Jun 20 20:04:20 2018 (r335461) @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysproto.h> #include <sys/libkern.h> #include <sys/kenv.h> +#include <sys/limits.h> #include <security/mac/mac_framework.h> @@ -514,6 +515,141 @@ getenv_string(const char *name, char *data, int size) strlcpy(data, cp, size); } return (cp != NULL); +} + +/* + * Return an array of integers at the given type size and signedness. + */ +int +getenv_array(const char *name, void *pdata, int size, int *psize, + int type_size, bool allow_signed) +{ + char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1]; + uint8_t shift; + int64_t value; + int64_t old; + char *end; + char *ptr; + int n; + + if (getenv_string(name, buf, sizeof(buf)) == 0) + return (0); + + /* get maximum number of elements */ + size /= type_size; + + n = 0; + + for (ptr = buf; *ptr != 0; ) { + + value = strtoq(ptr, &end, 0); + + /* check if signed numbers are allowed */ + if (value < 0 && !allow_signed) + goto error; + + /* check for invalid value */ + if (ptr == end) + goto error; + + /* check for valid suffix */ + switch (*end) { + case 't': + case 'T': + shift = 40; + end++; + break; + case 'g': + case 'G': + shift = 30; + end++; + break; + case 'm': + case 'M': + shift = 20; + end++; + break; + case 'k': + case 'K': + shift = 10; + end++; + break; + case ' ': + case '\t': + case ',': + case 0: + shift = 0; + break; + default: + /* garbage after numeric value */ + goto error; + } + + /* skip till next value, if any */ + while (*end == '\t' || *end == ',' || *end == ' ') + end++; + + /* update pointer */ + ptr = end; + + /* apply shift */ + old = value; + value <<= shift; + + /* overflow check */ + if ((value >> shift) != old) + goto error; + + /* check for buffer overflow */ + if (n >= size) + goto error; + + /* store value according to type size */ + switch (type_size) { + case 1: + if (allow_signed) { + if (value < SCHAR_MIN || value > SCHAR_MAX) + goto error; + } else { + if (value < 0 || value > UCHAR_MAX) + goto error; + } + ((uint8_t *)pdata)[n] = (uint8_t)value; + break; + case 2: + if (allow_signed) { + if (value < SHRT_MIN || value > SHRT_MAX) + goto error; + } else { + if (value < 0 || value > USHRT_MAX) + goto error; + } + ((uint16_t *)pdata)[n] = (uint16_t)value; + break; + case 4: + if (allow_signed) { + if (value < INT_MIN || value > INT_MAX) + goto error; + } else { + if (value > UINT_MAX) + goto error; + } + ((uint32_t *)pdata)[n] = (uint32_t)value; + break; + case 8: + ((uint64_t *)pdata)[n] = (uint64_t)value; + break; + default: + goto error; + } + n++; + } + *psize = n * type_size; + + if (n != 0) + return (1); /* success */ +error: + return (0); /* failure */ } /* Modified: head/sys/kern/kern_sysctl.c ============================================================================== --- head/sys/kern/kern_sysctl.c Wed Jun 20 19:45:04 2018 (r335460) +++ head/sys/kern/kern_sysctl.c Wed Jun 20 20:04:20 2018 (r335461) @@ -192,13 +192,8 @@ sysctl_load_tunable_by_oid_locked(struct sysctl_oid *o char path[96]; ssize_t rem = sizeof(path); ssize_t len; - uint8_t val_8; - uint16_t val_16; - uint32_t val_32; - int val_int; - long val_long; - int64_t val_64; - quad_t val_quad; + uint8_t data[512] __aligned(sizeof(uint64_t)); + int size; int error; path[--rem] = 0; @@ -226,85 +221,88 @@ sysctl_load_tunable_by_oid_locked(struct sysctl_oid *o switch (oidp->oid_kind & CTLTYPE) { case CTLTYPE_INT: - if (getenv_int(path + rem, &val_int) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(int), GETENV_SIGNED) == 0) return; - req.newlen = sizeof(val_int); - req.newptr = &val_int; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_UINT: - if (getenv_uint(path + rem, (unsigned int *)&val_int) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(int), GETENV_UNSIGNED) == 0) return; - req.newlen = sizeof(val_int); - req.newptr = &val_int; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_LONG: - if (getenv_long(path + rem, &val_long) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(long), GETENV_SIGNED) == 0) return; - req.newlen = sizeof(val_long); - req.newptr = &val_long; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_ULONG: - if (getenv_ulong(path + rem, (unsigned long *)&val_long) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(long), GETENV_UNSIGNED) == 0) return; - req.newlen = sizeof(val_long); - req.newptr = &val_long; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_S8: - if (getenv_int(path + rem, &val_int) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(int8_t), GETENV_SIGNED) == 0) return; - val_8 = val_int; - req.newlen = sizeof(val_8); - req.newptr = &val_8; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_S16: - if (getenv_int(path + rem, &val_int) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(int16_t), GETENV_SIGNED) == 0) return; - val_16 = val_int; - req.newlen = sizeof(val_16); - req.newptr = &val_16; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_S32: - if (getenv_long(path + rem, &val_long) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(int32_t), GETENV_SIGNED) == 0) return; - val_32 = val_long; - req.newlen = sizeof(val_32); - req.newptr = &val_32; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_S64: - if (getenv_quad(path + rem, &val_quad) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(int64_t), GETENV_SIGNED) == 0) return; - val_64 = val_quad; - req.newlen = sizeof(val_64); - req.newptr = &val_64; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_U8: - if (getenv_uint(path + rem, (unsigned int *)&val_int) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(uint8_t), GETENV_UNSIGNED) == 0) return; - val_8 = val_int; - req.newlen = sizeof(val_8); - req.newptr = &val_8; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_U16: - if (getenv_uint(path + rem, (unsigned int *)&val_int) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(uint16_t), GETENV_UNSIGNED) == 0) return; - val_16 = val_int; - req.newlen = sizeof(val_16); - req.newptr = &val_16; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_U32: - if (getenv_ulong(path + rem, (unsigned long *)&val_long) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(uint32_t), GETENV_UNSIGNED) == 0) return; - val_32 = val_long; - req.newlen = sizeof(val_32); - req.newptr = &val_32; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_U64: - /* XXX there is no getenv_uquad() */ - if (getenv_quad(path + rem, &val_quad) == 0) + if (getenv_array(path + rem, data, sizeof(data), &size, + sizeof(uint64_t), GETENV_UNSIGNED) == 0) return; - val_64 = val_quad; - req.newlen = sizeof(val_64); - req.newptr = &val_64; + req.newlen = size; + req.newptr = data; break; case CTLTYPE_STRING: penv = kern_getenv(path + rem); Modified: head/sys/sys/systm.h ============================================================================== --- head/sys/sys/systm.h Wed Jun 20 19:45:04 2018 (r335460) +++ head/sys/sys/systm.h Wed Jun 20 20:04:20 2018 (r335461) @@ -353,6 +353,11 @@ int kern_setenv(const char *name, const char *value); int kern_unsetenv(const char *name); int testenv(const char *name); +int getenv_array(const char *name, void *data, int size, int *psize, + int type_size, bool allow_signed); +#define GETENV_UNSIGNED false /* negative numbers not allowed */ +#define GETENV_SIGNED true /* negative numbers allowed */ + typedef uint64_t (cpu_tick_f)(void); void set_cputicker(cpu_tick_f *func, uint64_t freq, unsigned var); extern cpu_tick_f *cpu_ticks;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806202004.w5KK4KN2077781>