linux-api.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Aleksa Sarai <cyphar@cyphar.com>
To: Ingo Molnar <mingo@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>,
	 Juri Lelli <juri.lelli@redhat.com>,
	 Vincent Guittot <vincent.guittot@linaro.org>,
	 Dietmar Eggemann <dietmar.eggemann@arm.com>,
	 Steven Rostedt <rostedt@goodmis.org>,
	Ben Segall <bsegall@google.com>,  Mel Gorman <mgorman@suse.de>,
	Valentin Schneider <vschneid@redhat.com>,
	 Alexander Viro <viro@zeniv.linux.org.uk>,
	 Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
	 Arnd Bergmann <arnd@arndb.de>, Shuah Khan <shuah@kernel.org>
Cc: Kees Cook <kees@kernel.org>, Florian Weimer <fweimer@redhat.com>,
	 Arnd Bergmann <arnd@arndb.de>,
	Mark Rutland <mark.rutland@arm.com>,
	 linux-kernel@vger.kernel.org, linux-api@vger.kernel.org,
	 linux-fsdevel@vger.kernel.org, linux-arch@vger.kernel.org,
	 linux-kselftest@vger.kernel.org,
	Aleksa Sarai <cyphar@cyphar.com>
Subject: [PATCH RFC 7/8] selftests: openat2: add CHECK_FIELDS selftests
Date: Mon, 02 Sep 2024 17:06:29 +1000	[thread overview]
Message-ID: <20240902-extensible-structs-check_fields-v1-7-545e93ede2f2@cyphar.com> (raw)
In-Reply-To: <20240902-extensible-structs-check_fields-v1-0-545e93ede2f2@cyphar.com>

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
---
 tools/testing/selftests/openat2/openat2_test.c | 122 ++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/openat2/openat2_test.c b/tools/testing/selftests/openat2/openat2_test.c
index 4ca175a16ad6..8afb41d0958a 100644
--- a/tools/testing/selftests/openat2/openat2_test.c
+++ b/tools/testing/selftests/openat2/openat2_test.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Author: Aleksa Sarai <cyphar@cyphar.com>
- * Copyright (C) 2018-2019 SUSE LLC.
+ * Copyright (C) 2018-2024 SUSE LLC.
  */
 
 #define _GNU_SOURCE
@@ -29,6 +29,14 @@
 #define	O_LARGEFILE 0x8000
 #endif
 
+#ifndef CHECK_FIELDS
+#define CHECK_FIELDS (1ULL << 63)
+#endif
+
+#ifndef EEXTSYS_NOOP
+#define EEXTSYS_NOOP 134
+#endif
+
 struct open_how_ext {
 	struct open_how inner;
 	uint32_t extra1;
@@ -45,6 +53,114 @@ struct struct_test {
 	int err;
 };
 
+#define NUM_OPENAT2_CHECK_FIELDS_TESTS 1
+#define NUM_OPENAT2_CHECK_FIELDS_VARIATIONS 13
+
+static bool check(bool *failed, bool pred)
+{
+	*failed |= pred;
+	return pred;
+}
+
+static void test_openat2_check_fields(void)
+{
+	int misalignments[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 17, 87 };
+
+	for (int i = 0; i < ARRAY_LEN(misalignments); i++) {
+		int fd, misalign = misalignments[i];
+		bool failed = false;
+		char *fdpath = NULL;
+		void (*resultfn)(const char *msg, ...) = ksft_test_result_pass;
+
+		struct open_how_ext how_ext = {}, *how_copy = &how_ext;
+		void *copy = NULL;
+
+		if (!openat2_supported) {
+			ksft_print_msg("openat2(2) unsupported\n");
+			resultfn = ksft_test_result_skip;
+			goto skip;
+		}
+
+		if (misalign) {
+			/*
+			 * Explicitly misalign the structure copying it with
+			 * the given (mis)alignment offset. The other data is
+			 * set to zero and we verify this afterwards to make
+			 * sure CHECK_FIELDS doesn't write outside the buffer.
+			 */
+			copy = malloc(misalign*2 + sizeof(how_ext));
+			how_copy = copy + misalign;
+			memset(copy, 0x00, misalign*2 + sizeof(how_ext));
+			memcpy(how_copy, &how_ext, sizeof(how_ext));
+		}
+
+		fd = raw_openat2(AT_FDCWD, ".", how_copy, CHECK_FIELDS | sizeof(*how_copy));
+		if (check(&failed, (fd != -EEXTSYS_NOOP)))
+			ksft_print_msg("openat2(CHECK_FIELDS) returned wrong error code: %d (%s)",
+				       fd, strerror(-fd));
+		if (fd >= 0) {
+			fdpath = fdreadlink(fd);
+			close(fd);
+		}
+
+		if (failed) {
+			ksft_print_msg("openat2(CHECK_FIELDS) unexpectedly returned ");
+			if (fdpath)
+				ksft_print_msg("%d['%s']\n", fd, fdpath);
+			else
+				ksft_print_msg("%d (%s)\n", fd, strerror(-fd));
+		}
+
+		if (check(&failed, !(how_copy->inner.flags & O_PATH)))
+			ksft_print_msg("openat2(CHECK_FIELDS) returned flags is missing O_PATH (0x%.16x): 0x%.16llx\n",
+				       O_PATH, how_copy->inner.flags);
+
+		if (check(&failed, (how_copy->inner.mode != 07777)))
+			ksft_print_msg("openat2(CHECK_FIELDS) returned mode is invalid (0o%o): 0o%.4llo\n",
+				       07777, how_copy->inner.mode);
+
+		if (check(&failed, !(how_copy->inner.resolve & RESOLVE_IN_ROOT)))
+			ksft_print_msg("openat2(CHECK_FIELDS) returned resolve flags is missing RESOLVE_IN_ROOT (0x%.16x): 0x%.16llx\n",
+				       RESOLVE_IN_ROOT, how_copy->inner.resolve);
+
+		/* Verify that the buffer space outside the struct wasn't written to. */
+		if (check(&failed, how_copy->extra1 != 0))
+			ksft_print_msg("openat2(CHECK_FIELDS) touched a byte outside open_how (extra1): 0x%x\n",
+				       how_copy->extra1);
+		if (check(&failed, how_copy->extra2 != 0))
+			ksft_print_msg("openat2(CHECK_FIELDS) touched a byte outside open_how (extra2): 0x%x\n",
+				       how_copy->extra2);
+		if (check(&failed, how_copy->extra3 != 0))
+			ksft_print_msg("openat2(CHECK_FIELDS) touched a byte outside open_how (extra3): 0x%x\n",
+				       how_copy->extra3);
+
+		if (misalign) {
+			for (size_t i = 0; i < misalign; i++) {
+				char *p = copy + i;
+				if (check(&failed, *p != '\x00'))
+					ksft_print_msg("openat2(CHECK_FIELDS) touched a byte outside the size: buffer[%ld] = 0x%.2x\n",
+						       p - (char *) copy, *p);
+			}
+			for (size_t i = 0; i < misalign; i++) {
+				char *p = copy + misalign + sizeof(how_ext) + i;
+				if (check(&failed, *p != '\x00'))
+					ksft_print_msg("openat2(CHECK_FIELDS) touched a byte outside the size: buffer[%ld] = 0x%.2x\n",
+						       p - (char *) copy, *p);
+			}
+		}
+
+		if (failed)
+			resultfn = ksft_test_result_fail;
+
+skip:
+		resultfn("openat2(CHECK_FIELDS) [misalign=%d]\n", misalign);
+
+		free(copy);
+		free(fdpath);
+		fflush(stdout);
+	}
+}
+
 #define NUM_OPENAT2_STRUCT_TESTS 7
 #define NUM_OPENAT2_STRUCT_VARIATIONS 13
 
@@ -320,7 +436,8 @@ void test_openat2_flags(void)
 	}
 }
 
-#define NUM_TESTS (NUM_OPENAT2_STRUCT_VARIATIONS * NUM_OPENAT2_STRUCT_TESTS + \
+#define NUM_TESTS (NUM_OPENAT2_CHECK_FIELDS_TESTS * NUM_OPENAT2_CHECK_FIELDS_VARIATIONS + \
+		   NUM_OPENAT2_STRUCT_VARIATIONS * NUM_OPENAT2_STRUCT_TESTS + \
 		   NUM_OPENAT2_FLAG_TESTS)
 
 int main(int argc, char **argv)
@@ -328,6 +445,7 @@ int main(int argc, char **argv)
 	ksft_print_header();
 	ksft_set_plan(NUM_TESTS);
 
+	test_openat2_check_fields();
 	test_openat2_struct();
 	test_openat2_flags();
 

-- 
2.46.0


  parent reply	other threads:[~2024-09-02  7:08 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-02  7:06 [PATCH RFC 0/8] extensible syscalls: CHECK_FIELDS to allow for easier feature detection Aleksa Sarai
2024-09-02  7:06 ` [PATCH RFC 1/8] uaccess: add copy_struct_to_user helper Aleksa Sarai
2024-09-02  8:55   ` Arnd Bergmann
2024-09-02 16:02     ` Aleksa Sarai
2024-09-02  7:06 ` [PATCH RFC 2/8] sched_getattr: port to copy_struct_to_user Aleksa Sarai
2024-09-02  7:06 ` [PATCH RFC 3/8] openat2: explicitly return -E2BIG for (usize > PAGE_SIZE) Aleksa Sarai
2024-09-02  9:09   ` Arnd Bergmann
2024-09-02 16:08     ` Aleksa Sarai
2024-09-02 19:23       ` Arnd Bergmann
2024-09-02  7:06 ` [PATCH RFC 4/8] openat2: add CHECK_FIELDS flag to usize argument Aleksa Sarai
2024-09-02  7:06 ` [PATCH RFC 5/8] clone3: " Aleksa Sarai
2024-09-02  7:06 ` [PATCH RFC 6/8] selftests: openat2: add 0xFF poisoned data after misaligned struct Aleksa Sarai
2024-09-02  7:06 ` Aleksa Sarai [this message]
2024-09-02  7:06 ` [PATCH RFC 8/8] selftests: clone3: add CHECK_FIELDS selftests Aleksa Sarai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240902-extensible-structs-check_fields-v1-7-545e93ede2f2@cyphar.com \
    --to=cyphar@cyphar.com \
    --cc=arnd@arndb.de \
    --cc=brauner@kernel.org \
    --cc=bsegall@google.com \
    --cc=dietmar.eggemann@arm.com \
    --cc=fweimer@redhat.com \
    --cc=jack@suse.cz \
    --cc=juri.lelli@redhat.com \
    --cc=kees@kernel.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=mgorman@suse.de \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=shuah@kernel.org \
    --cc=vincent.guittot@linaro.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=vschneid@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).