git: 1af8d5652a01 - main - libjail: start refactoring struct ioctl support
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 16 Jan 2026 00:24:24 UTC
The branch main has been updated by kevans:
URL: https://cgit.FreeBSD.org/src/commit/?id=1af8d5652a01f79d055436c2ee83219700e7b16c
commit 1af8d5652a01f79d055436c2ee83219700e7b16c
Author: Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-11-27 05:19:39 +0000
Commit: Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-01-16 00:23:40 +0000
libjail: start refactoring struct ioctl support
Instead of ad-hoc comparisons against the struct type in a few places,
start to abstract out an interface for dealing with struct types. For
now, this just means that we have some special jailparam_import and
jailparam_export handling for the ip addr types, but in the next commit
we'll extend it further to support MAC labels.
Reviewed by: jamie
Differential Revision: https://reviews.freebsd.org/D53959
---
lib/libjail/jail.c | 206 ++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 149 insertions(+), 57 deletions(-)
diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c
index ad3348af0d2d..8fbd486d2c96 100644
--- a/lib/libjail/jail.c
+++ b/lib/libjail/jail.c
@@ -35,6 +35,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
@@ -46,12 +47,45 @@
#define SJPARAM "security.jail.param"
-#define JPS_IN_ADDR 1
-#define JPS_IN6_ADDR 2
+#define JPSDEF_OF(jp) \
+ ((jp)->jp_structtype >= 0 ? &jp_structdefs[(jp)->jp_structtype] : NULL)
+
+typedef int (jps_import_t)(const struct jailparam *, int, const char *);
+typedef char *(jps_export_t)(const struct jailparam *, int);
+
+static jps_import_t jps_import_in_addr;
+static jps_import_t jps_import_in6_addr;
+
+static jps_export_t jps_export_in_addr;
+static jps_export_t jps_export_in6_addr;
+
+static const struct jp_structdef {
+ const char *jps_type; /* sysctl type */
+ size_t jps_valuelen; /* value size */
+ jps_import_t *jps_import; /* jailparam_import() */
+ jps_export_t *jps_export; /* jailparam_export() */
+} jp_structdefs[] = {
+ {
+ .jps_type = "S,in_addr",
+ .jps_valuelen = sizeof(struct in_addr),
+ .jps_import = jps_import_in_addr,
+ .jps_export = jps_export_in_addr,
+ },
+ {
+ .jps_type = "S,in6_addr",
+ .jps_valuelen = sizeof(struct in6_addr),
+ .jps_import = jps_import_in6_addr,
+ .jps_export = jps_export_in6_addr,
+ },
+};
+
+_Static_assert(nitems(jp_structdefs) <= INT_MAX,
+ "Too many struct definitions requires an ABI break in struct jailparam");
#define ARRAY_SANITY 5
#define ARRAY_SLOP 5
+static const struct jp_structdef *jp_structinfo(const char *type, int *);
static int jailparam_import_enum(const char **values, int nvalues,
const char *valstr, size_t valsize, int *value);
@@ -66,6 +100,23 @@ char jail_errmsg[JAIL_ERRMSGLEN];
static const char *bool_values[] = { "false", "true" };
static const char *jailsys_values[] = { "disable", "new", "inherit" };
+static const struct jp_structdef *
+jp_structinfo(const char *type, int *oidx)
+{
+ const struct jp_structdef *jpsdef;
+
+ for (size_t idx = 0; idx < nitems(jp_structdefs); idx++) {
+ jpsdef = &jp_structdefs[idx];
+
+ if (strcmp(jpsdef->jps_type, type) == 0) {
+ *oidx = (int)idx;
+ return (jpsdef);
+ }
+ }
+
+ *oidx = -1;
+ return (NULL);
+}
/*
* Import a null-terminated parameter list and set a jail with the flags
@@ -325,6 +376,7 @@ jailparam_import(struct jailparam *jp, const char *value)
{
char *p, *ep, *tvalue;
const char *avalue;
+ const struct jp_structdef *jpsdef;
int i, nval, fw;
if (value == NULL)
@@ -426,34 +478,13 @@ jailparam_import(struct jailparam *jp, const char *value)
case CTLTYPE_STRUCT:
tvalue = alloca(fw + 1);
strlcpy(tvalue, avalue, fw + 1);
- switch (jp->jp_structtype) {
- case JPS_IN_ADDR:
- if (inet_pton(AF_INET, tvalue,
- &((struct in_addr *)jp->jp_value)[i]) != 1)
- {
- snprintf(jail_errmsg,
- JAIL_ERRMSGLEN,
- "%s: not an IPv4 address: %s",
- jp->jp_name, tvalue);
- errno = EINVAL;
- goto error;
- }
- break;
- case JPS_IN6_ADDR:
- if (inet_pton(AF_INET6, tvalue,
- &((struct in6_addr *)jp->jp_value)[i]) != 1)
- {
- snprintf(jail_errmsg,
- JAIL_ERRMSGLEN,
- "%s: not an IPv6 address: %s",
- jp->jp_name, tvalue);
- errno = EINVAL;
- goto error;
- }
- break;
- default:
+
+ if (jp->jp_structtype == -1)
goto unknown_type;
- }
+
+ jpsdef = &jp_structdefs[jp->jp_structtype];
+ if ((*jpsdef->jps_import)(jp, i, tvalue) != 0)
+ goto error;
break;
default:
unknown_type:
@@ -773,6 +804,7 @@ jailparam_export(struct jailparam *jp)
{
size_t *valuelens;
char *value, *tvalue, **values;
+ const struct jp_structdef *jpsdef;
size_t valuelen;
int i, nval, ival;
char valbuf[INET6_ADDRSTRLEN];
@@ -839,29 +871,25 @@ jailparam_export(struct jailparam *jp)
(uintmax_t)((uint64_t *)jp->jp_value)[i]);
break;
case CTLTYPE_STRUCT:
- switch (jp->jp_structtype) {
- case JPS_IN_ADDR:
- if (inet_ntop(AF_INET,
- &((struct in_addr *)jp->jp_value)[i],
- valbuf, sizeof(valbuf)) == NULL) {
- strerror_r(errno, jail_errmsg,
- JAIL_ERRMSGLEN);
- return (NULL);
- }
- break;
- case JPS_IN6_ADDR:
- if (inet_ntop(AF_INET6,
- &((struct in6_addr *)jp->jp_value)[i],
- valbuf, sizeof(valbuf)) == NULL) {
- strerror_r(errno, jail_errmsg,
- JAIL_ERRMSGLEN);
- return (NULL);
- }
- break;
- default:
+ if (jp->jp_structtype == -1)
goto unknown_type;
+
+ jpsdef = &jp_structdefs[jp->jp_structtype];
+ value = (*jpsdef->jps_export)(jp, i);
+ if (value == NULL) {
+ strerror_r(errno, jail_errmsg,
+ JAIL_ERRMSGLEN);
+ return (NULL);
}
- break;
+
+ valuelens[i] = strlen(value) + 1;
+ valuelen += valuelens[i];
+ values[i] = alloca(valuelens[i]);
+ strcpy(values[i], value);
+
+ free(value);
+ value = NULL;
+ continue; /* Value already added to values[] */
default:
unknown_type:
snprintf(jail_errmsg, JAIL_ERRMSGLEN,
@@ -1055,14 +1083,17 @@ unknown_parameter:
}
jp->jp_valuelen = strtoul(desc.s, NULL, 10);
break;
- case CTLTYPE_STRUCT:
- if (!strcmp(desc.s, "S,in_addr")) {
- jp->jp_structtype = JPS_IN_ADDR;
- jp->jp_valuelen = sizeof(struct in_addr);
- } else if (!strcmp(desc.s, "S,in6_addr")) {
- jp->jp_structtype = JPS_IN6_ADDR;
- jp->jp_valuelen = sizeof(struct in6_addr);
+ case CTLTYPE_STRUCT: {
+ const struct jp_structdef *jpsdef;
+
+ jpsdef = jp_structinfo(desc.s, &jp->jp_structtype);
+ if (jpsdef != NULL) {
+ assert(jp->jp_structtype >= 0);
+
+ jp->jp_valuelen = jpsdef->jps_valuelen;
} else {
+ assert(jp->jp_structtype == -1);
+
desclen = 0;
if (sysctl(mib + 2, miblen / sizeof(int),
NULL, &jp->jp_valuelen, NULL, 0) < 0) {
@@ -1073,6 +1104,7 @@ unknown_parameter:
}
}
break;
+ }
case CTLTYPE_NODE:
/*
* A node might be described by an empty-named child,
@@ -1215,3 +1247,63 @@ kvname(const char *name)
return (kvname);
}
+
+static int
+jps_import_in_addr(const struct jailparam *jp, int i, const char *value)
+{
+ struct in_addr *addr;
+
+ addr = &((struct in_addr *)jp->jp_value)[i];
+ if (inet_pton(AF_INET, value, addr) != 1) {
+ snprintf(jail_errmsg, JAIL_ERRMSGLEN,
+ "%s: not an IPv4 address: %s", jp->jp_name, value);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+jps_import_in6_addr(const struct jailparam *jp, int i, const char *value)
+{
+ struct in6_addr *addr6;
+
+ addr6 = &((struct in6_addr *)jp->jp_value)[i];
+ if (inet_pton(AF_INET6, value, addr6) != 1) {
+ snprintf(jail_errmsg, JAIL_ERRMSGLEN,
+ "%s: not an IPv6 address: %s", jp->jp_name, value);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+static char *
+jps_export_in_addr(const struct jailparam *jp, int i)
+{
+ struct in_addr *addr;
+ char valbuf[INET_ADDRSTRLEN];
+
+ addr = &((struct in_addr *)jp->jp_value)[i];
+ if (inet_ntop(AF_INET, addr, valbuf, sizeof(valbuf)) == NULL)
+ return (NULL);
+
+ /* Error checked by caller. */
+ return (strdup(valbuf));
+}
+
+static char *
+jps_export_in6_addr(const struct jailparam *jp, int i)
+{
+ struct in6_addr *addr6;
+ char valbuf[INET6_ADDRSTRLEN];
+
+ addr6 = &((struct in6_addr *)jp->jp_value)[i];
+ if (inet_ntop(AF_INET6, addr6, valbuf, sizeof(valbuf)) == NULL)
+ return (NULL);
+
+ /* Error checked by caller. */
+ return (strdup(valbuf));
+}