From patchwork Wed Oct 30 11:21:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adrian Reber X-Patchwork-Id: 11219469 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1ACF11390 for ; Wed, 30 Oct 2019 11:21:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E367A2087F for ; Wed, 30 Oct 2019 11:21:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="hW48Lc0b" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726102AbfJ3LVS (ORCPT ); Wed, 30 Oct 2019 07:21:18 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:39042 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726065AbfJ3LVS (ORCPT ); Wed, 30 Oct 2019 07:21:18 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572434476; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=tGhGu7p5l4Jg5WUP1EoXs/pnsE4ygK0Noe6XcN9W1HY=; b=hW48Lc0b2Zgcso+nJMIm07U5vfiVOfFkCwvfV1XQ93+zj48kILzK/k4HRSoF1pS/OCxpwj DFelQwDDwBSWqnvObuUOmVutZNGoeQnYfnfE2zqE2BCU6BBDNTwvosxP+OXxjV1E8Q/D7M jx13Oznm92XZuBZWaJSoKfISe8eW+GU= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-261-28URAv_aPe-98OsF77jZ3A-1; Wed, 30 Oct 2019 07:21:13 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 601381800D56; Wed, 30 Oct 2019 11:21:12 +0000 (UTC) Received: from dcbz.redhat.com (unknown [10.36.118.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 600AF5D6D0; Wed, 30 Oct 2019 11:21:08 +0000 (UTC) From: Adrian Reber To: Christian Brauner , Shuah Khan , Eugene Syromiatnikov , linux-kselftest@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Adrian Reber Subject: [PATCH] selftests: add tests for clone3() Date: Wed, 30 Oct 2019 12:21:00 +0100 Message-Id: <20191030112100.700087-1-areber@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-MC-Unique: 28URAv_aPe-98OsF77jZ3A-1 X-Mimecast-Spam-Score: 0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org This adds tests for clone3() with different values and sizes of struct clone_args. This selftest was initially part of of the clone3() with PID selftest. After that patch was almost merged Eugene sent out a couple of patches to fix problems with these test. This commit now only contains the clone3() selftest after the LPC decision to rework clone3() with PID to allow setting the PID in multiple PID namespaces including all of Eugene's patches. Signed-off-by: Eugene Syromiatnikov Signed-off-by: Adrian Reber --- MAINTAINERS | 1 + tools/testing/selftests/Makefile | 1 + tools/testing/selftests/clone3/.gitignore | 1 + tools/testing/selftests/clone3/Makefile | 7 + tools/testing/selftests/clone3/clone3.c | 195 ++++++++++++++++++++++ 5 files changed, 205 insertions(+) create mode 100644 tools/testing/selftests/clone3/.gitignore create mode 100644 tools/testing/selftests/clone3/Makefile create mode 100644 tools/testing/selftests/clone3/clone3.c diff --git a/MAINTAINERS b/MAINTAINERS index c6c34d04ce95..d9426de8fb38 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12830,6 +12830,7 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git F: samples/pidfd/ F: tools/testing/selftests/pidfd/ +F: tools/testing/selftests/clone3/ K: (?i)pidfd K: (?i)clone3 K: \b(clone_args|kernel_clone_args)\b diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 4cdbae6f4e61..ad442364218a 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -4,6 +4,7 @@ TARGETS += bpf TARGETS += breakpoints TARGETS += capabilities TARGETS += cgroup +TARGETS += clone3 TARGETS += cpufreq TARGETS += cpu-hotplug TARGETS += drivers/dma-buf diff --git a/tools/testing/selftests/clone3/.gitignore b/tools/testing/selftests/clone3/.gitignore new file mode 100644 index 000000000000..85d9d3ba2524 --- /dev/null +++ b/tools/testing/selftests/clone3/.gitignore @@ -0,0 +1 @@ +clone3 diff --git a/tools/testing/selftests/clone3/Makefile b/tools/testing/selftests/clone3/Makefile new file mode 100644 index 000000000000..ea922c014ae4 --- /dev/null +++ b/tools/testing/selftests/clone3/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +CFLAGS += -I../../../../usr/include/ + +TEST_GEN_PROGS := clone3 + +include ../lib.mk diff --git a/tools/testing/selftests/clone3/clone3.c b/tools/testing/selftests/clone3/clone3.c new file mode 100644 index 000000000000..a5a1ed91e550 --- /dev/null +++ b/tools/testing/selftests/clone3/clone3.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Based on Christian Brauner's clone3() example */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" + +/* + * Different sizes of struct clone_args + */ +#define CLONE3_ARGS_SIZE_V0 64 + +enum test_mode { + CLONE3_ARGS_NO_TEST, + CLONE3_ARGS_ALL_0, + CLONE3_ARGS_ALL_1, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG, +}; + +static pid_t raw_clone(struct clone_args *args, size_t size) +{ + return syscall(__NR_clone3, args, size); +} + +static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode) +{ + struct clone_args args = {0}; + pid_t ppid = -1; + pid_t pid = -1; + int status; + + args.flags = flags; + args.exit_signal = SIGCHLD; + + if (size == 0) + size = sizeof(struct clone_args); + + switch (test_mode) { + case CLONE3_ARGS_ALL_0: + args.flags = 0; + args.pidfd = 0; + args.child_tid = 0; + args.parent_tid = 0; + args.exit_signal = 0; + args.stack = 0; + args. stack_size = 0; + args.tls = 0; + break; + + case CLONE3_ARGS_ALL_1: + args.flags = 1; + args.pidfd = 1; + args.child_tid = 1; + args.parent_tid = 1; + args.exit_signal = 1; + args.stack = 1; + args. stack_size = 1; + args.tls = 1; + break; + + case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG: + args.exit_signal = 0xbadc0ded00000000ULL; + break; + + case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG: + args.exit_signal = 0x0000000080000000ULL; + break; + + case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG: + args.exit_signal = 0x0000000000000100ULL; + break; + + case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG: + args.exit_signal = 0x00000000000000f0ULL; + break; + } + + pid = raw_clone(&args, size); + if (pid < 0) { + ksft_print_msg("%s - Failed to create new process\n", + strerror(errno)); + return -errno; + } + + if (pid == 0) { + ksft_print_msg("I am the child, my PID is %d\n", getpid()); + _exit(EXIT_SUCCESS); + } + + ppid = getpid(); + ksft_print_msg("I am the parent (%d). My child's pid is %d\n", + ppid, pid); + + (void)wait(&status); + if (WEXITSTATUS(status)) + return WEXITSTATUS(status); + + return 0; +} + +static void test_clone3(uint64_t flags, size_t size, int expected, + enum test_mode test_mode) +{ + int ret; + + ksft_print_msg( + "[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n", + getpid(), flags, size); + ret = call_clone3(flags, size, test_mode); + ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n", + getpid(), ret, expected); + if (ret != expected) + ksft_test_result_fail( + "[%d] Result (%d) is different than expected (%d)\n", + getpid(), ret, expected); + else + ksft_test_result_pass( + "[%d] Result (%d) matches expectation (%d)\n", + getpid(), ret, expected); +} +int main(int argc, char *argv[]) +{ + pid_t pid; + + ksft_print_header(); + ksft_set_plan(17); + + /* Just a simple clone3() should return 0.*/ + test_clone3(0, 0, 0, CLONE3_ARGS_NO_TEST); + /* Do a clone3() in a new PID NS.*/ + test_clone3(CLONE_NEWPID, 0, 0, CLONE3_ARGS_NO_TEST); + /* Do a clone3() with CLONE3_ARGS_SIZE_V0. */ + test_clone3(0, CLONE3_ARGS_SIZE_V0, 0, CLONE3_ARGS_NO_TEST); + /* Do a clone3() with CLONE3_ARGS_SIZE_V0 - 8 */ + test_clone3(0, CLONE3_ARGS_SIZE_V0 - 8, -EINVAL, CLONE3_ARGS_NO_TEST); + /* Do a clone3() with sizeof(struct clone_args) + 8 */ + test_clone3(0, sizeof(struct clone_args) + 8, 0, CLONE3_ARGS_NO_TEST); + /* Do a clone3() with all members set to 1 */ + test_clone3(0, CLONE3_ARGS_SIZE_V0, -EINVAL, CLONE3_ARGS_ALL_1); + /* Do a clone3() with exit_signal having highest 32 bits non-zero */ + test_clone3(0, CLONE3_ARGS_SIZE_V0, -EINVAL, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG); + /* Do a clone3() with negative 32-bit exit_signal */ + test_clone3(0, CLONE3_ARGS_SIZE_V0, -EINVAL, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG); + /* Do a clone3() with exit_signal not fitting into CSIGNAL mask */ + test_clone3(0, CLONE3_ARGS_SIZE_V0, -EINVAL, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG); + /* Do a clone3() with NSIG < exit_signal < CSIG */ + test_clone3(0, CLONE3_ARGS_SIZE_V0, -EINVAL, + CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG); + /* + * Do a clone3() with sizeof(struct clone_args) + 8 + * and all members set to 0. + */ + test_clone3(0, sizeof(struct clone_args) + 8, 0, CLONE3_ARGS_ALL_0); + /* + * Do a clone3() with sizeof(struct clone_args) + 8 + * and all members set to 0. + */ + test_clone3(0, sizeof(struct clone_args) + 8, -EINVAL, + CLONE3_ARGS_ALL_1); + /* Do a clone3() with > page size */ + test_clone3(0, getpagesize() + 8, -E2BIG, CLONE3_ARGS_NO_TEST); + /* Do a clone3() with CLONE3_ARGS_SIZE_V0 in a new PID NS. */ + test_clone3(CLONE_NEWPID, CLONE3_ARGS_SIZE_V0, 0, CLONE3_ARGS_NO_TEST); + /* Do a clone3() with CLONE3_ARGS_SIZE_V0 - 8 in a new PID NS */ + test_clone3(CLONE_NEWPID, CLONE3_ARGS_SIZE_V0 - 8, -EINVAL, + CLONE3_ARGS_NO_TEST); + /* Do a clone3() with sizeof(struct clone_args) + 8 in a new PID NS */ + test_clone3(CLONE_NEWPID, sizeof(struct clone_args) + 8, 0, + CLONE3_ARGS_NO_TEST); + /* Do a clone3() with > page size in a new PID NS */ + test_clone3(CLONE_NEWPID, getpagesize() + 8, -E2BIG, + CLONE3_ARGS_NO_TEST); + + return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail(); +}