Uploaded image for project: 'RHEL'
  1. RHEL
  2. RHEL-31783

systemd service child crashes when loading credentials

    • Icon: Bug Bug
    • Resolution: Done-Errata
    • Icon: Major Major
    • rhel-9.5
    • rhel-9.3.0
    • systemd
    • None
    • systemd-252-33.el9
    • None
    • Moderate
    • ZStream
    • rhel-sst-cs-plumbers
    • ssg_core_services
    • 7
    • 26
    • 1
    • False
    • Hide

      None

      Show
      None
    • None
    • Red Hat Enterprise Linux
    • None
    • Approved Blocker
    • All
    • None

      What were you trying to do that didn't work?

      When having a service configured to load credentials, the child process of systemd aborts in assertion because of passing an invalid directory fd (-1 instead of AT_FDCWD):

      (gdb) bt
      #0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0)
          at pthread_kill.c:44
      #1  0x00007fae912a15b3 in __pthread_kill_internal (signo=6, threadid=<optimized out>) at pthread_kill.c:78
      #2  0x00007fae91254d06 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
      #3  0x00007fae912287f3 in __GI_abort () at abort.c:79
      #4  0x00007fae91687da0 in log_assert_failed (text=<optimized out>, file=<optimized out>, line=<optimized out>, 
          func=<optimized out>) at ../src/basic/log.c:853
      #5  0x00007fae917c14e7 in connect_unix_path (fd=4, dir_fd=-1, path=0x556d5cc6bf70 "/run/repro.socket")
          at ../src/basic/socket-util.c:1437
      #6  0x00007fae91794a02 in read_full_file_full (dir_fd=dir_fd@entry=-1, filename=0x556d5cc6bf70 "/run/repro.socket", 
          offset=offset@entry=18446744073709551615, size=size@entry=1048576, 
          flags=flags@entry=(READ_FULL_FILE_SECURE | READ_FULL_FILE_CONNECT_SOCKET | READ_FULL_FILE_FAIL_WHEN_LARGER), 
          bind_name=<optimized out>, ret_contents=0x7ffd71011e30, ret_size=0x7ffd71011e20) at ../src/basic/fileio.c:798
      #7  0x00007fae91aa51f4 in load_credential (context=0x556d5cdc6b98, params=<optimized out>, id=0x556d5cdf6c90 "foo", 
          path=0x556d5cc6bf70 "/run/repro.socket", encrypted=<optimized out>, unit=<optimized out>, read_dfd=-1, 
          write_dfd=3, uid=4294967295, ownership_ok=true, left=0x7ffd71011f30) at ../src/core/execute.c:2734
      #8  0x00007fae91aa59c3 in acquire_credentials (ownership_ok=true, uid=4294967295, p=<optimized out>, 
          unit=0x556d5ccd4930 "reproducer.service", params=0x7ffd71012580, context=0x556d5cdc6b98)
          at ../src/core/execute.c:2884
       :
      (gdb) f 5
      #5  0x00007fae917c14e7 in connect_unix_path (fd=4, dir_fd=-1, path=0x556d5cc6bf70 "/run/repro.socket")
          at ../src/basic/socket-util.c:1437
      1437	        assert(dir_fd == AT_FDCWD || dir_fd >= 0);
      (gdb) p dir_fd
      $1 = -1
      (gdb) up
      #6  0x00007fae91794a02 in read_full_file_full (dir_fd=dir_fd@entry=-1, filename=0x556d5cc6bf70 "/run/repro.socket", 
          offset=offset@entry=18446744073709551615, size=size@entry=1048576, 
          flags=flags@entry=(READ_FULL_FILE_SECURE | READ_FULL_FILE_CONNECT_SOCKET | READ_FULL_FILE_FAIL_WHEN_LARGER), 
          bind_name=<optimized out>, ret_contents=0x7ffd71011e30, ret_size=0x7ffd71011e20) at ../src/basic/fileio.c:798
      798	                r = connect_unix_path(sk, dir_fd, filename);
      (gdb) 
      #7  0x00007fae91aa51f4 in load_credential (context=0x556d5cdc6b98, params=<optimized out>, id=0x556d5cdf6c90 "foo", 
          path=0x556d5cc6bf70 "/run/repro.socket", encrypted=<optimized out>, unit=<optimized out>, read_dfd=-1, 
          write_dfd=3, uid=4294967295, ownership_ok=true, left=0x7ffd71011f30) at ../src/core/execute.c:2734
      2734	                r = read_full_file_full(
      (gdb) 
      #8  0x00007fae91aa59c3 in acquire_credentials (ownership_ok=true, uid=4294967295, p=<optimized out>, 
          unit=0x556d5ccd4930 "reproducer.service", params=0x7ffd71012580, context=0x556d5cdc6b98)
          at ../src/core/execute.c:2884
      2884	                        r = load_credential(
      (gdb) list
      2879	                                return log_debug_errno(errno, "Failed to open '%s': %m", lc->path);
      2880	                }
      2881	
      2882	                if (sub_fd < 0)
      2883	                        /* Regular file (incl. a credential passed in from higher up) */
      2884	                        r = load_credential(
      2885	                                        context,
      2886	                                        params,
      2887	                                        lc->id,
      2888	                                        lc->path,
      (gdb) 
      2889	                                        lc->encrypted,
      2890	                                        unit,
      2891	                                        -1,
      2892	                                        dfd,
      2893	                                        uid,
      2894	                                        ownership_ok,
      2895	                                        &left);
      2896	                else
      2897	                        /* Directory */
      2898	                        r = recurse_dir(
       :
      

      Faulty line is 2891, which passes -1.
      This got fixed Upstream by the following commit:

      commit 661e4251a5b157d1aee1df98fbd2f0c95285ebba
      Author: Daan De Meyer <daan.j.demeyer@gmail.com>
      Date:   Tue Dec 13 10:50:01 2022 +0000
      
          execute: Pass AT_FDCWD instead of -1
          
          Let's enforce that callers pass AT_FDCWD as read_dfd to load_credential()
          to avoid an assert() in read_full_file_full() if read_dfd is -1.
      

      Please provide the package NVR for which bug is seen:

      systemd-252-18.el9

      How reproducible:

      Always

      Steps to reproduce

      1. Create a dummy service loading credentials from a Unix socket
        # cat /etc/systemd/system/reproducer.service 
        [Service]
        Type=oneshot
        LoadCredential=foo:/run/repro.socket
        ExecStart=/bin/true
      2. Start the unix socket
        # ncat -l -U /run/repro.socket &
      3. Set SELinux to Permissive (because of context issues) and start the service
        # setenforce 0
        # systemctl start reproducer

      Expected results

      No assertion failure

      Actual results

      Apr 04 15:20:31 vm-rhel9 systemd[1]: Starting reproducer.service...
      Apr 04 15:20:31 vm-rhel9 systemd[39710]: Assertion 'dir_fd == AT_FDCWD || dir_fd >= 0' failed at src/basic/socket-util.c:1437, function connect_unix_path(). Aborting.
      

              lnykryn@redhat.com Lukáš Nykrýn
              rhn-support-rmetrich Renaud Métrich
              systemd maint mailing list systemd maint mailing list
              Frantisek Sumsal Frantisek Sumsal
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: