[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240902-extensible-structs-check_fields-v1-7-545e93ede2f2@cyphar.com>
Date: Mon, 02 Sep 2024 17:06:29 +1000
From: Aleksa Sarai <cyphar@...har.com>
To: Ingo Molnar <mingo@...hat.com>, Peter Zijlstra <peterz@...radead.org>,
Juri Lelli <juri.lelli@...hat.com>,
Vincent Guittot <vincent.guittot@...aro.org>,
Dietmar Eggemann <dietmar.eggemann@....com>,
Steven Rostedt <rostedt@...dmis.org>, Ben Segall <bsegall@...gle.com>,
Mel Gorman <mgorman@...e.de>, Valentin Schneider <vschneid@...hat.com>,
Alexander Viro <viro@...iv.linux.org.uk>,
Christian Brauner <brauner@...nel.org>, Jan Kara <jack@...e.cz>,
Arnd Bergmann <arnd@...db.de>, Shuah Khan <shuah@...nel.org>
Cc: Kees Cook <kees@...nel.org>, Florian Weimer <fweimer@...hat.com>,
Arnd Bergmann <arnd@...db.de>, Mark Rutland <mark.rutland@....com>,
linux-kernel@...r.kernel.org, linux-api@...r.kernel.org,
linux-fsdevel@...r.kernel.org, linux-arch@...r.kernel.org,
linux-kselftest@...r.kernel.org, Aleksa Sarai <cyphar@...har.com>
Subject: [PATCH RFC 7/8] selftests: openat2: add CHECK_FIELDS selftests
Signed-off-by: Aleksa Sarai <cyphar@...har.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@...har.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
Powered by blists - more mailing lists