diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -344,6 +344,7 @@ Elf_Brandinfo *bi, *bi_m; bool ret, has_fctl0; int i, interp_name_len; + int prison_fallback_brand; interp_name_len = interp != NULL ? strlen(interp) + 1 : 0; @@ -465,12 +466,19 @@ } } + prison_fallback_brand = imgp->proc->p_ucred->cr_prison->pr_elf_fallback_brand; + /* Lacking a recognized interpreter, try the default brand */ for (i = 0; i < MAX_BRANDS; i++) { bi = elf_brand_list[i]; if (bi == NULL || (bi->flags & BI_BRAND_NOTE_MANDATORY) != 0 || (interp != NULL && (bi->flags & BI_BRAND_ONLY_STATIC) != 0)) continue; + if (hdr->e_machine == bi->machine && + prison_fallback_brand == bi->brand && + (bi->header_supported == NULL || + bi->header_supported(imgp, NULL, NULL))) + return (bi); if (hdr->e_machine == bi->machine && __elfN(fallback_brand) == bi->brand && (bi->header_supported == NULL || diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -991,9 +991,10 @@ size_t namelen, onamelen, pnamelen; int born, created, cuflags, descend, drflags, enforce; int error, errmsg_len, errmsg_pos; - int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel; + int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel, gotelf; int jid, jsys, len, level; int childmax, osreldt, rsnum, slevel; + int elf_fallback_brand; #ifdef INET int ip4s; bool redo_ip4; @@ -1088,6 +1089,14 @@ else gotrsnum = 1; + error = vfs_copyopt(opts, "elf.fallback_brand", &elf_fallback_brand, sizeof(elf_fallback_brand)); + if (error == ENOENT) + gotelf = 0; + else if (error != 0) + goto done_free; + else + gotelf = 1; + pr_flags = ch_flags = 0; for (bf = pr_flag_bool; bf < pr_flag_bool + nitems(pr_flag_bool); @@ -1687,6 +1696,7 @@ pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; pr->pr_enforce_statfs = jail_default_enforce_statfs; pr->pr_devfs_rsnum = ppr->pr_devfs_rsnum; + pr->pr_elf_fallback_brand = -1; pr->pr_osreldate = osreldt ? osreldt : ppr->pr_osreldate; if (osrelstr == NULL) @@ -1944,6 +1954,10 @@ FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) tpr->pr_devfs_rsnum = rsnum; } + + if (gotelf) + pr->pr_elf_fallback_brand = elf_fallback_brand; + if (namelc != NULL) { if (ppr == &prison0) strlcpy(pr->pr_name, namelc, sizeof(pr->pr_name)); @@ -2422,6 +2436,11 @@ error = vfs_setopts(opts, "host.hostuuid", pr->pr_hostuuid); if (error != 0 && error != ENOENT) goto done; + error = vfs_setopt(opts, "elf.fallback_brand", + &pr->pr_elf_fallback_brand, + sizeof(pr->pr_elf_fallback_brand)); + if (error != 0 && error != ENOENT) + goto done; #ifdef COMPAT_FREEBSD32 if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) { uint32_t hid32 = pr->pr_hostid; @@ -4489,6 +4508,10 @@ SYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, "B", "Jail is in the process of shutting down"); +SYSCTL_JAIL_PARAM_NODE(elf, "Jail ABI"); +SYSCTL_JAIL_PARAM(_elf, fallback_brand, CTLTYPE_INT | CTLFLAG_RW, + "I", "ELF brand of last resort"); + SYSCTL_JAIL_PARAM_NODE(children, "Number of child jails"); SYSCTL_JAIL_PARAM(_children, cur, CTLTYPE_INT | CTLFLAG_RD, "I", "Current number of child jails"); diff --git a/sys/sys/jail.h b/sys/sys/jail.h --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -197,7 +197,7 @@ int pr_devfs_rsnum; /* (p) devfs ruleset */ enum prison_state pr_state; /* (q) state in life cycle */ volatile int pr_exportcnt; /* (r) count of mount exports */ - int pr_spare; + int pr_elf_fallback_brand; /* (p) elf fallback abi */ int pr_osreldate; /* (c) kern.osreldate value */ unsigned long pr_hostid; /* (p) jail hostid */ char pr_name[MAXHOSTNAMELEN]; /* (p) admin jail name */ diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 12, 2023 +.Dd May 25, 2023 .Dt JAIL 8 .Os .Sh NAME @@ -760,6 +760,20 @@ Allow access to SYSV IPC semaphore and shared memory primitives, in the same manner as .Va sysvmsg. +.It Va efi.fallback_brand +The ABI brand of the Jail. +.Pp +Setting this value allows executables with unknown ABI brand to run as the +specified ABI brand. +.Pp +More specifically, if the ABI field of the ELF header of an executable to run in +the Jail is unknown, it will fallback to try this brand before trying the +system-wise fallback brands. +.Pp +For example, setting this parameter to 3, the Linux ABI brand, causes Linux +executables with ELF ABI brand "0" run in the Jail without the need to rebrand +the executables with +.Xr brandelf 1 . .El .Pp There are pseudo-parameters that are not passed to the kernel, but are