Skip to content

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

@wezm

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions