From 0b2432438cbdfb884d94ab4da7eb9b9a44b4d483 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Mar 2026 21:38:08 +0100 Subject: [PATCH 1/7] core: Only build selinux-setup if we have selinux --- src/core/meson.build | 5 ++++- src/core/selinux-setup.c | 6 ++---- src/core/selinux-setup.h | 6 ++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/core/meson.build b/src/core/meson.build index e703cc3728..391dc45a6b 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -170,11 +170,14 @@ systemd_sources = files( 'apparmor-setup.c', 'ima-setup.c', 'ipe-setup.c', - 'selinux-setup.c', 'smack-setup.c', 'efi-random.c', ) +if conf.get('HAVE_SELINUX') == 1 + systemd_sources += files('selinux-setup.c') +endif + systemd_executor_sources = files( 'executor.c', 'exec-invoke.c', diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index 6f78346036..17905de2c7 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -13,11 +13,10 @@ #include "time-util.h" int mac_selinux_setup(bool *loaded_policy) { - assert(loaded_policy); - -#if HAVE_SELINUX int r; + assert(loaded_policy); + r = dlopen_libselinux(); if (r < 0) { log_debug_errno(r, "No SELinux library available, skipping setup."); @@ -92,7 +91,6 @@ int mac_selinux_setup(bool *loaded_policy) { } else log_debug("Unable to load SELinux policy. Ignoring."); } -#endif return 0; } diff --git a/src/core/selinux-setup.h b/src/core/selinux-setup.h index 3dad97bbf6..dd961b0370 100644 --- a/src/core/selinux-setup.h +++ b/src/core/selinux-setup.h @@ -3,4 +3,10 @@ #include "core-forward.h" +#if HAVE_SELINUX int mac_selinux_setup(bool *loaded_policy); +#else +static inline int mac_selinux_setup(bool *loaded_policy) { + return 0; +} +#endif From 5ae78f0ca92a0843bf67616c2e7d6c6c8f4818d7 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Mar 2026 21:38:27 +0100 Subject: [PATCH 2/7] selinux-util: Make clang-tidy happy if selinux is not available Most of our libraries are available on all distributions so we don't bother with making clang-tidy happy if the library is not available. The one exception is selinux which isn't available on Arch. Let's conditionalize the includes in selinux-util.c so that clang-tidy is still happy on Arch where we can't install libselinux. --- src/shared/selinux-util.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c index f980ec83ac..1049044f87 100644 --- a/src/shared/selinux-util.c +++ b/src/shared/selinux-util.c @@ -1,32 +1,34 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include -#include #include #include -#include #include #if HAVE_SELINUX +#include +#include +#include + #include #include #include #include -#endif #include "sd-dlopen.h" #include "alloc-util.h" -#include "errno-util.h" #include "fd-util.h" #include "label.h" -#include "label-util.h" #include "log.h" #include "path-util.h" -#include "selinux-util.h" #include "string-util.h" #include "time-util.h" +#endif + +#include "errno-util.h" +#include "label-util.h" +#include "selinux-util.h" #if HAVE_SELINUX DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(context_t, sym_context_free, context_freep, NULL); From 52277670215227271297c0cbca5b847416cfb819 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Mar 2026 21:50:10 +0100 Subject: [PATCH 3/7] core: Add two more IWYU pragmas If selinux isn't enabled, these are reported as unused, so let's add pragmas to tell clang-tidy to keep these. --- src/core/dbus.c | 2 +- src/core/load-fragment.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/dbus.c b/src/core/dbus.c index 30d265ec6c..f5a117d2bd 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -39,7 +39,7 @@ #include "path-util.h" #include "pidref.h" #include "process-util.h" -#include "selinux-access.h" +#include "selinux-access.h" /* IWYU pragma: keep */ #include "serialize.h" #include "set.h" #include "special.h" diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d1f74a8fd7..cef01ab776 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -57,7 +57,7 @@ #include "reboot-util.h" #include "seccomp-util.h" #include "securebits-util.h" -#include "selinux-util.h" +#include "selinux-util.h" /* IWYU pragma: keep */ #include "set.h" #include "show-status.h" #include "signal-util.h" From 09bee40212006fab0b85a5ff2382194d3d802d3a Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Mar 2026 21:52:00 +0100 Subject: [PATCH 4/7] reboot-util: Make clang-tidy happy if xenctrl is not installed xenctrl is another library that's not widely available across distributions. Let's make sure clang-tidy is happy with reboot-util.c if it is not available. --- src/shared/reboot-util.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/shared/reboot-util.c b/src/shared/reboot-util.c index 948e15631d..55ec6c0f0a 100644 --- a/src/shared/reboot-util.c +++ b/src/shared/reboot-util.c @@ -1,21 +1,23 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include -#include #include #include #if HAVE_XENCTRL +#include +#include + #define __XEN_INTERFACE_VERSION__ 0x00040900 #include #include #include + +#include "errno-util.h" +#include "fd-util.h" #endif #include "alloc-util.h" -#include "errno-util.h" -#include "fd-util.h" #include "fileio.h" #include "log.h" #include "proc-cmdline.h" From ea733800bd64266ae5e9b1f49cce529a239602ec Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Mar 2026 22:05:08 +0100 Subject: [PATCH 5/7] test-resolved-stream: Use accept4() instead of accept() --- src/resolve/test-resolved-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/test-resolved-stream.c b/src/resolve/test-resolved-stream.c index 9e6e7bc050..75c2868285 100644 --- a/src/resolve/test-resolved-stream.c +++ b/src/resolve/test-resolved-stream.c @@ -111,7 +111,7 @@ static void *tcp_dns_server(void *p) { assert_se(setsockopt(bindfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) >= 0); assert_se(bind(bindfd, &server_address.sa, sockaddr_len(&server_address)) >= 0); assert_se(listen(bindfd, 1) >= 0); - assert_se((acceptfd = accept(bindfd, NULL, NULL)) >= 0); + assert_se((acceptfd = accept4(bindfd, NULL, NULL, SOCK_CLOEXEC)) >= 0); server_handle(acceptfd); return NULL; } From 84d51e252db0390b448930cfab49d47ec989d8ef Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Mar 2026 22:11:15 +0100 Subject: [PATCH 6/7] test-fd-util: Replace dup() with fcntl() Last remaining use of dup() in the codebase, let's get rid of it. --- src/test/test-fd-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c index e99d7d0472..338bbc29d0 100644 --- a/src/test/test-fd-util.c +++ b/src/test/test-fd-util.c @@ -151,7 +151,7 @@ TEST(fd_move_above_stdio) { new_fd = fd_move_above_stdio(new_fd); assert_se(new_fd >= 3); - assert_se(dup(original_stdin) == 0); + assert_se(fcntl(original_stdin, F_DUPFD, 0) == 0); assert_se(close_nointr(original_stdin) != EBADF); assert_se(close_nointr(new_fd) != EBADF); } From e6f1d9a5e5eb892aab8f40b1ed0c2825cff3e5d1 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 20 Mar 2026 22:14:42 +0100 Subject: [PATCH 7/7] ci: Replace codeql PotentiallyDangerousFunction query with clang-tidy The strerror() calls in test-errno-util.c are intentional so silence clang-tidy there. --- .clang-tidy | 18 +++++ .../PotentiallyDangerousFunction.ql | 68 ------------------- src/test/test-errno-util.c | 7 +- 3 files changed, 22 insertions(+), 71 deletions(-) delete mode 100644 .github/codeql-queries/PotentiallyDangerousFunction.ql diff --git a/.clang-tidy b/.clang-tidy index 56b7e40a28..82681fda39 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -15,6 +15,7 @@ Checks: ' bugprone-suspicious-string-compare, bugprone-swapped-arguments, bugprone-tautological-type-limits, + bugprone-unsafe-functions, bugprone-unused-return-value, misc-header-include-cycle, misc-include-cleaner, @@ -50,6 +51,23 @@ CheckOptions: varlink-io\.systemd\..*; varlink-idl-common\.h; unistd\.h +' + bugprone-unsafe-functions.ReportDefaultFunctions: false + bugprone-unsafe-functions.CustomFunctions: ' + ^fgets$,read_line(),is potentially dangerous; + ^strtok$,extract_first_word(),is potentially dangerous; + ^strsep$,extract_first_word(),is potentially dangerous; + ^dup$,fcntl() with F_DUPFD_CLOEXEC,is potentially dangerous; + ^htonl$,htobe32(),is confusing; + ^htons$,htobe16(),is confusing; + ^ntohl$,be32toh(),is confusing; + ^ntohs$,be16toh(),is confusing; + ^strerror$,STRERROR() or printf %m,is not thread-safe; + ^accept$,accept4(),is not O_CLOEXEC-safe; + ^dirname$,path_extract_directory(),is icky; + ^basename$,path_extract_filename(),is icky; + ^setmntent$,libmount_parse_fstab(),libmount parser should be used instead; + ^getmntent$,mnt_table_next_fs(),libmount parser should be used instead ' misc-header-include-cycle.IgnoredFilesList: 'glib-2.0' WarningsAsErrors: '*' diff --git a/.github/codeql-queries/PotentiallyDangerousFunction.ql b/.github/codeql-queries/PotentiallyDangerousFunction.ql deleted file mode 100644 index abd3f87a34..0000000000 --- a/.github/codeql-queries/PotentiallyDangerousFunction.ql +++ /dev/null @@ -1,68 +0,0 @@ -/** - * vi: sw=2 ts=2 et syntax=ql: - * - * Borrowed from - * https://github.com/Semmle/ql/blob/master/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql - * - * @name Use of potentially dangerous function - * @description Certain standard library functions are dangerous to call. - * @id cpp/potentially-dangerous-function - * @kind problem - * @problem.severity error - * @precision high - * @tags reliability - * security - */ -import cpp - -predicate potentiallyDangerousFunction(Function f, string message) { - ( - f.getQualifiedName() = "fgets" and - message = "Call to fgets() is potentially dangerous. Use read_line() instead." - ) or ( - f.getQualifiedName() = "strtok" and - message = "Call to strtok() is potentially dangerous. Use extract_first_word() instead." - ) or ( - f.getQualifiedName() = "strsep" and - message = "Call to strsep() is potentially dangerous. Use extract_first_word() instead." - ) or ( - f.getQualifiedName() = "dup" and - message = "Call to dup() is potentially dangerous. Use fcntl(fd, FD_DUPFD_CLOEXEC, 3) instead." - ) or ( - f.getQualifiedName() = "htonl" and - message = "Call to htonl() is confusing. Use htobe32() instead." - ) or ( - f.getQualifiedName() = "htons" and - message = "Call to htons() is confusing. Use htobe16() instead." - ) or ( - f.getQualifiedName() = "ntohl" and - message = "Call to ntohl() is confusing. Use be32toh() instead." - ) or ( - f.getQualifiedName() = "ntohs" and - message = "Call to ntohs() is confusing. Use be16toh() instead." - ) or ( - f.getQualifiedName() = "strerror" and - message = "Call to strerror() is not thread-safe. Use printf()'s %m format string or STRERROR() instead." - ) or ( - f.getQualifiedName() = "accept" and - message = "Call to accept() is not O_CLOEXEC-safe. Use accept4() instead." - ) or ( - f.getQualifiedName() = "dirname" and - message = "Call dirname() is icky. Use path_extract_directory() instead." - ) or ( - f.getQualifiedName() = "basename" and - message = "Call basename() is icky. Use path_extract_filename() instead." - ) or ( - f.getQualifiedName() = "setmntent" and - message = "Libmount parser is used instead, specifically libmount_parse_fstab()." - ) or ( - f.getQualifiedName() = "getmntent" and - message = "Libmount parser is used instead, specifically mnt_table_next_fs()." - ) -} - -from FunctionCall call, Function target, string message -where - call.getTarget() = target and - potentiallyDangerousFunction(target, message) -select call, message diff --git a/src/test/test-errno-util.c b/src/test/test-errno-util.c index 9eb729c2e4..30a47cbcde 100644 --- a/src/test/test-errno-util.c +++ b/src/test/test-errno-util.c @@ -6,10 +6,11 @@ TEST(strerror_not_threadsafe) { /* Just check that strerror really is not thread-safe. */ - log_info("strerror(%d) → %s", 200, strerror(200)); - log_info("strerror(%d) → %s", 201, strerror(201)); - log_info("strerror(%d) → %s", INT_MAX, strerror(INT_MAX)); + log_info("strerror(%d) → %s", 200, strerror(200)); /* NOLINT(bugprone-unsafe-functions) */ + log_info("strerror(%d) → %s", 201, strerror(201)); /* NOLINT(bugprone-unsafe-functions) */ + log_info("strerror(%d) → %s", INT_MAX, strerror(INT_MAX)); /* NOLINT(bugprone-unsafe-functions) */ + /* NOLINTNEXTLINE(bugprone-unsafe-functions) */ log_info("strerror(%d), strerror(%d) → %p, %p", 200, 201, strerror(200), strerror(201)); /* This call is not allowed, because the first returned string becomes invalid when