binfmt_misc: normalize the per-exec invocation flags

A static entry fixes its invocation flags at registration. A 'B' entry's
load program picks them per exec. Since load_misc_binary() branches on
which kind of entry matched and then applies the two flag sets side by
side every flag is handled twice and each new one has to be added to
both arms.

Translate the 'B' flags into the entry flags they mirror and let the
dispatch act on a single set of flags. The boolean the two arms
communicated 'P' can be removed.

No functional change.

Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-4-e57866e4ae0f@kernel.org
Reviewed-by: Farid Zakaria <farid.m.zakaria@gmail.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Christian Brauner
2026-07-21 16:13:46 +02:00
parent 23c703f959
commit 08915b9f18

View File

@@ -319,6 +319,40 @@ static const char *entry_select_interpreter(const struct binfmt_misc_entry *e,
return ERR_PTR(retval);
}
/**
* entry_invocation_flags - the invocation flags in effect for this exec
* @e: matched binary type handler
* @bprm: binary that is being executed
*
* A static entry fixes its flags at registration, a 'B' entry's load program
* picks them per exec with bpf_binprm_set_flags(). Translate the latter into
* the former, implications included, so the dispatch has one set to act on.
*
* Return: the invocation flags for this exec
*/
static unsigned long entry_invocation_flags(const struct binfmt_misc_entry *e,
struct linux_binprm *bprm)
{
unsigned long flags = 0;
u64 bpf_flags;
if (!test_bit(MISC_FMT_BPF_BIT, &e->flags))
return e->flags;
bpf_flags = bprm->bpf_flags;
/* Clear so they can't accumulate into a nested interpreter level. */
bprm->bpf_flags = 0;
if (bpf_flags & BPF_BINPRM_PRESERVE_ARGV0)
flags |= MISC_FMT_PRESERVE_ARGV0;
if (bpf_flags & BPF_BINPRM_EXECFD)
flags |= MISC_FMT_OPEN_BINARY;
if (bpf_flags & BPF_BINPRM_CREDENTIALS)
flags |= MISC_FMT_CREDENTIALS | MISC_FMT_OPEN_BINARY;
return flags;
}
/*
* the loader itself
*/
@@ -328,7 +362,7 @@ static int load_misc_binary(struct linux_binprm *bprm)
const char *interpreter;
struct file *interp_file;
struct binfmt_misc *misc;
bool preserve_argv0, want_execfd, want_creds;
unsigned long flags;
int retval;
misc = current_binfmt_misc();
@@ -347,28 +381,10 @@ static int load_misc_binary(struct linux_binprm *bprm)
if (IS_ERR(interpreter))
return PTR_ERR(interpreter);
/*
* The invocation flags are fixed at registration for a static handler
* and chosen per exec by the load program, via bpf_binprm_set_flags(),
* for a bpf one.
*/
if (test_bit(MISC_FMT_BPF_BIT, &fmt->flags)) {
u64 f = bprm->bpf_flags;
/* Clear so it can't accumulate into a nested interpreter level. */
bprm->bpf_flags = 0;
preserve_argv0 = f & BPF_BINPRM_PRESERVE_ARGV0;
want_creds = f & BPF_BINPRM_CREDENTIALS;
want_execfd = f & (BPF_BINPRM_CREDENTIALS | BPF_BINPRM_EXECFD);
} else {
preserve_argv0 = fmt->flags & MISC_FMT_PRESERVE_ARGV0;
want_creds = fmt->flags & MISC_FMT_CREDENTIALS;
want_execfd = fmt->flags & MISC_FMT_OPEN_BINARY;
}
flags = entry_invocation_flags(fmt, bprm);
/* The entry's own choice - not one accumulated from an earlier level. */
if (preserve_argv0) {
if (flags & MISC_FMT_PRESERVE_ARGV0) {
bprm->interp_flags |= BINPRM_FLAGS_PRESERVE_ARGV0;
} else {
retval = remove_arg_zero(bprm);
@@ -424,9 +440,9 @@ static int load_misc_binary(struct linux_binprm *bprm)
return PTR_ERR(interp_file);
bprm->interpreter = interp_file;
if (want_execfd)
if (flags & MISC_FMT_OPEN_BINARY)
bprm->have_execfd = 1;
if (want_creds)
if (flags & MISC_FMT_CREDENTIALS)
bprm->execfd_creds = 1;
return 0;
}