From b3b50cbd4647bb095e0cb5b72e933bc3036e412d Mon Sep 17 00:00:00 2001 From: Abdelkader Boudih Date: Mon, 2 Nov 2026 21:09:55 +0100 Subject: [PATCH] jail: return a new descriptor from jail_get(JAIL_USE_DESC | JAIL_GET_DESC) Prior to this change, `jail_get` when called with `JAIL_USE|JAIL_GET_DESC` would fail to return a valid descriptor in the positive case because the `JAIL_USE_DESC` block jumped to `found_prison` before the descriptor was allocated. This resulted in the returned jail descriptor always being -1, despite the call being successful. This change fixes the logic so `jfd_out` is properly initialized in the aforementioned scenario. MFC after: 3 days Reviewed by: jamie, ngie, adrian Differential Revision: https://reviews.freebsd.org/D60984 --- sys/kern/kern_jail.c | 18 +++++++++++------- tests/sys/kern/jaildesc.c | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 3b9809671f21..ae22e43aef62 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -2645,6 +2645,17 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) vfs_opterror(opts, "unexpected desc"); goto done; } + if (flags & (JAIL_GET_DESC | JAIL_OWN_DESC)) { + /* + * Allocate a jail descriptor to return later. + * This must happen before the JAIL_USE_DESC + * lookup below, which jumps to found_prison. + */ + error = jaildesc_alloc(td, &jfp_out, &jfd_out, + flags & JAIL_OWN_DESC); + if (error) + goto done; + } if (flags & JAIL_USE_DESC) { /* Get the jail from its descriptor. */ error = jaildesc_find(td, jfd_in, &pr, NULL); @@ -2673,13 +2684,6 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) prison_free(mypr); mypr = jdpr; } - if (flags & (JAIL_GET_DESC | JAIL_OWN_DESC)) { - /* Allocate a jail descriptor to return later. */ - error = jaildesc_alloc(td, &jfp_out, &jfd_out, - flags & JAIL_OWN_DESC); - if (error) - goto done; - } } else goto done; diff --git a/tests/sys/kern/jaildesc.c b/tests/sys/kern/jaildesc.c index 6c7993cfc1d3..99b759cfc9d1 100644 --- a/tests/sys/kern/jaildesc.c +++ b/tests/sys/kern/jaildesc.c @@ -389,6 +389,45 @@ ATF_TC_BODY(at_desc_bad_fd, tc) ATF_REQUIRE_MSG(close(jd) == 0, "close: %s", strerror(errno)); } +/* + * Look a jail up by descriptor and ask for a descriptor back. + */ +ATF_TC(use_desc_get_desc); +ATF_TC_HEAD(use_desc_get_desc, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(use_desc_get_desc, tc) +{ + struct iovec iov[2]; + int desc, jd, jid, n; + + jd = create_jail("jaildesc_use_desc_get_desc"); + + desc = jd; + n = 0; + iov[n].iov_base = __DECONST(void *, "desc"); + iov[n++].iov_len = strlen("desc") + 1; + iov[n].iov_base = &desc; + iov[n++].iov_len = sizeof(desc); + jid = jail_get(iov, n, JAIL_USE_DESC | JAIL_GET_DESC); + ATF_REQUIRE_MSG(jid >= 0, "jail_get: %s", strerror(errno)); + ATF_REQUIRE_MSG(desc >= 0 && desc != jd, + "jail_get returned descriptor %d, input was %d", desc, jd); + + /* The returned descriptor must name the same jail. */ + n = 0; + iov[n].iov_base = __DECONST(void *, "desc"); + iov[n++].iov_len = strlen("desc") + 1; + iov[n].iov_base = &desc; + iov[n++].iov_len = sizeof(desc); + ATF_REQUIRE_MSG(jail_get(iov, n, JAIL_USE_DESC) == jid, + "jail_get: %s", strerror(errno)); + + ATF_REQUIRE_MSG(close(desc) == 0, "close: %s", strerror(errno)); + ATF_REQUIRE_MSG(close(jd) == 0, "close: %s", strerror(errno)); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, poll_close_race); @@ -397,6 +436,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, curjail_get); ATF_TP_ADD_TC(tp, self_destruct); ATF_TP_ADD_TC(tp, at_desc_bad_fd); + ATF_TP_ADD_TC(tp, use_desc_get_desc); return (atf_no_error()); }