2019-08-25 09:49:18 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2005-11-07 08:58:51 +00:00
|
|
|
/*
|
2008-02-05 06:31:10 +00:00
|
|
|
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2022-03-03 07:53:33 +00:00
|
|
|
#include <string.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sched.h>
|
2008-06-06 05:46:14 +00:00
|
|
|
#include <linux/limits.h>
|
2007-10-16 08:27:11 +00:00
|
|
|
#include <sys/socket.h>
|
2008-02-05 06:31:10 +00:00
|
|
|
#include <sys/wait.h>
|
2012-10-08 02:27:32 +00:00
|
|
|
#include <kern_util.h>
|
|
|
|
#include <os.h>
|
|
|
|
#include <um_malloc.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
struct helper_data {
|
|
|
|
void (*pre_exec)(void*);
|
|
|
|
void *pre_data;
|
|
|
|
char **argv;
|
|
|
|
int fd;
|
2006-11-25 19:09:39 +00:00
|
|
|
char *buf;
|
2005-04-16 22:20:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int helper_child(void *arg)
|
|
|
|
{
|
|
|
|
struct helper_data *data = arg;
|
|
|
|
char **argv = data->argv;
|
2011-07-26 00:12:50 +00:00
|
|
|
int err, ret;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2006-10-20 06:28:21 +00:00
|
|
|
if (data->pre_exec != NULL)
|
2005-04-16 22:20:36 +00:00
|
|
|
(*data->pre_exec)(data->pre_data);
|
2008-02-05 06:31:10 +00:00
|
|
|
err = execvp_noalloc(data->buf, argv[0], argv);
|
|
|
|
|
|
|
|
/* If the exec succeeds, we don't get here */
|
2011-07-26 00:12:50 +00:00
|
|
|
CATCH_EINTR(ret = write(data->fd, &err, sizeof(err)));
|
2008-02-05 06:31:10 +00:00
|
|
|
|
2006-10-20 06:28:21 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-05 06:31:10 +00:00
|
|
|
/* Returns either the pid of the child process we run or -E* on failure. */
|
2007-07-16 06:38:56 +00:00
|
|
|
int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct helper_data data;
|
|
|
|
unsigned long stack, sp;
|
|
|
|
int pid, fds[2], ret, n;
|
|
|
|
|
2021-01-10 18:05:08 +00:00
|
|
|
stack = alloc_stack(0, __cant_sleep());
|
2006-10-20 06:28:21 +00:00
|
|
|
if (stack == 0)
|
2006-09-26 06:33:02 +00:00
|
|
|
return -ENOMEM;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-10-16 08:27:11 +00:00
|
|
|
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
|
2006-10-20 06:28:21 +00:00
|
|
|
if (ret < 0) {
|
2007-10-16 08:27:11 +00:00
|
|
|
ret = -errno;
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
|
|
|
|
errno);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto out_free;
|
|
|
|
}
|
|
|
|
|
2007-10-16 08:27:11 +00:00
|
|
|
ret = os_set_exec_close(fds[1]);
|
2006-10-20 06:28:21 +00:00
|
|
|
if (ret < 0) {
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
|
|
|
|
"ret = %d\n", -ret);
|
2005-04-16 22:20:36 +00:00
|
|
|
goto out_close;
|
|
|
|
}
|
|
|
|
|
um: Fix stack pointer alignment
GCC assumes that stack is aligned to 16-byte on call sites [1].
Since GCC 8, GCC began using 16-byte aligned SSE instructions to
implement assignments to structs on stack. When
CC_OPTIMIZE_FOR_PERFORMANCE is enabled, this affects
os-Linux/sigio.c, write_sigio_thread:
struct pollfds *fds, tmp;
tmp = current_poll;
Note that struct pollfds is exactly 16 bytes in size.
GCC 8+ generates assembly similar to:
movdqa (%rdi),%xmm0
movaps %xmm0,-0x50(%rbp)
This is an issue, because movaps will #GP if -0x50(%rbp) is not
aligned to 16 bytes [2], and how rbp gets assigned to is via glibc
clone thread_start, then function prologue, going though execution
trace similar to (showing only relevant instructions):
sub $0x10,%rsi
mov %rcx,0x8(%rsi)
mov %rdi,(%rsi)
syscall
pop %rax
pop %rdi
callq *%rax
push %rbp
mov %rsp,%rbp
The stack pointer always points to the topmost element on stack,
rather then the space right above the topmost. On push, the
pointer decrements first before writing to the memory pointed to
by it. Therefore, there is no need to have the stack pointer
pointer always point to valid memory unless the stack is poped;
so the `- sizeof(void *)` in the code is unnecessary.
On the other hand, glibc reserves the 16 bytes it needs on stack
and pops itself, so by the call instruction the stack pointer
is exactly the caller-supplied sp. It then push the 16 bytes of
the return address and the saved stack pointer, so the base
pointer will be 16-byte aligned if and only if the caller
supplied sp is 16-byte aligned. Therefore, the caller must supply
a 16-byte aligned pointer, which `stack + UM_KERN_PAGE_SIZE`
already satisfies.
On a side note, musl is unaffected by this issue because it forces
16 byte alignment via `and $-16,%rsi` in its clone wrapper.
Similarly, glibc i386 is also unaffected because it has
`andl $0xfffffff0, %ecx`.
To reproduce this bug, enable CONFIG_UML_RTC and
CC_OPTIMIZE_FOR_PERFORMANCE. uml_rtc will call
add_sigio_fd which will then cause write_sigio_thread to either go
into segfault loop or panic with "Segfault with no mm".
Similarly, signal stacks will be aligned by the host kernel upon
signal delivery. `- sizeof(void *)` to sigaltstack is
unconventional and extraneous.
On a related note, initialization of longjmp buffers do require
`- sizeof(void *)`. This is to account for the return address
that would have been pushed to the stack at the call site.
The reason for uml to respect 16-byte alignment, rather than
telling GCC to assume 8-byte alignment like the host kernel since
commit d9b0cde91c60 ("x86-64, gcc: Use
-mpreferred-stack-boundary=3 if supported"), is because uml links
against libc. There is no reason to assume libc is also compiled
with that flag and assumes 8-byte alignment rather than 16-byte.
[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838
[2] https://c9x.me/x86/html/file_module_x86_id_180.html
Signed-off-by: YiFei Zhu <zhuyifei1999@gmail.com>
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Richard Weinberger <richard@nod.at>
2021-04-20 05:56:10 +00:00
|
|
|
sp = stack + UM_KERN_PAGE_SIZE;
|
2005-04-16 22:20:36 +00:00
|
|
|
data.pre_exec = pre_exec;
|
|
|
|
data.pre_data = pre_data;
|
|
|
|
data.argv = argv;
|
|
|
|
data.fd = fds[1];
|
2008-05-12 21:01:52 +00:00
|
|
|
data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
|
|
|
|
uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
|
2007-12-18 00:19:46 +00:00
|
|
|
pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
|
2006-10-20 06:28:21 +00:00
|
|
|
if (pid < 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
ret = -errno;
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
|
|
|
|
errno);
|
2006-11-25 19:09:39 +00:00
|
|
|
goto out_free2;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2005-11-07 08:58:51 +00:00
|
|
|
close(fds[1]);
|
2005-04-16 22:20:36 +00:00
|
|
|
fds[1] = -1;
|
|
|
|
|
2007-05-06 21:51:33 +00:00
|
|
|
/*
|
|
|
|
* Read the errno value from the child, if the exec failed, or get 0 if
|
|
|
|
* the exec succeeded because the pipe fd was set as close-on-exec.
|
|
|
|
*/
|
2007-05-06 21:51:35 +00:00
|
|
|
n = read(fds[0], &ret, sizeof(ret));
|
2006-10-20 06:28:21 +00:00
|
|
|
if (n == 0) {
|
2005-04-16 22:20:36 +00:00
|
|
|
ret = pid;
|
2006-10-20 06:28:21 +00:00
|
|
|
} else {
|
|
|
|
if (n < 0) {
|
2007-05-06 21:51:35 +00:00
|
|
|
n = -errno;
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "run_helper : read on pipe failed, "
|
|
|
|
"ret = %d\n", -n);
|
2006-09-26 06:33:02 +00:00
|
|
|
ret = n;
|
|
|
|
}
|
2015-08-09 19:49:07 +00:00
|
|
|
CATCH_EINTR(waitpid(pid, NULL, __WALL));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 07:53:33 +00:00
|
|
|
if (ret < 0)
|
|
|
|
printk(UM_KERN_ERR "run_helper : failed to exec %s on host: %s\n",
|
|
|
|
argv[0], strerror(-ret));
|
|
|
|
|
2006-11-25 19:09:39 +00:00
|
|
|
out_free2:
|
|
|
|
kfree(data.buf);
|
2005-04-16 22:20:36 +00:00
|
|
|
out_close:
|
|
|
|
if (fds[1] != -1)
|
2005-11-07 08:58:51 +00:00
|
|
|
close(fds[1]);
|
|
|
|
close(fds[0]);
|
2005-04-16 22:20:36 +00:00
|
|
|
out_free:
|
2007-07-16 06:38:56 +00:00
|
|
|
free_stack(stack, 0);
|
2006-10-20 06:28:21 +00:00
|
|
|
return ret;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2005-11-07 08:58:51 +00:00
|
|
|
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
|
2007-07-16 06:38:56 +00:00
|
|
|
unsigned long *stack_out)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
unsigned long stack, sp;
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 02:27:49 +00:00
|
|
|
int pid, status, err;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2021-01-10 18:05:08 +00:00
|
|
|
stack = alloc_stack(0, __cant_sleep());
|
2006-10-20 06:28:21 +00:00
|
|
|
if (stack == 0)
|
|
|
|
return -ENOMEM;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
um: Fix stack pointer alignment
GCC assumes that stack is aligned to 16-byte on call sites [1].
Since GCC 8, GCC began using 16-byte aligned SSE instructions to
implement assignments to structs on stack. When
CC_OPTIMIZE_FOR_PERFORMANCE is enabled, this affects
os-Linux/sigio.c, write_sigio_thread:
struct pollfds *fds, tmp;
tmp = current_poll;
Note that struct pollfds is exactly 16 bytes in size.
GCC 8+ generates assembly similar to:
movdqa (%rdi),%xmm0
movaps %xmm0,-0x50(%rbp)
This is an issue, because movaps will #GP if -0x50(%rbp) is not
aligned to 16 bytes [2], and how rbp gets assigned to is via glibc
clone thread_start, then function prologue, going though execution
trace similar to (showing only relevant instructions):
sub $0x10,%rsi
mov %rcx,0x8(%rsi)
mov %rdi,(%rsi)
syscall
pop %rax
pop %rdi
callq *%rax
push %rbp
mov %rsp,%rbp
The stack pointer always points to the topmost element on stack,
rather then the space right above the topmost. On push, the
pointer decrements first before writing to the memory pointed to
by it. Therefore, there is no need to have the stack pointer
pointer always point to valid memory unless the stack is poped;
so the `- sizeof(void *)` in the code is unnecessary.
On the other hand, glibc reserves the 16 bytes it needs on stack
and pops itself, so by the call instruction the stack pointer
is exactly the caller-supplied sp. It then push the 16 bytes of
the return address and the saved stack pointer, so the base
pointer will be 16-byte aligned if and only if the caller
supplied sp is 16-byte aligned. Therefore, the caller must supply
a 16-byte aligned pointer, which `stack + UM_KERN_PAGE_SIZE`
already satisfies.
On a side note, musl is unaffected by this issue because it forces
16 byte alignment via `and $-16,%rsi` in its clone wrapper.
Similarly, glibc i386 is also unaffected because it has
`andl $0xfffffff0, %ecx`.
To reproduce this bug, enable CONFIG_UML_RTC and
CC_OPTIMIZE_FOR_PERFORMANCE. uml_rtc will call
add_sigio_fd which will then cause write_sigio_thread to either go
into segfault loop or panic with "Segfault with no mm".
Similarly, signal stacks will be aligned by the host kernel upon
signal delivery. `- sizeof(void *)` to sigaltstack is
unconventional and extraneous.
On a related note, initialization of longjmp buffers do require
`- sizeof(void *)`. This is to account for the return address
that would have been pushed to the stack at the call site.
The reason for uml to respect 16-byte alignment, rather than
telling GCC to assume 8-byte alignment like the host kernel since
commit d9b0cde91c60 ("x86-64, gcc: Use
-mpreferred-stack-boundary=3 if supported"), is because uml links
against libc. There is no reason to assume libc is also compiled
with that flag and assumes 8-byte alignment rather than 16-byte.
[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838
[2] https://c9x.me/x86/html/file_module_x86_id_180.html
Signed-off-by: YiFei Zhu <zhuyifei1999@gmail.com>
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Richard Weinberger <richard@nod.at>
2021-04-20 05:56:10 +00:00
|
|
|
sp = stack + UM_KERN_PAGE_SIZE;
|
2007-12-18 00:19:46 +00:00
|
|
|
pid = clone(proc, (void *) sp, flags, arg);
|
2006-10-20 06:28:21 +00:00
|
|
|
if (pid < 0) {
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 02:27:49 +00:00
|
|
|
err = -errno;
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "run_helper_thread : clone failed, "
|
|
|
|
"errno = %d\n", errno);
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 02:27:49 +00:00
|
|
|
return err;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-10-20 06:28:21 +00:00
|
|
|
if (stack_out == NULL) {
|
2015-08-09 19:49:07 +00:00
|
|
|
CATCH_EINTR(pid = waitpid(pid, &status, __WALL));
|
2006-10-20 06:28:21 +00:00
|
|
|
if (pid < 0) {
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 02:27:49 +00:00
|
|
|
err = -errno;
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "run_helper_thread - wait failed, "
|
|
|
|
"errno = %d\n", errno);
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 02:27:49 +00:00
|
|
|
pid = err;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2006-10-20 06:28:21 +00:00
|
|
|
if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "run_helper_thread - thread "
|
|
|
|
"returned status 0x%x\n", status);
|
2007-07-16 06:38:56 +00:00
|
|
|
free_stack(stack, 0);
|
2006-10-20 06:28:21 +00:00
|
|
|
} else
|
|
|
|
*stack_out = stack;
|
|
|
|
return pid;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-05 06:31:10 +00:00
|
|
|
int helper_wait(int pid)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2007-12-18 00:19:46 +00:00
|
|
|
int ret, status;
|
2015-08-09 19:49:07 +00:00
|
|
|
int wflags = __WALL;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-12-18 00:19:46 +00:00
|
|
|
CATCH_EINTR(ret = waitpid(pid, &status, wflags));
|
2006-10-20 06:28:21 +00:00
|
|
|
if (ret < 0) {
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
|
|
|
|
"errno = %d\n", pid, errno);
|
2007-12-18 00:19:46 +00:00
|
|
|
return -errno;
|
|
|
|
} else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
2008-02-05 06:31:10 +00:00
|
|
|
printk(UM_KERN_ERR "helper_wait : process %d exited with "
|
|
|
|
"status 0x%x\n", pid, status);
|
2007-12-18 00:19:46 +00:00
|
|
|
return -ECHILD;
|
|
|
|
} else
|
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|