It seems somehow common to execve /proc/self/exe in docker
or golang community these days.
At least, moby "reexec" and runc "libcontainer" do that.
Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com>
---
linux-user/syscall.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c9f812091c..a2b03ecb8b 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8470,6 +8470,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#endif
case TARGET_NR_execve:
{
+ const char *path;
char **argp, **envp;
int argc, envc;
abi_ulong gp;
@@ -8537,7 +8538,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
* before the execve completes and makes it the other
* program's problem.
*/
- ret = get_errno(safe_execve(p, argp, envp));
+ path = p;
+ if (is_proc_myself(path, "exe")) {
+ path = exec_path;
+ }
+ ret = get_errno(safe_execve(path, argp, envp));
unlock_user(p, arg1, 0);
goto execve_end;
--
2.21.1 (Apple Git-122.3)
Le 31/05/2021 à 07:50, YAMAMOTO Takashi a écrit : > It seems somehow common to execve /proc/self/exe in docker > or golang community these days. > At least, moby "reexec" and runc "libcontainer" do that. > > Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com> > --- > linux-user/syscall.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index c9f812091c..a2b03ecb8b 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -8470,6 +8470,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, > #endif > case TARGET_NR_execve: > { > + const char *path; > char **argp, **envp; > int argc, envc; > abi_ulong gp; > @@ -8537,7 +8538,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, > * before the execve completes and makes it the other > * program's problem. > */ > - ret = get_errno(safe_execve(p, argp, envp)); > + path = p; > + if (is_proc_myself(path, "exe")) { > + path = exec_path; > + } > + ret = get_errno(safe_execve(path, argp, envp)); > unlock_user(p, arg1, 0); > > goto execve_end; > The problem here is QEMU can fail to execute the file directly. The binary can be launched with binfmt_misc and the 'O' flag: ``O`` - open-binary Legacy behavior of binfmt_misc is to pass the full path of the binary to the interpreter as an argument. When this flag is included, binfmt_misc will open the file for reading and pass its descriptor as an argument, instead of the full path, thus allowing the interpreter to execute non-readable binaries. This feature should be used with care - the interpreter has to be trusted not to emit the contents of the non-readable binary. You should use do_openat() (that resolves the /proc/self/exe path) and fexecve(). Thanks, Laurent
On Sun, Jun 20, 2021 at 11:14 PM Laurent Vivier <laurent@vivier.eu> wrote: > > Le 31/05/2021 à 07:50, YAMAMOTO Takashi a écrit : > > It seems somehow common to execve /proc/self/exe in docker > > or golang community these days. > > At least, moby "reexec" and runc "libcontainer" do that. > > > > Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com> > > --- > > linux-user/syscall.c | 7 ++++++- > > 1 file changed, 6 insertions(+), 1 deletion(-) > > > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > > index c9f812091c..a2b03ecb8b 100644 > > --- a/linux-user/syscall.c > > +++ b/linux-user/syscall.c > > @@ -8470,6 +8470,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, > > #endif > > case TARGET_NR_execve: > > { > > + const char *path; > > char **argp, **envp; > > int argc, envc; > > abi_ulong gp; > > @@ -8537,7 +8538,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, > > * before the execve completes and makes it the other > > * program's problem. > > */ > > - ret = get_errno(safe_execve(p, argp, envp)); > > + path = p; > > + if (is_proc_myself(path, "exe")) { > > + path = exec_path; > > + } > > + ret = get_errno(safe_execve(path, argp, envp)); > > unlock_user(p, arg1, 0); > > > > goto execve_end; > > > > The problem here is QEMU can fail to execute the file directly. i don't understand this sentence. can you explain a bit? > > The binary can be launched with binfmt_misc and the 'O' flag: > > ``O`` - open-binary > Legacy behavior of binfmt_misc is to pass the full path > of the binary to the interpreter as an argument. When this flag is > included, binfmt_misc will open the file for reading and pass its > descriptor as an argument, instead of the full path, thus allowing > the interpreter to execute non-readable binaries. This feature > should be used with care - the interpreter has to be trusted not to > emit the contents of the non-readable binary. > > You should use do_openat() (that resolves the /proc/self/exe path) and fexecve(). i thought there was an issue with the approach. but i don't remember what it was. maybe i will retry it. > > Thanks, > Laurent
Le 21/06/2021 à 04:02, Takashi Yamamoto a écrit : > On Sun, Jun 20, 2021 at 11:14 PM Laurent Vivier <laurent@vivier.eu> wrote: >> >> Le 31/05/2021 à 07:50, YAMAMOTO Takashi a écrit : >>> It seems somehow common to execve /proc/self/exe in docker >>> or golang community these days. >>> At least, moby "reexec" and runc "libcontainer" do that. >>> >>> Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com> >>> --- >>> linux-user/syscall.c | 7 ++++++- >>> 1 file changed, 6 insertions(+), 1 deletion(-) >>> >>> diff --git a/linux-user/syscall.c b/linux-user/syscall.c >>> index c9f812091c..a2b03ecb8b 100644 >>> --- a/linux-user/syscall.c >>> +++ b/linux-user/syscall.c >>> @@ -8470,6 +8470,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, >>> #endif >>> case TARGET_NR_execve: >>> { >>> + const char *path; >>> char **argp, **envp; >>> int argc, envc; >>> abi_ulong gp; >>> @@ -8537,7 +8538,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, >>> * before the execve completes and makes it the other >>> * program's problem. >>> */ >>> - ret = get_errno(safe_execve(p, argp, envp)); >>> + path = p; >>> + if (is_proc_myself(path, "exe")) { >>> + path = exec_path; >>> + } >>> + ret = get_errno(safe_execve(path, argp, envp)); >>> unlock_user(p, arg1, 0); >>> >>> goto execve_end; >>> >> >> The problem here is QEMU can fail to execute the file directly. > > i don't understand this sentence. can you explain a bit? It's related to the text below. The binary can be executable ('x') but not readable ('r'), so QEMU cannot load it. It's the purpose of the 'O' flag: kernel opens the file and pass the FD to QEMU to execute it. Thanks, Laurent > >> >> The binary can be launched with binfmt_misc and the 'O' flag: >> >> ``O`` - open-binary >> Legacy behavior of binfmt_misc is to pass the full path >> of the binary to the interpreter as an argument. When this flag is >> included, binfmt_misc will open the file for reading and pass its >> descriptor as an argument, instead of the full path, thus allowing >> the interpreter to execute non-readable binaries. This feature >> should be used with care - the interpreter has to be trusted not to >> emit the contents of the non-readable binary. >> >> You should use do_openat() (that resolves the /proc/self/exe path) and fexecve(). > > i thought there was an issue with the approach. but i don't remember > what it was. > maybe i will retry it. > >> >> Thanks, >> Laurent
© 2016 - 2024 Red Hat, Inc.