Skip to content

Commit

Permalink
Merge branch 'for-next/execve' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/kees/linux.git
  • Loading branch information
Stephen Rothwell committed Jul 14, 2022
2 parents afcdabe + 5036793 commit 6bcbb00
Showing 5 changed files with 105 additions and 4 deletions.
9 changes: 8 additions & 1 deletion fs/exec.c
Original file line number Diff line number Diff line change
@@ -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>
@@ -982,10 +983,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 +1033,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 +1156,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);
5 changes: 4 additions & 1 deletion kernel/fork.c
Original file line number Diff line number Diff line change
@@ -2034,8 +2034,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);
}
3 changes: 2 additions & 1 deletion kernel/nsproxy.c
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 1 addition & 1 deletion tools/testing/selftests/timens/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 90 additions & 0 deletions tools/testing/selftests/timens/vfork_exec.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 6bcbb00

Please sign in to comment.