Skip to content

Segfault in tmpfiles when compiled with gcc and optimisations enabled #5

Description

@wezm

Compiling with gcc (15.2.1; x86_64; Arch Linux) gives these warnings about dangling pointers in run in tmpfiles.c:

../src/tmpfiles/tmpfiles.c: In function ‘run’:
../src/tmpfiles/tmpfiles.c:5578:24: warning: dangling pointer ‘config_dirs’ to an unnamed temporary may be used [-Wdangling-pointer=]
 5578 |                 return cat_config(config_dirs, argv + optind);
      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/shared/macro.h:367:51: note: unnamed temporary defined here
  367 | #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
      |                                                   ^
../src/shared/constants.h:11:9: note: in expansion of macro ‘STRV_MAKE’
   11 |         STRV_MAKE(CONF_PATHS_USR(n))
      |         ^~~~~~~~~
../src/tmpfiles/tmpfiles.c:5553:31: note: in expansion of macro ‘CONF_PATHS_STRV’
 5553 |                 config_dirs = CONF_PATHS_STRV("tmpfiles.d");
      |                               ^~~~~~~~~~~~~~~
../src/tmpfiles/tmpfiles.c:5598:21: warning: dangling pointer ‘config_dirs’ to an unnamed temporary may be used [-Wdangling-pointer=]
 5598 |                 r = read_config_files(&c, config_dirs, argv + optind, &invalid_config);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/shared/macro.h:367:51: note: unnamed temporary defined here
  367 | #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
      |                                                   ^
../src/shared/constants.h:11:9: note: in expansion of macro ‘STRV_MAKE’
   11 |         STRV_MAKE(CONF_PATHS_USR(n))
      |         ^~~~~~~~~
../src/tmpfiles/tmpfiles.c:5553:31: note: in expansion of macro ‘CONF_PATHS_STRV’
 5553 |                 config_dirs = CONF_PATHS_STRV("tmpfiles.d");
      |                               ^~~~~~~~~~~~~~~
../src/tmpfiles/tmpfiles.c:5600:21: warning: dangling pointer ‘config_dirs’ to an unnamed temporary may be used [-Wdangling-pointer=]
 5600 |                 r = parse_arguments(&c, config_dirs, argv + optind, &invalid_config);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/shared/macro.h:367:51: note: unnamed temporary defined here
  367 | #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
      |                                                   ^
../src/shared/constants.h:11:9: note: in expansion of macro ‘STRV_MAKE’
   11 |         STRV_MAKE(CONF_PATHS_USR(n))
      |         ^~~~~~~~~
../src/tmpfiles/tmpfiles.c:5553:31: note: in expansion of macro ‘CONF_PATHS_STRV’
 5553 |                 config_dirs = CONF_PATHS_STRV("tmpfiles.d");
      |                               ^~~~~~~~~~~~~~~
../src/shared/macro.h:117:37: warning: dangling pointer ‘config_dirs’ to an unnamed temporary may be used [-Wdangling-pointer=]
  117 | #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
      |                                     ^~~~~~~~~~~~~~~~
../src/shared/string-util.h:44:32: note: in definition of macro ‘_STRV_FOREACH’
   44 |         for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++)
      |                                ^
../src/shared/macro.h:103:27: note: in expansion of macro ‘XCONCATENATE’
  103 | #define CONCATENATE(x, y) XCONCATENATE(x, y)
      |                           ^~~~~~~~~~~~
../src/shared/macro.h:117:25: note: in expansion of macro ‘CONCATENATE’
  117 | #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
      |                         ^~~~~~~~~~~
../src/shared/string-util.h:47:29: note: in expansion of macro ‘UNIQ_T’
   47 |         _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ))
      |                             ^~~~~~
../src/tmpfiles/tmpfiles.c:5563:17: note: in expansion of macro ‘STRV_FOREACH’
 5563 |                 STRV_FOREACH(i, config_dirs) {
      |                 ^~~~~~~~~~~~
../src/shared/macro.h:367:51: note: unnamed temporary defined here
  367 | #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
      |                                                   ^
../src/shared/constants.h:11:9: note: in expansion of macro ‘STRV_MAKE’
   11 |         STRV_MAKE(CONF_PATHS_USR(n))
      |         ^~~~~~~~~
../src/tmpfiles/tmpfiles.c:5553:31: note: in expansion of macro ‘CONF_PATHS_STRV’
 5553 |                 config_dirs = CONF_PATHS_STRV("tmpfiles.d");
      |                               ^~~~~~~~~~~~~~~

When building with -O1 or higher (meson setup build -Dc_args="-O1 -g") tmpfiles segfaults when run. E.g. build/src/tmpfiles/sd-tmpfiles --cat-config. Building with sanitizers (meson setup --wipe build -Dc_args="-O1 -g -fsanitize=undefined,address" -Dc_link_args="-lasan -lubsan") results in this use-after-scope error for that invocation:

==3094829==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7bc637e003a0 at pc 0x557fa5f80abc bp 0x7ffc53a21540 sp 0x7ffc53a21530
READ of size 8 at 0x7bc637e003a0 thread T0
    #0 0x557fa5f80abb in conf_files_list_strv ../src/shared/conf-files.c:110
    #1 0x557fa5f80abb in conf_files_list_with_replacement ../src/shared/conf-files.c:220
    #2 0x557fa5f6ec75 in cat_config ../src/tmpfiles/tmpfiles.c:5122
    #3 0x557fa5f6ec75 in run ../src/tmpfiles/tmpfiles.c:5578
    #4 0x557fa5f6ec75 in main ../src/tmpfiles/tmpfiles.c:5663
    #5 0x7fc63a027634  (/usr/lib/libc.so.6+0x27634) (BuildId: 9569a499070da747128b450e157301b26f5c2f9c)
    #6 0x7fc63a0276e8 in __libc_start_main (/usr/lib/libc.so.6+0x276e8) (BuildId: 9569a499070da747128b450e157301b26f5c2f9c)
    #7 0x557fa5f42ca4 in _start (/home/wmoore/Source/github.com/chimera-linux/sd-tools/build/src/tmpfiles/sd-tmpfiles+0x80ca4) (BuildId: 8f19f6c0ca3a003d7a2e732c0a8c7d84a6028e2d)

Address 0x7bc637e003a0 is located in stack of thread T0 at offset 928 in frame
    #0 0x557fa5f6cfe6 in main ../src/tmpfiles/tmpfiles.c:5657

  This frame has 29 object(s):
    [32, 33) 'invalid_config' (line 5485)
    [48, 56) 'config_dirsp' (line 5482)
    [80, 88) 'a' (line 5486)
    [112, 120) 't' (line 5561)
    [144, 152) 'j' (line 5564)
    [176, 184) 'config_dirs' (line 662)
    [208, 216) 'data_dirs' (line 662)
    [240, 248) 'persistent_config' (line 663)
    [272, 280) 'runtime_config' (line 663)
    [304, 312) 'data_home' (line 663)
    [336, 344) 'res' (line 664)
    [368, 376) 'config_dirs' (line 630)
    [400, 408) 'data_dirs' (line 630)
    [432, 440) 'ret'
    [464, 472) 'ret'
    [496, 504) 'j' (line 566)
    [528, 536) 'j' (line 591)
    [560, 568) 'files' (line 5119)
    [592, 600) 'files' (line 5417)
    [624, 632) 'p' (line 5418)
    [656, 672) 'rlim' (line 5494)
    [688, 704) 'highest' (line 5531)
    [720, 736) '__unique_prefix_i19' (line 5605)
    [752, 768) '__unique_prefix_i20' (line 5610)
    [784, 800) '__unique_prefix_i21' (line 5634)
    [816, 832) '__unique_prefix_i22' (line 5641)
    [848, 888) 'c' (line 5483)
    [928, 968) '<unknown>' <== Memory access at offset 928 is inside this variable
    [1008, 1048) '<unknown>'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope ../src/shared/conf-files.c:110 in conf_files_list_strv
Shadow bytes around the buggy address:
  0x7bc637e00100: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2
  0x7bc637e00180: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2
  0x7bc637e00200: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2
  0x7bc637e00280: f2 f2 00 00 f2 f2 00 00 f2 f2 00 00 f2 f2 00 00
  0x7bc637e00300: f2 f2 00 00 f2 f2 00 00 f2 f2 00 00 00 00 00 f2
=>0x7bc637e00380: f2 f2 f2 f2[f8]f8 f8 f8 f8 f2 f2 f2 f2 f2 00 00
  0x7bc637e00400: 00 00 00 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x7bc637e00480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7bc637e00500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7bc637e00580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7bc637e00600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==3094829==ABORTING

Replicating this with clang does not trigger the sanitizer. It does also happen with gcc 14 (14.3.1) though. Similar results are also achieved with other invocations like build/src/tmpfiles/sd-tmpfiles --create --dry-run.

AddressSanitizer: stack-use-after-scope ../src/shared/conf-files.c:110 in conf_files_list_strv
  ==3339842==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7b5c346003a0 at pc 0x55b3abeefabc bp 0x7ffdeab803b0 sp 0x7ffdeab803a0
  READ of size 8 at 0x7b5c346003a0 thread T0
      #0 0x55b3abeefabb in conf_files_list_strv ../src/shared/conf-files.c:110
      #1 0x55b3abeefabb in conf_files_list_with_replacement ../src/shared/conf-files.c:220
      #2 0x55b3abedddcf in read_config_files ../src/tmpfiles/tmpfiles.c:5423
      #3 0x55b3abedddcf in run ../src/tmpfiles/tmpfiles.c:5598
      #4 0x55b3abedddcf in main ../src/tmpfiles/tmpfiles.c:5663
      #5 0x7f5c36827634  (/usr/lib/libc.so.6+0x27634) (BuildId: 9569a499070da747128b450e157301b26f5c2f9c)
      #6 0x7f5c368276e8 in __libc_start_main (/usr/lib/libc.so.6+0x276e8) (BuildId: 9569a499070da747128b450e157301b26f5c2f9c)
      #7 0x55b3abeb1ca4 in _start (/home/wmoore/Source/github.com/chimera-linux/sd-tools/build/src/tmpfiles/sd-tmpfiles+0x80ca4) (BuildId: 8f19f6c0ca3a003d7a2e732c0a8c7d84a6028e2d)

Address 0x7b5c346003a0 is located in stack of thread T0 at offset 928 in frame
#0 0x55b3abedbfe6 in main ../src/tmpfiles/tmpfiles.c:5657

This frame has 29 object(s):
  [32, 33) 'invalid_config' (line 5485)
  [48, 56) 'config_dirsp' (line 5482)
  [80, 88) 'a' (line 5486)
  [112, 120) 't' (line 5561)
  [144, 152) 'j' (line 5564)
  [176, 184) 'config_dirs' (line 662)
  [208, 216) 'data_dirs' (line 662)
  [240, 248) 'persistent_config' (line 663)
  [272, 280) 'runtime_config' (line 663)
  [304, 312) 'data_home' (line 663)
  [336, 344) 'res' (line 664)
  [368, 376) 'config_dirs' (line 630)
  [400, 408) 'data_dirs' (line 630)
  [432, 440) 'ret'
  [464, 472) 'ret'
  [496, 504) 'j' (line 566)
  [528, 536) 'j' (line 591)
  [560, 568) 'files' (line 5119)
  [592, 600) 'files' (line 5417)
  [624, 632) 'p' (line 5418)
  [656, 672) 'rlim' (line 5494)
  [688, 704) 'highest' (line 5531)
  [720, 736) '__unique_prefix_i19' (line 5605)
  [752, 768) '__unique_prefix_i20' (line 5610)
  [784, 800) '__unique_prefix_i21' (line 5634)
  [816, 832) '__unique_prefix_i22' (line 5641)
  [848, 888) 'c' (line 5483)
  [928, 968) '<unknown>' <== Memory access at offset 928 is inside this variable
  [1008, 1048) '<unknown>'

HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions are supported)
SUMMARY: AddressSanitizer: stack-use-after-scope ../src/shared/conf-files.c:110 in conf_files_list_strv
Shadow bytes around the buggy address:
0x7b5c34600100: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2
0x7b5c34600180: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2
0x7b5c34600200: f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 00 f2
0x7b5c34600280: f2 f2 00 00 f2 f2 00 00 f2 f2 00 00 f2 f2 00 00
0x7b5c34600300: f2 f2 00 00 f2 f2 00 00 f2 f2 00 00 00 00 00 f2
=>0x7b5c34600380: f2 f2 f2 f2[f8]f8 f8 f8 f8 f2 f2 f2 f2 f2 00 00
0x7b5c34600400: 00 00 00 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
0x7b5c34600480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7b5c34600500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7b5c34600580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7b5c34600600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==3339842==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions