From e7713316f9d14ae05ef322da1e549005d3841e26 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 8 Jan 2024 09:12:33 +0100 Subject: [PATCH] common: Mark our memfds as non-executable We only ever use them to store data. Recent Linux kernels now encourage explicitly declaring whether a memfd is supposed to be executable [1]. This avoids an unsightly warning at boot: > login: [ 85.637785] cockpit-tls[1176]: memfd_create() called without MFD_EXEC or MFD_NOEXEC_SEAL set Older kernel releases don't know about that flag yet. Add build-time and runtime fallbacks. [1] https://lwn.net/Articles/918106/ --- src/common/cockpitjsonprint.c | 11 ++++++++++- src/common/test-jsonfds.c | 26 ++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/common/cockpitjsonprint.c b/src/common/cockpitjsonprint.c index f55492f2d0a3..de10908b4943 100644 --- a/src/common/cockpitjsonprint.c +++ b/src/common/cockpitjsonprint.c @@ -28,6 +28,11 @@ #include #include +/* no-op fallback for old kernels */ +#ifndef MFD_NOEXEC_SEAL +#define MFD_NOEXEC_SEAL 0 +#endif + static bool char_needs_json_escape (unsigned char c) { @@ -183,7 +188,11 @@ FILE * cockpit_json_print_open_memfd (const char *name, int version) { - int fd = memfd_create ("cockpit login messages", MFD_ALLOW_SEALING | MFD_CLOEXEC); + /* current kernels moan about not specifying exec mode */ + int fd = memfd_create ("cockpit login messages", MFD_ALLOW_SEALING | MFD_CLOEXEC | MFD_NOEXEC_SEAL); + /* fallback for older kernels */ + if (fd == -1 && errno == EINVAL) + fd = memfd_create ("cockpit login messages", MFD_ALLOW_SEALING | MFD_CLOEXEC); assert (fd != -1); FILE *stream = fdopen (fd, "w"); diff --git a/src/common/test-jsonfds.c b/src/common/test-jsonfds.c index 6d209ca9b0b5..8d58f390ae1b 100644 --- a/src/common/test-jsonfds.c +++ b/src/common/test-jsonfds.c @@ -52,6 +52,24 @@ typedef struct char *inaccessible; } TestFixture; +/* no-op fallback for old kernels */ +#ifndef MFD_NOEXEC_SEAL +#define MFD_NOEXEC_SEAL 0 +#endif + +static int +memfd_create_noexec (const char *name, + unsigned int flags) +{ + int fd; + + /* current kernels moan about not specifying exec mode */ + fd = memfd_create (name, flags | MFD_NOEXEC_SEAL); + if (fd == -1 && errno == EINVAL) + fd = memfd_create (name, flags); + return fd; +} + static void test_fixture_setup (TestFixture *fixture, gconstpointer user_data) @@ -428,7 +446,7 @@ test_memfd_error_cases (void) /* memfd is not properly sealed */ - fd = memfd_create ("xyz", MFD_CLOEXEC); + fd = memfd_create_noexec ("xyz", MFD_CLOEXEC); content = cockpit_memfd_read (fd, &error); cockpit_assert_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "*incorrect seals set*"); @@ -437,7 +455,7 @@ test_memfd_error_cases (void) close (fd); /* memfd is empty */ - fd = memfd_create ("xyz", MFD_ALLOW_SEALING | MFD_CLOEXEC); + fd = memfd_create_noexec ("xyz", MFD_ALLOW_SEALING | MFD_CLOEXEC); r = fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); g_assert (r == 0); @@ -533,7 +551,7 @@ test_memfd_json_error_cases (void) gint r; /* invalid json */ - fd = memfd_create ("xyz", MFD_CLOEXEC | MFD_ALLOW_SEALING); + fd = memfd_create_noexec ("xyz", MFD_CLOEXEC | MFD_ALLOW_SEALING); g_assert_cmpint (write (fd, "beh", 3), ==, 3); r = fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); g_assert (r == 0); @@ -544,7 +562,7 @@ test_memfd_json_error_cases (void) close (fd); /* valid json, but not an object */ - fd = memfd_create ("xyz", MFD_CLOEXEC | MFD_ALLOW_SEALING); + fd = memfd_create_noexec ("xyz", MFD_CLOEXEC | MFD_ALLOW_SEALING); g_assert_cmpint (write (fd, "[]", 2), ==, 2); r = fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); g_assert (r == 0);