Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751638AbdIMOUQ (ORCPT ); Wed, 13 Sep 2017 10:20:16 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39916 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750993AbdIMOUO (ORCPT ); Wed, 13 Sep 2017 10:20:14 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 2F7B081E19 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=oleg@redhat.com Date: Wed, 13 Sep 2017 16:20:11 +0200 From: Oleg Nesterov To: Rob Landley Cc: Alan Cox , Geert Uytterhoeven , Linux Embedded , dalias@libc.org, "linux-kernel@vger.kernel.org" Subject: Re: execve(NULL, argv, envp) for nommu? Message-ID: <20170913142011.GA9563@redhat.com> References: <324c00d9-06a6-1fc5-83fe-5bd36d874501@landley.net> <20170905142436.262ed118@alans-desktop> <20170911151526.GA4126@redhat.com> <20170912154549.GA31411@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20170912154549.GA31411@redhat.com> User-Agent: Mutt/1.5.24 (2015-08-30) X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Wed, 13 Sep 2017 14:20:14 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2488 Lines: 84 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))