Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1601633imu; Wed, 12 Dec 2018 00:37:44 -0800 (PST) X-Google-Smtp-Source: AFSGD/WEv87QgD8e+VLU4RIRnCHk6W+esAvhv36peD7UU664jYhPVrmvjlqd4PhcNxJ/q0al5Ry1 X-Received: by 2002:a62:2b8b:: with SMTP id r133mr19417509pfr.246.1544603864358; Wed, 12 Dec 2018 00:37:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1544603864; cv=none; d=google.com; s=arc-20160816; b=J0ctomC9zbFwOGPVOwapF0+BGW7tTjhZmBxnDzp9/vd1f5yNsC2G7bbgTforAmuYV9 scw8EtUnsYpLz9Z8+U+C7ZU8JDhTRA6BiptdIJI6dfCFDLxeXcgu1O2dlgO/gmU771je sJVnNDQrDo+4hlLtKJ8Necx5dsG+HBjcw3gaLSCVPOyROz5YXhDNejhz4CZc+TWSZsTA V4avjZjacimbAosrbYdaXslP4rAHnTKQXTXXs5LalHfwUIauHHSR+F+xnavRvexq2ncE YxQOoQV0QvaxyRTkLNDlbldRCEyD4ggAu7l2lMJoe+G5XvJLVCuApf40kqsjIehPPHTt BQSg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=MsDW9I5EkU7yGMazT7Ed+KSirPj16IprJvwT67M7T0Q=; b=MLVVI1r8T09wW4vnNK+Dw4+rG5ciSjVlBQRN9Yp79I3LWft6MeuGyTRVXAiunV0mdo ppCbJ58rtxL3UdGM4Ov7cOBdr7A8rAWMhyV2ZpUHFIh5vkW+DWxZfRPHU4mzshacaSEs m5GEoxXoGgsdXbp1rqPr0cinsFViqsDXLcbfItDpqCiaim9mWZN5jYPGsh3wybJtj49C wsO7BNyo/1s+JqQjWwb9koy5+8Kdc57f5PjvHT7EuocHuXAR+iG2Gzx5taoAmgHrALgi pdcImu+KTzvMU8+rKQTnjz3O1GDws1YuOCiM12GgRtlrXDI02UKxC+W0swW02LC4KV8B Mh0w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i12si13564028pgq.466.2018.12.12.00.37.25; Wed, 12 Dec 2018 00:37:44 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726800AbeLLIe4 (ORCPT + 99 others); Wed, 12 Dec 2018 03:34:56 -0500 Received: from smtp-sh.infomaniak.ch ([128.65.195.4]:40538 "EHLO smtp-sh.infomaniak.ch" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726895AbeLLIe4 (ORCPT ); Wed, 12 Dec 2018 03:34:56 -0500 Received: from smtp5.infomaniak.ch (smtp5.infomaniak.ch [83.166.132.18]) by smtp-sh.infomaniak.ch (8.14.5/8.14.5) with ESMTP id wBC8Hnvb022715 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 12 Dec 2018 09:17:49 +0100 Received: from localhost (ns3096276.ip-94-23-54.eu [94.23.54.103]) (authenticated bits=0) by smtp5.infomaniak.ch (8.14.5/8.14.5) with ESMTP id wBC8HlF8056457; Wed, 12 Dec 2018 09:17:47 +0100 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= To: linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= , Al Viro , James Morris , Jonathan Corbet , Kees Cook , Matthew Garrett , Michael Kerrisk , =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= , Mimi Zohar , =?UTF-8?q?Philippe=20Tr=C3=A9buchet?= , Shuah Khan , Thibaut Sautereau , Vincent Strubel , Yves-Alexis Perez , kernel-hardening@lists.openwall.com, linux-api@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH v1 4/5] selftest/yama: Add tests for O_MAYEXEC enforcing Date: Wed, 12 Dec 2018 09:17:11 +0100 Message-Id: <20181212081712.32347-5-mic@digikod.net> X-Mailer: git-send-email 2.20.0.rc2 In-Reply-To: <20181212081712.32347-1-mic@digikod.net> References: <20181212081712.32347-1-mic@digikod.net> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Antivirus: Dr.Web (R) for Unix mail servers drweb plugin ver.6.0.2.8 X-Antivirus-Code: 0x100000 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Test propagation of noexec mount points or file executability through files open with or without O_MAYEXEC. Signed-off-by: Mickaël Salaün Cc: Kees Cook Cc: Mickaël Salaün Cc: Shuah Khan --- MAINTAINERS | 1 + tools/testing/selftests/Makefile | 1 + tools/testing/selftests/yama/.gitignore | 1 + tools/testing/selftests/yama/Makefile | 19 ++ tools/testing/selftests/yama/config | 2 + tools/testing/selftests/yama/test_omayexec.c | 276 +++++++++++++++++++ 6 files changed, 300 insertions(+) create mode 100644 tools/testing/selftests/yama/.gitignore create mode 100644 tools/testing/selftests/yama/Makefile create mode 100644 tools/testing/selftests/yama/config create mode 100644 tools/testing/selftests/yama/test_omayexec.c diff --git a/MAINTAINERS b/MAINTAINERS index 8119141a926f..a1d01a81b283 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16591,6 +16591,7 @@ M: Kees Cook T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip S: Supported F: security/yama/ +F: tools/testing/selftests/yama/ F: Documentation/admin-guide/LSM/Yama.rst YEALINK PHONE DRIVER diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index f0017c831e57..608f31167aa6 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -46,6 +46,7 @@ endif TARGETS += user TARGETS += vm TARGETS += x86 +TARGETS += yama TARGETS += zram #Please keep the TARGETS list alphabetically sorted # Run "make quicktest=1 run_tests" or diff --git a/tools/testing/selftests/yama/.gitignore b/tools/testing/selftests/yama/.gitignore new file mode 100644 index 000000000000..6e8d5cfb48d0 --- /dev/null +++ b/tools/testing/selftests/yama/.gitignore @@ -0,0 +1 @@ +/test_omayexec diff --git a/tools/testing/selftests/yama/Makefile b/tools/testing/selftests/yama/Makefile new file mode 100644 index 000000000000..d411f1615b60 --- /dev/null +++ b/tools/testing/selftests/yama/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 + +all: + +include ../lib.mk + +.PHONY: all clean + +BINARIES := test_omayexec +CFLAGS += -Wl,-no-as-needed -Wall -Werror +LDFLAGS += -lcap + +test_omayexec: test_omayexec.c ../kselftest_harness.h + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +TEST_PROGS += $(BINARIES) +EXTRA_CLEAN := $(BINARIES) + +all: $(BINARIES) diff --git a/tools/testing/selftests/yama/config b/tools/testing/selftests/yama/config new file mode 100644 index 000000000000..9d375bfc465b --- /dev/null +++ b/tools/testing/selftests/yama/config @@ -0,0 +1,2 @@ +CONFIG_SECURITY=y +CONFIG_SECURITY_YAMA=y diff --git a/tools/testing/selftests/yama/test_omayexec.c b/tools/testing/selftests/yama/test_omayexec.c new file mode 100644 index 000000000000..7d41097f0e89 --- /dev/null +++ b/tools/testing/selftests/yama/test_omayexec.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Yama tests - O_MAYEXEC + * + * Copyright © 2018 ANSSI + * + * Author: Mickaël Salaün + */ + +#include +#include /* O_CLOEXEC */ +#include +#include +#include /* strlen */ +#include +#include +#include /* mkdir */ +#include /* unlink, rmdir */ + +#include "../kselftest_harness.h" + +#ifndef O_MAYEXEC +#define O_MAYEXEC 040000000 +#endif + +#define SYSCTL_MAYEXEC "/proc/sys/kernel/yama/open_mayexec_enforce" + +#define BIN_DIR "./test-mount" +#define BIN_PATH BIN_DIR "/file" +#define DIR_PATH BIN_DIR "/directory" + +#define ALLOWED 1 +#define DENIED 0 + +static void test_omx(struct __test_metadata *_metadata, + const char *const path, const int exec_allowed) +{ + int fd; + + /* without O_MAYEXEC */ + fd = open(path, O_RDONLY | O_CLOEXEC); + ASSERT_NE(-1, fd); + EXPECT_FALSE(close(fd)); + + /* with O_MAYEXEC */ + fd = open(path, O_RDONLY | O_CLOEXEC | O_MAYEXEC); + if (exec_allowed) { + /* open should succeed */ + ASSERT_NE(-1, fd); + EXPECT_FALSE(close(fd)); + } else { + /* open should return EACCES */ + ASSERT_EQ(-1, fd); + ASSERT_EQ(EACCES, errno); + } +} + +static void ignore_dac(struct __test_metadata *_metadata, int override) +{ + cap_t caps; + const cap_value_t cap_val[2] = { + CAP_DAC_OVERRIDE, + CAP_DAC_READ_SEARCH, + }; + + caps = cap_get_proc(); + ASSERT_TRUE(!!caps); + ASSERT_FALSE(cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_val, + override ? CAP_SET : CAP_CLEAR)); + ASSERT_FALSE(cap_set_proc(caps)); + EXPECT_FALSE(cap_free(caps)); +} + +static void test_dir_file(struct __test_metadata *_metadata, + const char *const dir_path, const char *const file_path, + const int exec_allowed, const int only_file_perm) +{ + if (only_file_perm) { + /* test as root */ + ignore_dac(_metadata, 1); + /* always allowed because of generic_permission() use */ + test_omx(_metadata, dir_path, ALLOWED); + } + + /* without bypass */ + ignore_dac(_metadata, 0); + test_omx(_metadata, dir_path, exec_allowed); + test_omx(_metadata, file_path, exec_allowed); +} + +static void sysctl_write(struct __test_metadata *_metadata, + const char *path, const char *value) +{ + int fd; + size_t len_value; + ssize_t len_wrote; + + fd = open(path, O_WRONLY | O_CLOEXEC); + ASSERT_NE(-1, fd); + len_value = strlen(value); + len_wrote = write(fd, value, len_value); + ASSERT_EQ(len_wrote, len_value); + EXPECT_FALSE(close(fd)); +} + +static void create_workspace(struct __test_metadata *_metadata, + int mount_exec, int file_exec) +{ + int fd; + + /* + * Cleanup previous workspace if any error previously happened (don't + * check errors). + */ + umount(BIN_DIR); + rmdir(BIN_DIR); + + /* create a clean mount point */ + ASSERT_FALSE(mkdir(BIN_DIR, 00700)); + ASSERT_FALSE(mount("test", BIN_DIR, "tmpfs", + MS_MGC_VAL | (mount_exec ? 0 : MS_NOEXEC), + "mode=0700,size=4k")); + + /* create a test file */ + fd = open(BIN_PATH, O_CREAT | O_RDONLY | O_CLOEXEC, + file_exec ? 00500 : 00400); + ASSERT_NE(-1, fd); + EXPECT_NE(-1, close(fd)); + + /* create a test directory */ + ASSERT_FALSE(mkdir(DIR_PATH, file_exec ? 00500 : 00400)); +} + +static void delete_workspace(struct __test_metadata *_metadata) +{ + ignore_dac(_metadata, 1); + sysctl_write(_metadata, SYSCTL_MAYEXEC, "0"); + + /* no need to unlink BIN_PATH nor DIR_PATH */ + ASSERT_FALSE(umount(BIN_DIR)); + ASSERT_FALSE(rmdir(BIN_DIR)); +} + +FIXTURE_DATA(mount_exec_file_exec) { }; + +FIXTURE_SETUP(mount_exec_file_exec) +{ + create_workspace(_metadata, 1, 1); +} + +FIXTURE_TEARDOWN(mount_exec_file_exec) +{ + delete_workspace(_metadata); +} + +TEST_F(mount_exec_file_exec, mount) +{ + /* enforce mount exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "1"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED, 0); +} + +TEST_F(mount_exec_file_exec, file) +{ + /* enforce file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "2"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED, 0); +} + +TEST_F(mount_exec_file_exec, mount_file) +{ + /* enforce mount and file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "3"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED, 0); +} + +FIXTURE_DATA(mount_exec_file_noexec) { }; + +FIXTURE_SETUP(mount_exec_file_noexec) +{ + create_workspace(_metadata, 1, 0); +} + +FIXTURE_TEARDOWN(mount_exec_file_noexec) +{ + delete_workspace(_metadata); +} + +TEST_F(mount_exec_file_noexec, mount) +{ + /* enforce mount exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "1"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED, 0); +} + +TEST_F(mount_exec_file_noexec, file) +{ + /* enforce file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "2"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED, 1); +} + +TEST_F(mount_exec_file_noexec, mount_file) +{ + /* enforce mount and file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "3"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED, 1); +} + +FIXTURE_DATA(mount_noexec_file_exec) { }; + +FIXTURE_SETUP(mount_noexec_file_exec) +{ + create_workspace(_metadata, 0, 1); +} + +FIXTURE_TEARDOWN(mount_noexec_file_exec) +{ + delete_workspace(_metadata); +} + +TEST_F(mount_noexec_file_exec, mount) +{ + /* enforce mount exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "1"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED, 0); +} + +TEST_F(mount_noexec_file_exec, file) +{ + /* enforce file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "2"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, ALLOWED, 0); +} + +TEST_F(mount_noexec_file_exec, mount_file) +{ + /* enforce mount and file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "3"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED, 0); +} + +FIXTURE_DATA(mount_noexec_file_noexec) { }; + +FIXTURE_SETUP(mount_noexec_file_noexec) +{ + create_workspace(_metadata, 0, 0); +} + +FIXTURE_TEARDOWN(mount_noexec_file_noexec) +{ + delete_workspace(_metadata); +} + +TEST_F(mount_noexec_file_noexec, mount) +{ + /* enforce mount exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "1"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED, 0); +} + +TEST_F(mount_noexec_file_noexec, file) +{ + /* enforce file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "2"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED, 1); +} + +TEST_F(mount_noexec_file_noexec, mount_file) +{ + /* enforce mount and file exec check */ + sysctl_write(_metadata, SYSCTL_MAYEXEC, "3"); + test_dir_file(_metadata, DIR_PATH, BIN_PATH, DENIED, 0); +} + +TEST_HARNESS_MAIN -- 2.20.0.rc2