Thread (4 messages) flat view 4 messages, 3 authors, 2018-10-08

Re: [RFC v3 1/1] ns: add binfmt_misc to the user namespace

From: Jann Horn <jannh@google.com>
Date: 2018-10-08 10:58:33
Also in: linux-fsdevel, lkml

On Sat, Oct 6, 2018 at 8:04 AM Andrei Vagin [off-list ref] wrote:
On Thu, Oct 04, 2018 at 12:50:22AM +0200, Laurent Vivier wrote:
quoted
This patch allows to have a different binfmt_misc configuration
for each new user namespace. By default, the binfmt_misc configuration
is the one of the host, but if the binfmt_misc filesystem is mounted
in the new namespace a new empty binfmt instance is created and used
in this namespace.

For instance, using "unshare" we can start a chroot of an another
architecture and configure the binfmt_misc interpreter without being root
to run the binaries in this chroot.

Signed-off-by: Laurent Vivier <redacted>
---
 fs/binfmt_misc.c               | 85 +++++++++++++++++++++++-----------
 include/linux/user_namespace.h | 15 ++++++
 kernel/user.c                  | 14 ++++++
 kernel/user_namespace.c        |  9 ++++
 4 files changed, 95 insertions(+), 28 deletions(-)
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index aa4a7a23ff99..78780bc87506 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -38,9 +38,6 @@ enum {
      VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
 };

-static LIST_HEAD(entries);
-static int enabled = 1;
-
 enum {Enabled, Magic};
 #define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
 #define MISC_FMT_OPEN_BINARY (1 << 30)
@@ -60,10 +57,7 @@ typedef struct {
      struct file *interp_file;
 } Node;

-static DEFINE_RWLOCK(entries_lock);
 static struct file_system_type bm_fs_type;
-static struct vfsmount *bm_mnt;
-static int entry_count;

 /*
  * Max length of the register string.  Determined by:
@@ -85,13 +79,13 @@ static int entry_count;
  * if we do, return the node, else NULL
  * locking is done in load_misc_binary
  */
-static Node *check_file(struct linux_binprm *bprm)
+static Node *check_file(struct user_namespace *ns, struct linux_binprm *bprm)
 {
      char *p = strrchr(bprm->interp, '.');
      struct list_head *l;

      /* Walk all the registered handlers. */
-     list_for_each(l, &entries) {
+     list_for_each(l, &ns->binfmt_ns->entries) {
              Node *e = list_entry(l, Node, list);
              char *s;
              int j;
@@ -133,17 +127,18 @@ static int load_misc_binary(struct linux_binprm *bprm)
      struct file *interp_file = NULL;
      int retval;
      int fd_binary = -1;
+     struct user_namespace *ns = current_user_ns();

      retval = -ENOEXEC;
-     if (!enabled)
+     if (!ns->binfmt_ns->enabled)
              return retval;

      /* to keep locking time low, we copy the interpreter string */
-     read_lock(&entries_lock);
-     fmt = check_file(bprm);
+     read_lock(&ns->binfmt_ns->entries_lock);
It looks like ns->binfmt_ns isn't protected by any lock and
ns->binfmt_ns can be changed between read_lock() and read_unlock().

This can be fixed if ns->binfmt_ns will be dereferenced only once in
this function:

        struct binfmt_namespace *binfmt_ns = ns->binfmt_ns;
Technically, wouldn't you want READ_ONCE(ns->binfmt_ns)?
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help