On 09/12, Oleg Nesterov wrote:
>
> On 09/12, Rob Landley wrote:
> >
> > On 09/11/2017 10:15 AM, Oleg Nesterov wrote:
> > > On 09/08, Rob Landley wrote:
> > >>
> > >> So is exec(NULL, argv, envp) a reasonable thing to want?
> > >
> > > I think that something like prctl(PR_OPEN_EXE_FILE) which does
> > >
> > >   dentry_open(current->mm->exe_file->path, O_PATH)
> > >
> > > and returns fd make more sense.
> > >
> > > Then you can do execveat(fd, "", ..., AT_EMPTY_PATH).
> > I'm all for it? That sounds like a cosmetic difference, a more verbose
> > way of achieving the same outcome.
>
> Simpler to implement. Something like the (untested) patch below. Not sure
> it is correct, not sure it is good idea, etc.

OTOH... with the trivial patch below

        execveat(AT_FDCWD, "", NULL, NULL, AT_EMPTY_PATH);

should always work, even if the binary is not in scope after chroot, or if
it is no longer executable, or unlinked. But I am not sure what else should
we do to avoid the security problems.

Oleg.


--- x/fs/exec.c
+++ x/fs/exec.c
@@ -832,23 +832,32 @@ static struct file *do_open_execat(int fd, struct 
filename *name, int flags)
 {
        struct file *file;
        int err;
-       struct open_flags open_exec_flags = {
-               .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
-               .acc_mode = MAY_EXEC,
-               .intent = LOOKUP_OPEN,
-               .lookup_flags = LOOKUP_FOLLOW,
-       };
-
-       if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
-               return ERR_PTR(-EINVAL);
-       if (flags & AT_SYMLINK_NOFOLLOW)
-               open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW;
-       if (flags & AT_EMPTY_PATH)
-               open_exec_flags.lookup_flags |= LOOKUP_EMPTY;
 
-       file = do_filp_open(fd, name, &open_exec_flags);
-       if (IS_ERR(file))
-               goto out;
+       if (fd == AT_FDCWD && name->name[0] == '\0' && flags == AT_EMPTY_PATH) {
+               file = get_mm_exe_file(current->mm);
+               if (!file) {
+                       file = ERR_PTR(-ENOENT);
+                       goto out;
+               }
+       } else {
+               struct open_flags open_exec_flags = {
+                       .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
+                       .acc_mode = MAY_EXEC,
+                       .intent = LOOKUP_OPEN,
+                       .lookup_flags = LOOKUP_FOLLOW,
+               };
+
+               if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
+                       return ERR_PTR(-EINVAL);
+               if (flags & AT_SYMLINK_NOFOLLOW)
+                       open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW;
+               if (flags & AT_EMPTY_PATH)
+                       open_exec_flags.lookup_flags |= LOOKUP_EMPTY;
+
+               file = do_filp_open(fd, name, &open_exec_flags);
+               if (IS_ERR(file))
+                       goto out;
+       }
 
        err = -EACCES;
        if (!S_ISREG(file_inode(file)->i_mode))

Reply via email to