Commit d7b767b5 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 9a8ac9ee c6e8e36c
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#include <linux/io_uring.h> #include <linux/io_uring.h>
#include <linux/syscall_user_dispatch.h> #include <linux/syscall_user_dispatch.h>
#include <linux/coredump.h> #include <linux/coredump.h>
#include <linux/time_namespace.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
...@@ -630,7 +631,6 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm) ...@@ -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, unsigned int bytes_to_copy = min_t(unsigned int, len,
min_not_zero(offset_in_page(pos), PAGE_SIZE)); min_not_zero(offset_in_page(pos), PAGE_SIZE));
struct page *page; struct page *page;
char *kaddr;
pos -= bytes_to_copy; pos -= bytes_to_copy;
arg -= bytes_to_copy; arg -= bytes_to_copy;
...@@ -639,11 +639,8 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm) ...@@ -639,11 +639,8 @@ int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
page = get_arg_page(bprm, pos, 1); page = get_arg_page(bprm, pos, 1);
if (!page) if (!page)
return -E2BIG; return -E2BIG;
kaddr = kmap_atomic(page);
flush_arg_page(bprm, pos & PAGE_MASK, page); flush_arg_page(bprm, pos & PAGE_MASK, page);
memcpy(kaddr + offset_in_page(pos), arg, bytes_to_copy); memcpy_to_page(page, offset_in_page(pos), arg, bytes_to_copy);
flush_dcache_page(page);
kunmap_atomic(kaddr);
put_arg_page(page); put_arg_page(page);
} }
...@@ -982,10 +979,12 @@ static int exec_mmap(struct mm_struct *mm) ...@@ -982,10 +979,12 @@ static int exec_mmap(struct mm_struct *mm)
{ {
struct task_struct *tsk; struct task_struct *tsk;
struct mm_struct *old_mm, *active_mm; struct mm_struct *old_mm, *active_mm;
bool vfork;
int ret; int ret;
/* Notify parent that we're no longer interested in the old VM */ /* Notify parent that we're no longer interested in the old VM */
tsk = current; tsk = current;
vfork = !!tsk->vfork_done;
old_mm = current->mm; old_mm = current->mm;
exec_mm_release(tsk, old_mm); exec_mm_release(tsk, old_mm);
if (old_mm) if (old_mm)
...@@ -1030,6 +1029,10 @@ static int exec_mmap(struct mm_struct *mm) ...@@ -1030,6 +1029,10 @@ static int exec_mmap(struct mm_struct *mm)
tsk->mm->vmacache_seqnum = 0; tsk->mm->vmacache_seqnum = 0;
vmacache_flush(tsk); vmacache_flush(tsk);
task_unlock(tsk); task_unlock(tsk);
if (vfork)
timens_on_fork(tsk->nsproxy, tsk);
if (old_mm) { if (old_mm) {
mmap_read_unlock(old_mm); mmap_read_unlock(old_mm);
BUG_ON(active_mm != old_mm); BUG_ON(active_mm != old_mm);
...@@ -1149,7 +1152,7 @@ static int de_thread(struct task_struct *tsk) ...@@ -1149,7 +1152,7 @@ static int de_thread(struct task_struct *tsk)
/* /*
* We are going to release_task()->ptrace_unlink() silently, * We are going to release_task()->ptrace_unlink() silently,
* the tracer can sleep in do_wait(). EXIT_DEAD guarantees * 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)) if (unlikely(leader->ptrace))
__wake_up_parent(leader, leader->parent); __wake_up_parent(leader, leader->parent);
......
...@@ -2033,8 +2033,11 @@ static __latent_entropy struct task_struct *copy_process( ...@@ -2033,8 +2033,11 @@ static __latent_entropy struct task_struct *copy_process(
/* /*
* If the new process will be in a different time namespace * 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. * 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) if (nsp->time_ns != nsp->time_ns_for_children)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
...@@ -179,6 +179,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) ...@@ -179,6 +179,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
if (IS_ERR(new_ns)) if (IS_ERR(new_ns))
return PTR_ERR(new_ns); return PTR_ERR(new_ns);
if ((flags & CLONE_VM) == 0)
timens_on_fork(new_ns, tsk); timens_on_fork(new_ns, tsk);
tsk->nsproxy = new_ns; tsk->nsproxy = new_ns;
......
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 TEST_GEN_PROGS_EXTENDED := gettime_perf
CFLAGS := -Wall -Werror -pthread CFLAGS := -Wall -Werror -pthread
......
// 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment