libjail: fix fetching mac.label for multiple jails

When doing a basic `jls -n`, jls(8) will jailparam_get() the mac.label
for every jail on the system using the same set of jailparams, and thus
the same jp_value.  We only init the mac_t the first time, so the first
jail would populate it with `?` from /etc/mac.conf and the resulting
jail_get(2) would clobber it with the empty string, then a second jail
would try to pass the empty string to the kernel and fail because it
must have a non-zero length.

Fix it by invoking jps_get() every time.  Drop some comments to note
that jps_get() will be invoked with zero || garbage from previous call,
and be sure that we don't leak our previous mac_t.  There aren't any
other jps_get implementations at this time, so this shouldn't cause any
unexpected problems.

Reported by:	ivy
Reviewed by:	jamie
Differential Revision:	https://reviews.freebsd.org/D57280
This commit is contained in:
Kyle Evans committed 2026-09-09 16:24:18 -05:00
1 parent f2a2e02ae5
commit b2a270da9f
2 files changed
+29 -7

No files matched your search

+25 -6
View File
@@ -746,13 +746,23 @@ jailparam_get(struct jailparam *jp, unsigned njp, int flags)
jiov[i].iov_base = jp[j].jp_name;
jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
i++;
if (jp[j].jp_value == NULL &&
!(jp[j].jp_flags & JP_RAWVALUE)) {
jp[j].jp_value = malloc(jp[j].jp_valuelen);
/*
* We give structured types' jps_get() implementations
* a chance to initialize the value. We'll guarantee
* that the initial value is zeroed out, but they should
* assume on every call that the value may be populated
* by a subsequent jailparam_get().
*/
if (!(jp[j].jp_flags & JP_RAWVALUE)) {
if (jp[j].jp_value == NULL) {
strerror_r(errno, jail_errmsg,
JAIL_ERRMSGLEN);
return (-1);
jp[j].jp_value = calloc(1,
jp[j].jp_valuelen);
if (jp[j].jp_value == NULL) {
strerror_r(errno, jail_errmsg,
JAIL_ERRMSGLEN);
return (-1);
}
}
/*
@@ -1435,6 +1445,15 @@ jps_get_mac_label(struct jailparam *jp, struct iovec *jiov)
mac_t *pmac = jp->jp_value;
int error;
/*
* Our value is only allocated once and may be reused for many
* jailparam_get() calls; avoid leaking.
*/
if (*pmac != NULL) {
mac_free(*pmac);
*pmac = NULL;
}
error = mac_prepare_type(pmac, "jail");
if (error != 0 && errno == ENOENT) {
/*
+4 -1
View File
@@ -35,6 +35,9 @@ basic_body()
{
# Create the jail
atf_check -s exit:0 -o ignore jail -c name=basejail persist ip4.addr=192.0.1.1
# Create a second jail to test `jls -n` in the process for breakage when
# handling some of the non-trivial parameter types.
atf_check -s exit:0 -o ignore jail -c name=basejail2 persist ip4.addr=192.0.1.2
# Check output of jls
atf_check -s exit:0 -o ignore jls
atf_check -s exit:0 -o ignore jls -v
@@ -52,7 +55,7 @@ basic_body()
basic_cleanup()
{
jail -r basejail
jail -r basejail basejail2
}
atf_test_case "list" "cleanup"