// SPDX-License-Identifier: GPL-2.0-only
/*
* binfmt_misc.c
*
* Copyright (C) 1997 Richard Günther
*
* binfmt_misc detects binaries via a magic or filename extension and invokes
* a specified wrapper. See Documentation/admin-guide/binfmt-misc.rst for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched/mm.h>
#include <linux/magic.h>
#include <linux/binfmts.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/string_helpers.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/fs_context.h>
#include <linux/syscalls.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "internal.h"
#ifdef DEBUG
# define USE_DEBUG 1
#else
# define USE_DEBUG 0
#endif
enum {
VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
};
enum {Enabled, Magic};
#define MISC_FMT_PRESERVE_ARGV0 (1UL << 31)
#define MISC_FMT_OPEN_BINARY (1UL << 30)
#define MISC_FMT_CREDENTIALS (1UL << 29)
#define MISC_FMT_OPEN_FILE (1UL << 28)
typedef struct {
struct list_head list;
unsigned long flags; /* type, status, etc. */
int offset; /* offset of magic */
int size; /* size of magic/mask */
char *magic; /* magic or filename extension */
char *mask; /* mask, NULL for exact match */
const char *interpreter; /* filename of interpreter */
char *name;
struct dentry *dentry;
struct file *interp_file;
refcount_t users; /* sync removal with load_misc_binary() */
} Node;
static struct file_system_type bm_fs_type;
/*
* Max length of the register string. Determined by:
* - 7 delimiters
* - name: ~50 bytes
* - type: 1 byte
* - offset: 3 bytes (has to be smaller than BINPRM_BUF_SIZE)
* - magic: 128 bytes (512 in escaped form)
* - mask: 128 bytes (512 in escaped form)
* - interp: ~50 bytes
* - flags: 5 bytes
* Round that up a bit, and then back off to hold the internal data
* (like struct Node).
*/
#define MAX_REGISTER_LENGTH 1920
/**
* search_binfmt_handler - search for a binary handler for @bprm
* @misc: handle to binfmt_misc instance
* @bprm: binary for which we are looking for a handler
*
* Search for a binary type handler for @bprm in the list of registered binary
* type handlers.
*
* Return: binary type list entry on success, NULL on failure
*/
static Node *search_binfmt_handler(struct binfmt_misc *misc,
struct linux_binprm *bprm)
{
char *p = strrchr(bprm->interp, '.');
Node *e;
/* Walk all the registered handlers. */
list_for_each_entry(e, &misc->entries, list) {
char *s;
int j;
/* Make sure this one is currently enabled. */
if (!test_bit(Enabled, &e->flags))
continue;
/* Do matching based on extension if applicable. */
if (!test_bit(Magic, &e->flags)) {
if (p && !strcmp(e->magic, p + 1))
return e;
continue;
}
/* Do matching based on magic & mask. */
s = bprm->buf + e->offset;
if (e->mask) {
for (j = 0; j < e->size; j++)
if ((*s++ ^ e->magic[j]) & e->mask[j])
break;
} else {
for (j = 0; j < e->size; j++)
if ((*s++ ^ e->magic[j]))
break;
}
if (j == e->size)
return e;
}
return NULL;
}
/**
* get_binfmt_handler - try to find a binary type handler
* @misc: handle to binfmt_misc instance
* @bprm: binary for which we are looking for a handler
*
* Try to find a binfmt handler for the binary type. If one is found take a
* reference to protect against removal via bm_{entry,status}_write().
*
* Return: binary type list entry on success, NULL on failure
*/
static Node *get_binfmt_handler(struct binfmt_misc *misc,
struct linux_binprm *bprm)
{
Node *e;
read_lock(&misc->entries_lock);
e = search_binfmt_handler(misc, bprm);
if (e)
refcount_inc(&e->users);
read_unlock(&misc->entries_lock);
return e;
}
/**
* put_binfmt_handler - put binary handler node
* @e: node to put
*
* Free node syncing with load_misc_binary() and defer final free to
* load_misc_binary() in case it is using the binary type handler we were
* requested to remove.
*/
static void put_binfmt_handler(Node *e)
{
if (refcount_dec_and_test(&e->users)) {
if (e->flags & MISC_FMT_OPEN_FILE)
filp_close(e->interp_file, NULL);
kfree(e);
}
}
/**
* load_binfmt_misc - load the binfmt_misc of the caller's user namespace
*
* To be called in load_misc_binary() to load the relevant struct binfmt_misc.
* If a user namespace doesn't have its own binfmt_misc mount it can make use
* of its ancestor's binfmt_misc handlers. This mimicks the behavior of
* pre-namespaced binfmt_misc where all registered binfmt_misc handlers where
* available to all user and user namespaces on the system.
*
* Return: the binfmt_misc instance of the caller's user namespace
*/
static struct binfmt_misc *load_binfmt_misc(void)
{
const struct user_namespace *user_ns;
struct binfmt_misc *misc;
user_ns = current_user_ns();
while (user_ns) {
/* Pairs with smp_store_release() in bm_fill_super(). */
misc = smp_load_acquire(&user_ns->binfmt_misc);
if (misc)
return misc;
user_ns = user_ns->parent;
}
return &init_binfmt_misc;
}
/*
* the loader itself
*/
static int load_misc_binary(struct linux_binprm *bprm)
{
Node *fmt;
struct file *interp_file = NULL;
int retval = -ENOEXEC;
struct binfmt_misc *misc;
misc = load_binfmt_misc(