Thread (19 messages) flat view 19 messages, 8 authors, 2018-05-10

Re: [PATCH v2 net-next 1/4] umh: introduce fork_usermode_blob() helper

From: Alexei Starovoitov <hidden>
Date: 2018-05-05 16:24:15
Also in: lkml

On Sat, May 05, 2018 at 12:48:24AM -0400, Jann Horn wrote:
On Thu, May 3, 2018 at 12:36 AM, Alexei Starovoitov [off-list ref] wrote:
quoted
Introduce helper:
int fork_usermode_blob(void *data, size_t len, struct umh_info *info);
struct umh_info {
       struct file *pipe_to_umh;
       struct file *pipe_from_umh;
       pid_t pid;
};

that GPLed kernel modules (signed or unsigned) can use it to execute part
of its own data as swappable user mode process.

The kernel will do:
- mount "tmpfs"
- allocate a unique file in tmpfs
- populate that file with [data, data + len] bytes
- user-mode-helper code will do_execve that file and, before the process
  starts, the kernel will create two unix pipes for bidirectional
  communication between kernel module and umh
- close tmpfs file, effectively deleting it
- the fork_usermode_blob will return zero on success and populate
  'struct umh_info' with two unix pipes and the pid of the user process

As the first step in the development of the bpfilter project
the fork_usermode_blob() helper is introduced to allow user mode code
to be invoked from a kernel module. The idea is that user mode code plus
normal kernel module code are built as part of the kernel build
and installed as traditional kernel module into distro specified location,
such that from a distribution point of view, there is
no difference between regular kernel modules and kernel modules + umh code.
Such modules can be signed, modprobed, rmmod, etc. The use of this new helper
by a kernel module doesn't make it any special from kernel and user space
tooling point of view.
[...]
quoted
+static struct vfsmount *umh_fs;
+
+static int init_tmpfs(void)
+{
+       struct file_system_type *type;
+
+       if (umh_fs)
+               return 0;
+       type = get_fs_type("tmpfs");
+       if (!type)
+               return -ENODEV;
+       umh_fs = kern_mount(type);
+       if (IS_ERR(umh_fs)) {
+               int err = PTR_ERR(umh_fs);
+
+               put_filesystem(type);
+               umh_fs = NULL;
+               return err;
+       }
+       return 0;
+}
Should init_tmpfs() be holding some sort of mutex if it's fiddling
with `umh_fs`? The current code only calls it in initcall context, but
if that ever changes and two processes try to initialize the tmpfs at
the same time, a few things could go wrong.
I thought that module loading is serialized, so calls to
fork_usermode_blob() will be serialized as well, but looking at the code
again that doesn't seem to be the case, so need to revisit not only
this function, but the rest of it too.
I guess Luis' suggestion (putting a call to init_tmpfs() in
do_basic_setup()) might be the easiest way to get rid of that problem.
I still think that two mounts where umh mount is dynamic is cleaner.
Why waste the mount if no module uses this helper?
I'm thinking to wrap init_tmpfs into DO_ONCE instead or use a mutex.
Looks like shmem_file_setup_with_mnt() can be called in parallel
on the same mount, so that should be fine.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help