The branch main has been updated by kevans:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=db3b39f063d9f05ee808b9c5a11146ed6810d857

commit db3b39f063d9f05ee808b9c5a11146ed6810d857
Author:     Kyle Evans <[email protected]>
AuthorDate: 2025-11-27 05:24:14 +0000
Commit:     Kyle Evans <[email protected]>
CommitDate: 2026-01-16 00:23:40 +0000

    libjail: extend struct handlers to included MAC labels
    
    MAC label handling is a little special; to avoid being too disruptive,
    we allocate a `mac_t *` here for the value so that we can mac_prepare()
    or mac_from_text() into.  As a result, we need:
    
     - A custom free() handler to avoid leaking the *jp_value
     - A custom jailparam_get() handler to mac_prepare() the mac_t and
        populate the iove properly, so that the kernel doesn't have to
        do something funky like copyin, dereference, copyin again.
     - A custom jailparam_set() handler to similarly populate the iovec
        properly.
    
    Reviewed by:    jamie
    Differential Revision:  https://reviews.freebsd.org/D53960
---
 lib/libjail/jail.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 189 insertions(+), 3 deletions(-)

diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c
index 8fbd486d2c96..75fd411c70c8 100644
--- a/lib/libjail/jail.c
+++ b/lib/libjail/jail.c
@@ -29,6 +29,7 @@
 #include <sys/param.h>
 #include <sys/jail.h>
 #include <sys/linker.h>
+#include <sys/mac.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
 
@@ -50,20 +51,38 @@
 #define        JPSDEF_OF(jp)   \
        ((jp)->jp_structtype >= 0 ? &jp_structdefs[(jp)->jp_structtype] : NULL)
 
+static int jps_get(struct jailparam *, struct iovec *);
+static int jps_set(const struct jailparam *, struct iovec *);
+static void jps_free(struct jailparam *);
+
 typedef int (jps_import_t)(const struct jailparam *, int, const char *);
 typedef char *(jps_export_t)(const struct jailparam *, int);
+typedef int (jps_get_t)(struct jailparam *, struct iovec *);
+typedef int (jps_set_t)(const struct jailparam *, struct iovec *);
+typedef void (jps_free_t)(struct jailparam *);
 
 static jps_import_t    jps_import_in_addr;
 static jps_import_t    jps_import_in6_addr;
+static jps_import_t    jps_import_mac_label;
 
 static jps_export_t    jps_export_in_addr;
 static jps_export_t    jps_export_in6_addr;
+static jps_export_t    jps_export_mac_label;
+
+static jps_get_t       jps_get_mac_label;
+
+static jps_set_t       jps_set_mac_label;
+
+static jps_free_t      jps_free_mac_label;
 
 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() */
+       jps_get_t       *jps_get;               /* jailparam_get() */
+       jps_set_t       *jps_set;               /* jailparam_set() */
+       jps_free_t      *jps_free;              /* jailparam_free() */
 } jp_structdefs[] = {
        {
                .jps_type = "S,in_addr",
@@ -77,6 +96,15 @@ static const struct jp_structdef {
                .jps_import = jps_import_in6_addr,
                .jps_export = jps_export_in6_addr,
        },
+       {
+               .jps_type = "S,mac",
+               .jps_valuelen = sizeof(mac_t *),
+               .jps_import = jps_import_mac_label,
+               .jps_export = jps_export_mac_label,
+               .jps_get = jps_get_mac_label,
+               .jps_set = jps_set_mac_label,
+               .jps_free = jps_free_mac_label,
+       },
 };
 
 _Static_assert(nitems(jp_structdefs) <= INT_MAX,
@@ -579,7 +607,7 @@ jailparam_set(struct jailparam *jp, unsigned njp, int flags)
                        /* No value means key removal. */
                        jiov[i].iov_base = NULL;
                        jiov[i].iov_len = 0;
-               } else {
+               } else if (jps_set(&jp[j], &jiov[i]) != 0) {
                        /*
                         * Try to fill in missing values with an empty string.
                         */
@@ -624,7 +652,7 @@ jailparam_get(struct jailparam *jp, unsigned njp, int flags)
 {
        struct iovec *jiov;
        struct jailparam *jp_desc, *jp_lastjid, *jp_jid, *jp_name, *jp_key;
-       int i, ai, ki, jid, arrays, sanity;
+       int i, ai, ki, jid, arrays, processed, sanity;
        unsigned j;
 
        /*
@@ -726,6 +754,26 @@ jailparam_get(struct jailparam *jp, unsigned njp, int 
flags)
                                            JAIL_ERRMSGLEN);
                                        return (-1);
                                }
+
+                               /*
+                                * Returns -1 on error, or # index populated on
+                                * success.  0 is perfectly valid for a type
+                                * that may want to simply initialize the value
+                                * as needed.
+                                */
+                               processed = jps_get(&jp[j], &jiov[i]);
+                               if (processed == -1) {
+                                       return (-1);
+                               } else if (processed > 0) {
+                                       /*
+                                        * The above math for jiov sizing does
+                                        * not really account for one param
+                                        * expanding to multiple entries.
+                                        */
+                                       assert(processed == 1);
+                                       i += processed;
+                                       continue;
+                               }
                        }
                        jiov[i].iov_base = jp[j].jp_value;
                        jiov[i].iov_len = jp[j].jp_valuelen;
@@ -924,12 +972,15 @@ jailparam_export(struct jailparam *jp)
 void
 jailparam_free(struct jailparam *jp, unsigned njp)
 {
+
        unsigned j;
 
        for (j = 0; j < njp; j++) {
                free(jp[j].jp_name);
-               if (!(jp[j].jp_flags & JP_RAWVALUE))
+               if (!(jp[j].jp_flags & JP_RAWVALUE)) {
+                       jps_free(jp);
                        free(jp[j].jp_value);
+               }
        }
 }
 
@@ -1248,6 +1299,43 @@ kvname(const char *name)
        return (kvname);
 }
 
+static int
+jps_get(struct jailparam *jp, struct iovec *jiov)
+{
+       const struct jp_structdef *jpsdef;
+
+       jpsdef = JPSDEF_OF(jp);
+       if (jpsdef == NULL || jpsdef->jps_get == NULL)
+               return (0);     /* Nop, but not an error. */
+
+       return ((jpsdef->jps_get)(jp, jiov));
+}
+
+static int
+jps_set(const struct jailparam *jp, struct iovec *jiov)
+{
+       const struct jp_structdef *jpsdef;
+
+       jpsdef = JPSDEF_OF(jp);
+       if (jpsdef == NULL || jpsdef->jps_set == NULL)
+               return (EINVAL);        /* Unhandled */
+
+       return ((jpsdef->jps_set)(jp, jiov));
+}
+
+static void
+jps_free(struct jailparam *jp)
+{
+       const struct jp_structdef *jpsdef;
+
+       jpsdef = JPSDEF_OF(jp);
+       if (jpsdef == NULL)
+               return;
+
+       if (jpsdef->jps_free != NULL)
+               jpsdef->jps_free(jp);
+}
+
 static int
 jps_import_in_addr(const struct jailparam *jp, int i, const char *value)
 {
@@ -1280,6 +1368,24 @@ jps_import_in6_addr(const struct jailparam *jp, int i, 
const char *value)
        return (0);
 }
 
+static int
+jps_import_mac_label(const struct jailparam *jp, int i, const char *value)
+{
+       mac_t *pmac;
+
+       pmac = &((mac_t *)jp->jp_value)[i];
+       if (mac_from_text(pmac, value) != 0) {
+               int serrno = errno;
+
+               snprintf(jail_errmsg, JAIL_ERRMSGLEN, "%s: mac_from_text: %s",
+                   jp->jp_name, strerror(errno));
+               errno = serrno;
+               return (-1);
+       }
+
+       return (0);
+}
+
 static char *
 jps_export_in_addr(const struct jailparam *jp, int i)
 {
@@ -1307,3 +1413,83 @@ jps_export_in6_addr(const struct jailparam *jp, int i)
        /* Error checked by caller. */
        return (strdup(valbuf));
 }
+
+static char *
+jps_export_mac_label(const struct jailparam *jp, int i)
+{
+       mac_t *macp;
+       char *labelbuf;
+       int error;
+
+       macp = &((mac_t *)jp->jp_value)[i];
+       error = mac_to_text(*macp, &labelbuf);
+       if (error != 0)
+               return (NULL);
+
+       return (labelbuf);
+}
+
+static int
+jps_get_mac_label(struct jailparam *jp, struct iovec *jiov)
+{
+       mac_t *pmac = jp->jp_value;
+       int error;
+
+       error = mac_prepare_type(pmac, "jail");
+       if (error != 0) {
+               int serrno = errno;
+
+               free(jp->jp_value);
+               jp->jp_value = NULL;
+               if (serrno == ENOENT) {
+                       snprintf(jail_errmsg, sizeof(jail_errmsg),
+                           "jail_get: no mac.conf(5) jail config");
+               } else {
+                       strerror_r(serrno, jail_errmsg, JAIL_ERRMSGLEN);
+               }
+
+               errno = serrno;
+               return (-1);
+       }
+
+       /*
+        * MAC label gets special handling because libjail internally maintains
+        * it as a pointer to a mac_t, but we actually want to pass the mac_t
+        * itself.  We don't want the jailparam_get() zeroing behavior, as it's
+        * initialized by us.
+        */
+       jiov->iov_base = *pmac;
+       jiov->iov_len = sizeof(**pmac);
+       return (1);
+}
+
+static int
+jps_set_mac_label(const struct jailparam *jp, struct iovec *jiov)
+{
+       mac_t *pmac;
+
+       /*
+        * MAC label gets special handling because libjail internally
+        * maintains it as a pointer to a mac_t, but we actually want to
+        * pass the mac_t itself.
+        */
+       pmac = jp->jp_value;
+       if (pmac != NULL) {
+               jiov->iov_base = *pmac;
+               jiov->iov_len = sizeof(**pmac);
+       } else {
+               jiov->iov_base = NULL;
+               jiov->iov_len = 0;
+       }
+
+       return (0);
+}
+
+static void
+jps_free_mac_label(struct jailparam *jp)
+{
+       mac_t *pmac = jp->jp_value;
+
+       if (pmac != NULL)
+               mac_free(*pmac);
+}

Reply via email to