From 4d13e4dcbb50aef894dd050ac6f383223cf916f0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 02:00:55 +0900 Subject: [PATCH 01/10] resolved: use usec_add() at one more place Follow-up for 8458b7fb91ea5e5109b6f3c94f8a781a120c798b. Fixes CID#1612580. --- src/resolve/resolved-dns-browse-services.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolved-dns-browse-services.c b/src/resolve/resolved-dns-browse-services.c index 0401dfb754..b2ecc4c3d4 100644 --- a/src/resolve/resolved-dns-browse-services.c +++ b/src/resolve/resolved-dns-browse-services.c @@ -198,7 +198,7 @@ int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_ /* If next_time is still in the past, the service is being added * after it has already expired. Just schedule a 100% * maintenance query. */ - next_time = usec + USEC_PER_SEC; + next_time = usec_add(usec, USEC_PER_SEC); s->rr_ttl_state = DNS_RECORD_TTL_STATE_100_PERCENT; } From 1f4e9f6d605f9cee7ef43373cd307ffb1445e562 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 02:06:45 +0900 Subject: [PATCH 02/10] core/exec-invoke: check size of read size Even though we do not use the read data, it is better to check the size to prevent something spurious going. Fixes CID#1612155. --- src/core/exec-invoke.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index dbac295824..56facd94c3 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -2244,8 +2244,11 @@ static int setup_private_users_child(int unshare_ready_fd, const char *uid_map, /* Wait until the parent unshared the user namespace */ uint64_t c; - if (read(unshare_ready_fd, &c, sizeof(c)) < 0) + ssize_t n = read(unshare_ready_fd, &c, sizeof(c)); + if (n < 0) return log_debug_errno(errno, "Failed to read from signaling eventfd: %m"); + if (n != sizeof(c)) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Short read from signaling eventfd."); /* Disable the setgroups() system call in the child user namespace, for good, unless PrivateUsers=full * and using the system service manager. */ From 04a99c48d24e297561076051695043f36eec2dae Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 02:15:56 +0900 Subject: [PATCH 03/10] cpu-set-util: fix identical ternary expression Follow-up for fe3ada076ea8799a4d75f2e63adf540992d6fbb2. Fixes CID#1611792. --- src/shared/cpu-set-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/cpu-set-util.c b/src/shared/cpu-set-util.c index c5277f11af..cef23889ca 100644 --- a/src/shared/cpu-set-util.c +++ b/src/shared/cpu-set-util.c @@ -222,7 +222,7 @@ int config_parse_cpu_set( void *userdata) { CPUSet *c = ASSERT_PTR(data); - int r, level = ltype ? LOG_DEBUG : LOG_DEBUG; + int r, level = ltype ? LOG_DEBUG : LOG_ERR; bool critical = ltype; assert(critical || lvalue); From d54f1e4329aa2b80107383f99253f5f3df9f1f84 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 02:23:52 +0900 Subject: [PATCH 04/10] cpu-set-util: check if cpu set is already allocated Prompted by CID#1611789, CID#1611790, and CID#1611791. --- src/shared/cpu-set-util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shared/cpu-set-util.c b/src/shared/cpu-set-util.c index cef23889ca..222e4b7e17 100644 --- a/src/shared/cpu-set-util.c +++ b/src/shared/cpu-set-util.c @@ -133,8 +133,10 @@ int cpu_set_realloc(CPUSet *c, size_t n) { return -ERANGE; n = CPU_ALLOC_SIZE(n); - if (n <= c->allocated) + if (n <= c->allocated) { + assert(c->set || n == 0); return 0; + } if (!GREEDY_REALLOC0(c->set, DIV_ROUND_UP(n, sizeof(cpu_set_t)))) return -ENOMEM; From 6ce3b1fa331f7c3e44354fe56a0ed92c33e54776 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 02:31:37 +0900 Subject: [PATCH 05/10] test: add explicit test cases for cpu_set_add() and cpu_set_add_range() cpu_set_add_range() is used in parse_cpu_set(), hence already tested. But it is better to test these functions explicitly. For CID#1611787 and CID#1611788, that should be false-positive. --- src/shared/cpu-set-util.c | 2 +- src/shared/cpu-set-util.h | 1 + src/test/test-cpu-set-util.c | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/shared/cpu-set-util.c b/src/shared/cpu-set-util.c index 222e4b7e17..7a155c12d4 100644 --- a/src/shared/cpu-set-util.c +++ b/src/shared/cpu-set-util.c @@ -179,7 +179,7 @@ int cpu_set_add_set(CPUSet *c, const CPUSet *src) { return 1; } -static int cpu_set_add_range(CPUSet *c, size_t start, size_t end) { +int cpu_set_add_range(CPUSet *c, size_t start, size_t end) { int r; assert(c); diff --git a/src/shared/cpu-set-util.h b/src/shared/cpu-set-util.h index 84a21809ca..29582d5409 100644 --- a/src/shared/cpu-set-util.h +++ b/src/shared/cpu-set-util.h @@ -24,6 +24,7 @@ void cpu_set_done(CPUSet *c); int cpu_set_realloc(CPUSet *c, size_t n); int cpu_set_add(CPUSet *c, size_t i); int cpu_set_add_set(CPUSet *c, const CPUSet *src); +int cpu_set_add_range(CPUSet *c, size_t start, size_t end); int cpu_set_add_all(CPUSet *c); char* cpu_set_to_string(const CPUSet *c); diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c index 6fc0ea0f49..eff6460610 100644 --- a/src/test/test-cpu-set-util.c +++ b/src/test/test-cpu-set-util.c @@ -262,4 +262,25 @@ TEST(print_cpu_alloc_size) { log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191)); } +TEST(cpu_set_add) { + _cleanup_(cpu_set_done) CPUSet c = {}; + + for (size_t i = 0; i < 8192; i++) + ASSERT_OK(cpu_set_add(&c, 8191)); + + ASSERT_ERROR(cpu_set_add(&c, 8192), ERANGE); + ASSERT_ERROR(cpu_set_add(&c, SIZE_MAX), ERANGE); +} + +TEST(cpu_set_add_range) { + _cleanup_(cpu_set_done) CPUSet c = {}; + + ASSERT_ERROR(cpu_set_add_range(&c, 0, 8192), ERANGE); + ASSERT_ERROR(cpu_set_add_range(&c, 0, SIZE_MAX), ERANGE); + ASSERT_SIGNAL(cpu_set_add_range(&c, 100, 0), SIGABRT); + + ASSERT_OK(cpu_set_add_range(&c, 0, 0)); + ASSERT_OK(cpu_set_add_range(&c, 0, 8191)); +} + DEFINE_TEST_MAIN(LOG_DEBUG); From 2c3b3e2fd9f7481ac59050ac39a93b5f0641ea4f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 02:58:01 +0900 Subject: [PATCH 06/10] ordered-set: avoid overflow Previously, ordered_set_put_strdupv() and friends returns the number of pushed entries, but that is potentially larger than INT_MAX (of course, realistically, OOM is triggered in that case). No caller uses the number of the new entries. Let's return 1 when at least one element is added. Fixes CID#1611523. --- src/basic/ordered-set.c | 12 ++++++------ src/test/test-ordered-set.c | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c index 4d2c43cf36..09fdc3dfce 100644 --- a/src/basic/ordered-set.c +++ b/src/basic/ordered-set.c @@ -61,7 +61,7 @@ int ordered_set_put_strdup_full(OrderedSet **s, const struct hash_ops *hash_ops, } int ordered_set_put_strdupv_full(OrderedSet **s, const struct hash_ops *hash_ops, char **l) { - int n = 0, r; + int r, ret = 0; assert(s); @@ -70,14 +70,14 @@ int ordered_set_put_strdupv_full(OrderedSet **s, const struct hash_ops *hash_ops if (r < 0) return r; - n += r; + ret = ret || r > 0; } - return n; + return ret; } int ordered_set_put_string_set_full(OrderedSet **s, const struct hash_ops *hash_ops, OrderedSet *l) { - int n = 0, r; + int r, ret = 0; char *p; assert(s); @@ -89,10 +89,10 @@ int ordered_set_put_string_set_full(OrderedSet **s, const struct hash_ops *hash_ if (r < 0) return r; - n += r; + ret = ret || r > 0; } - return n; + return ret; } void ordered_set_print(FILE *f, const char *field, OrderedSet *s) { diff --git a/src/test/test-ordered-set.c b/src/test/test-ordered-set.c index 7125dab2c2..a5cde0171a 100644 --- a/src/test/test-ordered-set.c +++ b/src/test/test-ordered-set.c @@ -90,18 +90,19 @@ TEST(set_put_string_set) { _cleanup_ordered_set_free_ OrderedSet *m = NULL, *q = NULL; _cleanup_free_ char **final = NULL; /* "just free" because the strings are in the set */ - assert_se(ordered_set_put_strdup(&m, "1") == 1); - assert_se(ordered_set_put_strdup(&m, "22") == 1); - assert_se(ordered_set_put_strdup(&m, "333") == 1); + ASSERT_OK_POSITIVE(ordered_set_put_strdup(&m, "1")); + ASSERT_OK_POSITIVE(ordered_set_put_strdup(&m, "22")); + ASSERT_OK_POSITIVE(ordered_set_put_strdup(&m, "333")); - assert_se(ordered_set_put_strdup(&q, "11") == 1); - assert_se(ordered_set_put_strdup(&q, "22") == 1); - assert_se(ordered_set_put_strdup(&q, "33") == 1); + ASSERT_OK_POSITIVE(ordered_set_put_strdup(&q, "11")); + ASSERT_OK_POSITIVE(ordered_set_put_strdup(&q, "22")); + ASSERT_OK_POSITIVE(ordered_set_put_strdup(&q, "33")); - assert_se(ordered_set_put_string_set(&m, q) == 2); + ASSERT_OK_POSITIVE(ordered_set_put_string_set(&m, q)); + ASSERT_OK_ZERO(ordered_set_put_string_set(&m, q)); - assert_se(final = ordered_set_get_strv(m)); - assert_se(strv_equal(final, STRV_MAKE("1", "22", "333", "11", "33"))); + ASSERT_NOT_NULL(final = ordered_set_get_strv(m)); + ASSERT_TRUE(strv_equal(final, STRV_MAKE("1", "22", "333", "11", "33"))); ordered_set_print(stdout, "BAR=", m); } From fa43d54b55839d2b37d99b9bbec57ae372fcc6c9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 03:02:50 +0900 Subject: [PATCH 07/10] delta: add missing error check Follow-up for 59829bb37a44a01c4394301fd65478037e6b01d8. Fixes CID#1611425. --- src/delta/delta.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/delta/delta.c b/src/delta/delta.c index 694f3f1fe6..d13516e310 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -286,6 +286,8 @@ static int enumerate_dir_d( log_debug("Adding to drops: %s %s %s %s %s/%s", unit, glyph(GLYPH_ARROW_RIGHT), *file, glyph(GLYPH_ARROW_RIGHT), path, *file); r = path_put(&h, path, *file, /* override = */ false); + if (r < 0) + return r; } return 0; } From 635894a49338e0ca885395b983f63653722be6b6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 03:05:20 +0900 Subject: [PATCH 08/10] fuzz-efi-string: add missing OOM check Fixes CID#1610113 and CID#1610114. --- src/boot/fuzz-efi-string.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/boot/fuzz-efi-string.c b/src/boot/fuzz-efi-string.c index 2b854b3782..ae19216f40 100644 --- a/src/boot/fuzz-efi-string.c +++ b/src/boot/fuzz-efi-string.c @@ -31,10 +31,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { DO_NOT_OPTIMIZE(parse_number8(str8, &(uint64_t){ 0 }, size % 2 == 0 ? NULL : &tail8)); const char16_t *tail16 = NULL; - _cleanup_free_ char16_t *str16 = memdup_str16(data, size); + _cleanup_free_ char16_t *str16 = ASSERT_SE_PTR(memdup_str16(data, size)); DO_NOT_OPTIMIZE(parse_number16(str16, &(uint64_t){ 0 }, size % 2 == 0 ? NULL : &tail16)); - _cleanup_free_ char16_t *pattern = memdup_str16(data, len), *haystack = memdup_str16(data + len, len2); + _cleanup_free_ char16_t + *pattern = ASSERT_SE_PTR(memdup_str16(data, len)), + *haystack = ASSERT_SE_PTR(memdup_str16(data + len, len2)); DO_NOT_OPTIMIZE(efi_fnmatch(pattern, haystack)); return 0; From c119eb0edcc422a2908dd2e6c5d678019f070dbd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 03:24:51 +0900 Subject: [PATCH 09/10] install: skip later first_word() calls if one of earlier calls passes Prompted by CID#1587764, that is false-positive. --- src/shared/install.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/shared/install.c b/src/shared/install.c index 8fc087fb78..3522af67ec 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -3350,8 +3350,7 @@ static int read_presets(RuntimeScope scope, const char *root_dir, UnitFilePreset if (strchr(COMMENTS, line[0])) continue; - parameter = first_word(line, "enable"); - if (parameter) { + if ((parameter = first_word(line, "enable"))) { char *unit_name; char **instances = NULL; @@ -3367,10 +3366,8 @@ static int read_presets(RuntimeScope scope, const char *root_dir, UnitFilePreset .action = PRESET_ENABLE, .instances = instances, }; - } - parameter = first_word(line, "disable"); - if (parameter) { + } else if ((parameter = first_word(line, "disable"))) { char *pattern; pattern = strdup(parameter); @@ -3381,10 +3378,8 @@ static int read_presets(RuntimeScope scope, const char *root_dir, UnitFilePreset .pattern = pattern, .action = PRESET_DISABLE, }; - } - parameter = first_word(line, "ignore"); - if (parameter) { + } else if ((parameter = first_word(line, "ignore"))) { char *pattern; pattern = strdup(parameter); @@ -3397,7 +3392,7 @@ static int read_presets(RuntimeScope scope, const char *root_dir, UnitFilePreset }; } - if (rule.action) { + if (rule.action != 0) { if (!GREEDY_REALLOC(ps.rules, ps.n_rules + 1)) return -ENOMEM; From 08cf7c70b9e83e42f5c74eda45446b56cf2d9bcf Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Jul 2025 03:38:56 +0900 Subject: [PATCH 10/10] fs-util: avoid overflow in MODE_TO_PTR() with MODE_INVALID Note, currently MODE_TO_PTR() and PTR_TO_MODE() are only used in src/udev/udev-rules.c . Fixes CID#1548060. --- src/basic/fs-util.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index b04fe71f03..74c1411556 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -6,8 +6,12 @@ /* The following macros add 1 when converting things, since 0 is a valid mode, while the pointer * NULL is special */ -#define PTR_TO_MODE(p) ((mode_t) ((uintptr_t) (p)-1)) -#define MODE_TO_PTR(u) ((void *) ((uintptr_t) (u)+1)) +static inline mode_t PTR_TO_MODE(void *p) { + return p ? (mode_t) ((uintptr_t) p - 1) : MODE_INVALID; +} +static inline void* MODE_TO_PTR(mode_t m) { + return m == MODE_INVALID ? NULL : (void *) ((uintptr_t) m + 1); +} int rmdir_parents(const char *path, const char *stop);