mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
execve updates for v5.20-rc1
- Allow unsharing time namespace on vfork+exec (Andrei Vagin) - Replace usage of deprecated kmap APIs (Fabio M. De Francesco) - Fix spelling mistake (Zhang Jiaming) -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAmLoDyAWHGtlZXNjb29r QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJh0mEACL07hj3eT3rWg6ohZx9sCTcAjY /tG+zxLQ7xu717nM1a4j7CI5kdNNpYbsCqG71ikDDRrOCeEutu7M8zE1emctjtHv oh853D6BKhV2Hvsiuk1oM2ZHR1bmgiW1eFNAJcCLz6rE6wYu564R0wYJV0h418fH Rjk+Y989A7Srs9t/9GQSktjX3Q039/PG28avhA5q144/ZNycr5FnLFOf4RlmzEUz 7E8TfGsftX8eRAfxW/dPiWuIKMuYPLqspca9pT3aFj3ze2qKnldjNV3c9M5ajL5Q q7KKWeWzunKyYHMaRzIxkHyhs396ZGKFN2PbcNYyml+NBItyc3fCHishMF7bW0Vb nyZbmYJslBloYmrSJYgqCfxyjUuhe0cMMk9iMzDVp6ROwtLgFFLwfwunM6RwRmnr dAmM8QGwSE3qYLhVnLEcRqpgdXzVd+S0TGhB5k5AyI3628/mLxhE66/eWq0X8QF5 los5zku1GagMkylt6SOGb3TME4JZe6ZdZpU4fe/ilM22qw852xgbF3+6Zap6IBbD AdzXVCHyU/obORfIxx5KTF213m4KpkWBBi3N1/vVlxIAFAUy1WdXDM1o2RPMD7hw DeHe8sgfTZxLmSqfWLuX+3qC94IvrbDPFaRCIMj1QNK0ltM8I9oHRPcUFyZMaV0O xHN/5QtmgVDfKA3mTw== =82SS -----END PGP SIGNATURE----- Merge tag 'execve-v5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux Pull execve updates from Kees Cook: - Allow unsharing time namespace on vfork+exec (Andrei Vagin) - Replace usage of deprecated kmap APIs (Fabio M. De Francesco) - Fix spelling mistake (Zhang Jiaming) * tag 'execve-v5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: exec: Call kmap_local_page() in copy_string_kernel() exec: Fix a spelling mistake selftests/timens: add a test for vfork+exit fs/exec: allow to unshare a time namespace on vfork+exec
This commit is contained in:
commit
d7b767b508
15
fs/exec.c
15
fs/exec.c
@ -65,6 +65,7 @@
|
||||
#include <linux/io_uring.h>
|
||||
#include <linux/syscall_user_dispatch.h>
|
||||
#include <linux/coredump.h>
|
||||
#include <linux/time_namespace.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/mmu_context.h>
|
||||
@ -630,7 +631,6 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
|
||||
unsigned int bytes_to_copy = min_t(unsigned int, len,
|
||||
min_not_zero(offset_in_page(pos), PAGE_SIZE));
|
||||
struct page *page;
|
||||
char *kaddr;
|
||||
|
||||
pos -= bytes_to_copy;
|
||||
arg -= bytes_to_copy;
|
||||
@ -639,11 +639,8 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
|
||||
page = get_arg_page(bprm, pos, 1);
|
||||
if (!page)
|
||||
return -E2BIG;
|
||||
kaddr = kmap_atomic(page);
|
||||
flush_arg_page(bprm, pos & PAGE_MASK, page);
|
||||
memcpy(kaddr + offset_in_page(pos), arg, bytes_to_copy);
|
||||
flush_dcache_page(page);
|
||||
kunmap_atomic(kaddr);
|
||||
memcpy_to_page(page, offset_in_page(pos), arg, bytes_to_copy);
|
||||
put_arg_page(page);
|
||||
}
|
||||
|
||||
@ -982,10 +979,12 @@ static int exec_mmap(struct mm_struct *mm)
|
||||
{
|
||||
struct task_struct *tsk;
|
||||
struct mm_struct *old_mm, *active_mm;
|
||||
bool vfork;
|
||||
int ret;
|
||||
|
||||
/* Notify parent that we're no longer interested in the old VM */
|
||||
tsk = current;
|
||||
vfork = !!tsk->vfork_done;
|
||||
old_mm = current->mm;
|
||||
exec_mm_release(tsk, old_mm);
|
||||
if (old_mm)
|
||||
@ -1030,6 +1029,10 @@ static int exec_mmap(struct mm_struct *mm)
|
||||
tsk->mm->vmacache_seqnum = 0;
|
||||
vmacache_flush(tsk);
|
||||
task_unlock(tsk);
|
||||
|
||||
if (vfork)
|
||||
timens_on_fork(tsk->nsproxy, tsk);
|
||||
|
||||
if (old_mm) {
|
||||
mmap_read_unlock(old_mm);
|
||||
BUG_ON(active_mm != old_mm);
|
||||
@ -1149,7 +1152,7 @@ static int de_thread(struct task_struct *tsk)
|
||||
/*
|
||||
* We are going to release_task()->ptrace_unlink() silently,
|
||||
* the tracer can sleep in do_wait(). EXIT_DEAD guarantees
|
||||
* the tracer wont't block again waiting for this thread.
|
||||
* the tracer won't block again waiting for this thread.
|
||||
*/
|
||||
if (unlikely(leader->ptrace))
|
||||
__wake_up_parent(leader, leader->parent);
|
||||
|
@ -2033,8 +2033,11 @@ static __latent_entropy struct task_struct *copy_process(
|
||||
/*
|
||||
* If the new process will be in a different time namespace
|
||||
* do not allow it to share VM or a thread group with the forking task.
|
||||
*
|
||||
* On vfork, the child process enters the target time namespace only
|
||||
* after exec.
|
||||
*/
|
||||
if (clone_flags & (CLONE_THREAD | CLONE_VM)) {
|
||||
if ((clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM) {
|
||||
if (nsp->time_ns != nsp->time_ns_for_children)
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
@ -179,7 +179,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
|
||||
if (IS_ERR(new_ns))
|
||||
return PTR_ERR(new_ns);
|
||||
|
||||
timens_on_fork(new_ns, tsk);
|
||||
if ((flags & CLONE_VM) == 0)
|
||||
timens_on_fork(new_ns, tsk);
|
||||
|
||||
tsk->nsproxy = new_ns;
|
||||
return 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex
|
||||
TEST_GEN_PROGS := timens timerfd timer clock_nanosleep procfs exec futex vfork_exec
|
||||
TEST_GEN_PROGS_EXTENDED := gettime_perf
|
||||
|
||||
CFLAGS := -Wall -Werror -pthread
|
||||
|
90
tools/testing/selftests/timens/vfork_exec.c
Normal file
90
tools/testing/selftests/timens/vfork_exec.c
Normal file
@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "timens.h"
|
||||
|
||||
#define OFFSET (36000)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct timespec now, tst;
|
||||
int status, i;
|
||||
pid_t pid;
|
||||
|
||||
if (argc > 1) {
|
||||
if (sscanf(argv[1], "%ld", &now.tv_sec) != 1)
|
||||
return pr_perror("sscanf");
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
_gettime(CLOCK_MONOTONIC, &tst, i);
|
||||
if (abs(tst.tv_sec - now.tv_sec) > 5)
|
||||
return pr_fail("%ld %ld\n", now.tv_sec, tst.tv_sec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nscheck();
|
||||
|
||||
ksft_set_plan(1);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
if (unshare_timens())
|
||||
return 1;
|
||||
|
||||
if (_settime(CLOCK_MONOTONIC, OFFSET))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
_gettime(CLOCK_MONOTONIC, &tst, i);
|
||||
if (abs(tst.tv_sec - now.tv_sec) > 5)
|
||||
return pr_fail("%ld %ld\n",
|
||||
now.tv_sec, tst.tv_sec);
|
||||
}
|
||||
|
||||
pid = vfork();
|
||||
if (pid < 0)
|
||||
return pr_perror("fork");
|
||||
|
||||
if (pid == 0) {
|
||||
char now_str[64];
|
||||
char *cargv[] = {"exec", now_str, NULL};
|
||||
char *cenv[] = {NULL};
|
||||
|
||||
// Check that we are still in the source timens.
|
||||
for (i = 0; i < 2; i++) {
|
||||
_gettime(CLOCK_MONOTONIC, &tst, i);
|
||||
if (abs(tst.tv_sec - now.tv_sec) > 5)
|
||||
return pr_fail("%ld %ld\n",
|
||||
now.tv_sec, tst.tv_sec);
|
||||
}
|
||||
|
||||
/* Check for proper vvar offsets after execve. */
|
||||
snprintf(now_str, sizeof(now_str), "%ld", now.tv_sec + OFFSET);
|
||||
execve("/proc/self/exe", cargv, cenv);
|
||||
return pr_perror("execve");
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) != pid)
|
||||
return pr_perror("waitpid");
|
||||
|
||||
if (status)
|
||||
ksft_exit_fail();
|
||||
|
||||
ksft_test_result_pass("exec\n");
|
||||
ksft_exit_pass();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user