From patchwork Wed Mar 11 21:17:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11432835 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 47AD914B7 for ; Wed, 11 Mar 2020 21:17:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DBAEF20756 for ; Wed, 11 Mar 2020 21:17:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="i1rRo9cQ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729366AbgCKVRl (ORCPT ); Wed, 11 Mar 2020 17:17:41 -0400 Received: from mail-pl1-f196.google.com ([209.85.214.196]:45224 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729102AbgCKVRk (ORCPT ); Wed, 11 Mar 2020 17:17:40 -0400 Received: by mail-pl1-f196.google.com with SMTP id b22so1675244pls.12 for ; Wed, 11 Mar 2020 14:17:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Nc9NjinbmrTaxyzjE2LeQktq68AoC4uPHhJEEjjrJgc=; b=i1rRo9cQXtQVJYpbkuUHBDz3DG2L+anp7slukdngNw8TGGR8GERDze0/8etvv/yWCU oK1pY3tV7qSb9h+h38yzskqqoUyBDN0LO34fCcezTJH4uiRheDXJoTKLGn8dSZkiw9c0 p7x8bEBWEzaa1MXRoL5I8RL7L3uHPzbYdtGf4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Nc9NjinbmrTaxyzjE2LeQktq68AoC4uPHhJEEjjrJgc=; b=Ecsm0QhQEVme08XV3eZKW4cq58N5HTGAIoGJzKLN4B4dDO4aH9zLec6+5OM6zIdSMt JoU3KPQCIjlf4JH0auYehSQ/9JfwuWlS9qe8NzUK42IWCLHGOWzRZpyUoseNle/pro/5 05FlB6Uj83APjqK8BVt2p/cTeLzjzWxdf7EakOLNcF9Gs4ym5rTg1JObLqLLElmXXy1X fJe0SCQvWQnrnltp40DVQ8kOBBxL+eW4rkNqcaZdfK4z8MAYLifJtc5KANKR1PIdscNS fGo0Gsh7y9vhFX4BOTQHbYQvjuOf6MRd34E3LuLg4Fxx+kDTJSTA6Zg04JBcHAsSxzJW GiRQ== X-Gm-Message-State: ANhLgQ0sQPj1EwZ+A4E/YuSxgZOfMVjva8lNIXVptqiudyjaku/KIXNz qBTsQIICgostuJXWgJfH6Cd+4w== X-Google-Smtp-Source: ADFU+vtwSFH+JOAbpOb/3n4HNpVl3+GgXIImjKKjyy8vWRpDCnnW52YDpgakBJbUmvK3PJtQ+eVTKA== X-Received: by 2002:a17:902:8485:: with SMTP id c5mr4831297plo.156.1583961459264; Wed, 11 Mar 2020 14:17:39 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id u3sm6874522pfb.36.2020.03.11.14.17.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Mar 2020 14:17:37 -0700 (PDT) From: Kees Cook To: Shuah Khan Cc: Kees Cook , Andy Lutomirski , Will Drewry , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/2] selftests/seccomp: Move test child waiting logic Date: Wed, 11 Mar 2020 14:17:32 -0700 Message-Id: <20200311211733.21211-2-keescook@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200311211733.21211-1-keescook@chromium.org> References: <20200311211733.21211-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org In order to better handle timeout failures, rearrange the child waiting logic into a separate function. This is mostly a copy/paste with an indentation change. To handle pid tracking, a new field is added for the child pid. Also move the alarm() pairing into the function. Signed-off-by: Kees Cook --- tools/testing/selftests/kselftest_harness.h | 93 +++++++++++---------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 5336b26506ab..c7b67e379219 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -635,6 +635,7 @@ struct __test_metadata { const char *name; void (*fn)(struct __test_metadata *); + pid_t pid; /* pid of test when being run */ int termsig; int passed; int trigger; /* extra handler after the evaluation */ @@ -695,64 +696,68 @@ static inline int __bail(int for_realz, bool no_print, __u8 step) return 0; } -void __run_test(struct __test_metadata *t) +void __wait_for_test(struct __test_metadata *t) { - pid_t child_pid; int status; + alarm(t->timeout); + waitpid(t->pid, &status, 0); + alarm(0); + + if (WIFEXITED(status)) { + t->passed = t->termsig == -1 ? !WEXITSTATUS(status) : 0; + if (t->termsig != -1) { + fprintf(TH_LOG_STREAM, + "%s: Test exited normally " + "instead of by signal (code: %d)\n", + t->name, + WEXITSTATUS(status)); + } else if (!t->passed) { + fprintf(TH_LOG_STREAM, + "%s: Test failed at step #%d\n", + t->name, + WEXITSTATUS(status)); + } + } else if (WIFSIGNALED(status)) { + t->passed = 0; + if (WTERMSIG(status) == SIGABRT) { + fprintf(TH_LOG_STREAM, + "%s: Test terminated by assertion\n", + t->name); + } else if (WTERMSIG(status) == t->termsig) { + t->passed = 1; + } else { + fprintf(TH_LOG_STREAM, + "%s: Test terminated unexpectedly " + "by signal %d\n", + t->name, + WTERMSIG(status)); + } + } else { + fprintf(TH_LOG_STREAM, + "%s: Test ended in some other way [%u]\n", + t->name, + status); + } +} + +void __run_test(struct __test_metadata *t) +{ t->passed = 1; t->trigger = 0; printf("[ RUN ] %s\n", t->name); - alarm(t->timeout); - child_pid = fork(); - if (child_pid < 0) { + t->pid = fork(); + if (t->pid < 0) { printf("ERROR SPAWNING TEST CHILD\n"); t->passed = 0; - } else if (child_pid == 0) { + } else if (t->pid == 0) { t->fn(t); /* return the step that failed or 0 */ _exit(t->passed ? 0 : t->step); } else { - /* TODO(wad) add timeout support. */ - waitpid(child_pid, &status, 0); - if (WIFEXITED(status)) { - t->passed = t->termsig == -1 ? !WEXITSTATUS(status) : 0; - if (t->termsig != -1) { - fprintf(TH_LOG_STREAM, - "%s: Test exited normally " - "instead of by signal (code: %d)\n", - t->name, - WEXITSTATUS(status)); - } else if (!t->passed) { - fprintf(TH_LOG_STREAM, - "%s: Test failed at step #%d\n", - t->name, - WEXITSTATUS(status)); - } - } else if (WIFSIGNALED(status)) { - t->passed = 0; - if (WTERMSIG(status) == SIGABRT) { - fprintf(TH_LOG_STREAM, - "%s: Test terminated by assertion\n", - t->name); - } else if (WTERMSIG(status) == t->termsig) { - t->passed = 1; - } else { - fprintf(TH_LOG_STREAM, - "%s: Test terminated unexpectedly " - "by signal %d\n", - t->name, - WTERMSIG(status)); - } - } else { - fprintf(TH_LOG_STREAM, - "%s: Test ended in some other way [%u]\n", - t->name, - status); - } + __wait_for_test(t); } printf("[ %4s ] %s\n", (t->passed ? "OK" : "FAIL"), t->name); - alarm(0); } static int test_harness_run(int __attribute__((unused)) argc, From patchwork Wed Mar 11 21:17:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 11432831 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 4924E92C for ; Wed, 11 Mar 2020 21:17:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D7E022074D for ; Wed, 11 Mar 2020 21:17:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="YgTgbM40" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729202AbgCKVRk (ORCPT ); Wed, 11 Mar 2020 17:17:40 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:36441 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726684AbgCKVRk (ORCPT ); Wed, 11 Mar 2020 17:17:40 -0400 Received: by mail-pf1-f196.google.com with SMTP id i13so2052810pfe.3 for ; Wed, 11 Mar 2020 14:17:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=jVB9ateUNPWjDSRVGMb+4rgbxEOqdavmk19dJVvZMIM=; b=YgTgbM406HdGsLsPlF+VVmtshblGPo2TvOf06wGTAhyHuMsZ2O+UXyNXLGkoFJjBZE cVnCgfZ5EH7rzeAdjXhc7QfXKSUzwW1Wq8FpJAB6ZT/GQkIbvJBMuNA33fRKml839N7I kj8xerEdEETVWepH0A+NUni0QHeCHJX7bbJ30= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=jVB9ateUNPWjDSRVGMb+4rgbxEOqdavmk19dJVvZMIM=; b=QY8ORZWU398r2di9K9w9pV9K6AOZRL0myD5tRhn7HyTebBQOayXtLnD344/h/h355e 41LfzbiO1lMit9mghTQhHcdiP10VORFuGtojYWJioQMcExqnxfBjdfi12PEyUwT+R/3Q SWuly2bUBQePQ/wgVjWLE5HuFlSymICeHam/9fccKltRBJmaFC/Ol44X1yiHbLmBmZVE zNH+CSAJRZIZyjMHK3KtL2gi43mxnQT33IrLPvJB98fbtZQOYv+oaWFRmy6xe3SwGHcd 07nIY11zIf4zv9DNFXjm9aThze4YNXxg85M7r6tfj/DX6x4FGQIQ8noS+5HbB9EaFYMH G82A== X-Gm-Message-State: ANhLgQ01mzB07p/Frlm7V8XekADANJX02vZV/TiZXWP1ZznrCJCjuHd0 a82cEX9ZeMpKB/XvSaUKQwxn3A== X-Google-Smtp-Source: ADFU+vtTCjEhI3JPw2xL9W4cakF1N6Pmv6rkqFP+mzP01zBwJjNzf9RYvvo4VRKg6V5rIt4yJLfXMA== X-Received: by 2002:aa7:87c1:: with SMTP id i1mr1082817pfo.297.1583961458705; Wed, 11 Mar 2020 14:17:38 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id y200sm19036662pfb.138.2020.03.11.14.17.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Mar 2020 14:17:37 -0700 (PDT) From: Kees Cook To: Shuah Khan Cc: Kees Cook , Andy Lutomirski , Will Drewry , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/2] selftests/harness: Handle timeouts cleanly Date: Wed, 11 Mar 2020 14:17:33 -0700 Message-Id: <20200311211733.21211-3-keescook@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200311211733.21211-1-keescook@chromium.org> References: <20200311211733.21211-1-keescook@chromium.org> MIME-Version: 1.0 Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org When a selftest would timeout before, the program would just fall over and no accounting of failures would be reported (i.e. it would result in an incomplete TAP report). Instead, add an explicit SIGALRM handler to cleanly catch and report the timeout. Before: [==========] Running 2 tests from 2 test cases. [ RUN ] timeout.finish [ OK ] timeout.finish [ RUN ] timeout.too_long Alarm clock After: [==========] Running 2 tests from 2 test cases. [ RUN ] timeout.finish [ OK ] timeout.finish [ RUN ] timeout.too_long timeout.too_long: Test terminated by timeout [ FAIL ] timeout.too_long [==========] 1 / 2 tests passed. [ FAILED ] Signed-off-by: Kees Cook --- tools/testing/selftests/kselftest_harness.h | 53 ++++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index c7b67e379219..2902f6a78f8a 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -639,7 +639,8 @@ struct __test_metadata { int termsig; int passed; int trigger; /* extra handler after the evaluation */ - int timeout; + int timeout; /* seconds to wait for test timeout */ + bool timed_out; /* did this test timeout instead of exiting? */ __u8 step; bool no_print; /* manual trigger when TH_LOG_STREAM is not available */ struct __test_metadata *prev, *next; @@ -696,15 +697,63 @@ static inline int __bail(int for_realz, bool no_print, __u8 step) return 0; } +struct __test_metadata *__active_test; +static void __timeout_handler(int sig, siginfo_t *info, void *ucontext) +{ + struct __test_metadata *t = __active_test; + + /* Sanity check handler execution environment. */ + if (!t) { + fprintf(TH_LOG_STREAM, + "no active test in SIGARLM handler!?\n"); + abort(); + } + if (sig != SIGALRM || sig != info->si_signo) { + fprintf(TH_LOG_STREAM, + "%s: SIGALRM handler caught signal %d!?\n", + t->name, sig != SIGALRM ? sig : info->si_signo); + abort(); + } + + t->timed_out = true; + kill(t->pid, SIGKILL); +} + void __wait_for_test(struct __test_metadata *t) { + struct sigaction action = { + .sa_sigaction = __timeout_handler, + .sa_flags = SA_SIGINFO, + }; + struct sigaction saved_action; int status; + if (sigaction(SIGALRM, &action, &saved_action)) { + t->passed = 0; + fprintf(TH_LOG_STREAM, + "%s: unable to install SIGARLM handler\n", + t->name); + return; + } + __active_test = t; + t->timed_out = false; alarm(t->timeout); waitpid(t->pid, &status, 0); alarm(0); + if (sigaction(SIGALRM, &saved_action, NULL)) { + t->passed = 0; + fprintf(TH_LOG_STREAM, + "%s: unable to uninstall SIGARLM handler\n", + t->name); + return; + } + __active_test = NULL; - if (WIFEXITED(status)) { + if (t->timed_out) { + t->passed = 0; + fprintf(TH_LOG_STREAM, + "%s: Test terminated by timeout\n", t->name); + } else if (WIFEXITED(status)) { t->passed = t->termsig == -1 ? !WEXITSTATUS(status) : 0; if (t->termsig != -1) { fprintf(TH_LOG_STREAM,