svn commit: r335699 - in stable/11/sys: kern sys
Hans Petter Selasky
hselasky at FreeBSD.org
Wed Jun 27 07:24:08 UTC 2018
Author: hselasky
Date: Wed Jun 27 07:24:07 2018
New Revision: 335699
URL: https://svnweb.freebsd.org/changeset/base/335699
Log:
MFC r335461:
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
Sponsored by: Mellanox Technologies
Modified:
stable/11/sys/kern/kern_environment.c
stable/11/sys/kern/kern_sysctl.c
stable/11/sys/sys/systm.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/kern/kern_environment.c
==============================================================================
--- stable/11/sys/kern/kern_environment.c Wed Jun 27 07:18:54 2018 (r335698)
+++ stable/11/sys/kern/kern_environment.c Wed Jun 27 07:24:07 2018 (r335699)
@@ -51,6 +51,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>
@@ -512,6 +513,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: stable/11/sys/kern/kern_sysctl.c
==============================================================================
--- stable/11/sys/kern/kern_sysctl.c Wed Jun 27 07:18:54 2018 (r335698)
+++ stable/11/sys/kern/kern_sysctl.c Wed Jun 27 07:24:07 2018 (r335699)
@@ -191,13 +191,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;
@@ -225,85 +220,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: stable/11/sys/sys/systm.h
==============================================================================
--- stable/11/sys/sys/systm.h Wed Jun 27 07:18:54 2018 (r335698)
+++ stable/11/sys/sys/systm.h Wed Jun 27 07:24:07 2018 (r335699)
@@ -345,6 +345,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;
More information about the svn-src-stable
mailing list