CentOS systemd 将以 `sudo` 启动的服务子进程放在 `user.slice` 中(而不是 `system.slice`)

CentOS systemd 将以 `sudo` 启动的服务子进程放在 `user.slice` 中(而不是 `system.slice`)

使用 systemd 服务创建的子进程sudo放置在user.slice.仅在 CentOS 8 (x86_64 20230606) 上观察到此行为,而在 Ubuntu 20.04.5 LTS 上则未观察到,在 Ubuntu 20.04.5 LTS 上,此类子进程被放置在其中system.slice

这是一个很大的问题,因为这会导致主服务进程驻留在不同的 cgroup 中,而创建的子进程sudo最终位于另一个 cgroup 中。因此,systemctl stop在服务上调用只会停止主服务进程,而不会停止使用 创建的子进程sudo,因此它们最终会挂起。

复制步骤:

  1. 以非 root 用户(具有sudo权限)身份登录:
$ ssh centos@{ADDR}
  1. script.sh创建包含以下内容的bash 脚本:
#!/bin/bash
sudo sleep 1000
  1. 使脚本可执行:
$ chmod +x script.sh
  1. 将脚本作为 systemd 服务运行:
$ sudo systemd-run ./script.sh
Running as unit: run-r16ed2fef94d442b5800035653bcbbe01.service
  1. 检查状态:
$ sudo systemctl status run-rf4fe2865d42240c1a95f1ed497575494.service
● run-rf4fe2865d42240c1a95f1ed497575494.service - /home/centos/./script.sh
   Loaded: loaded (/run/systemd/transient/run-rf4fe2865d42240c1a95f1ed497575494.service; transient)
Transient: yes
   Active: active (running) since Wed 2023-11-15 10:01:49 UTC; 1min 1s ago
 Main PID: 10587 (script.sh)
    Tasks: 1 (limit: 97480)
   Memory: 1.7M
   CGroup: /system.slice/run-rf4fe2865d42240c1a95f1ed497575494.service
           └─10587 /bin/bash /home/centos/./script.sh

您可以看到结果cgroup 中既没有列出子进程也没有列出sudosleep注意 PID 10587。

  1. 检查睡眠进程是否存在:
$ ps aux | grep sleep
root       10588  0.0  0.0 333172  8140 ?        S    10:01   0:00 sudo sleep 1000
root       10591  0.0  0.0 217092   848 ?        S    10:01   0:00 sleep 1000
centos     10687  0.0  0.0 221940  1164 pts/0    S+   10:03   0:00 grep --color=auto sleep

停止创建的 systemd 进程不会杀死这两个sudosleep进程(PID 分别为 10588 和 10591)。

  1. 检查这些进程所属的systemd片:
  • 主要的systemd服务进程(10587,见systemctl status上文):
$ cat /proc/10587/cgroup | grep name=
1:name=systemd:/system.slice/run-rf4fe2865d42240c1a95f1ed497575494.service
  • sudo进程(10588):
$ cat /proc/10588/cgroup | grep name=
1:name=systemd:/user.slice/user-0.slice/session-c37.scope
  • 子进程sleep(10591)"
$ cat /proc/10591/cgroup | grep name=
1:name=systemd:/user.slice/user-0.slice/session-c37.scope

您可以观察到主脚本进程属于system.slice,而子进程属于user.slice

在 Ubuntu 20.04.5 LTS 中,使用完全相同的步骤会导致所有子进程被放置在同一个 cgroup 中,位于以下位置system.slice

$ sudo systemd-run ./script.sh
Running as unit: run-r09332b0da31a4dd198286a87a917e55f.service
ubuntu@ip-10-0-0-92:~$ sudo systemctl status run-r09332b0da31a4dd198286a87a917e55f.service
● run-r09332b0da31a4dd198286a87a917e55f.service - /home/ubuntu/./script.sh
     Loaded: loaded (/run/systemd/transient/run-r09332b0da31a4dd198286a87a917e55f.service; transient)
  Transient: yes
     Active: active (running) since Wed 2023-11-15 10:06:55 UTC; 7s ago
   Main PID: 1729 (script.sh)
      Tasks: 3 (limit: 18627)
     Memory: 1.4M
     CGroup: /system.slice/run-r09332b0da31a4dd198286a87a917e55f.service
             ├─1729 /bin/bash /home/ubuntu/./script.sh
             ├─1730 sudo sleep 1000
             └─1731 sleep 1000

因此,停止该服务会杀死所有子进程。

那么 CentOS 中发生了什么?我怎样才能使 systemd 的行为与 Ubuntu 中的行为相同?我可以强制将子进程放置在 下的同一个 cgroup 中system.slice吗?

我检查了 CentOS 中创建的服务的 systemd 参数,它们实际上与 Ubuntu 的相同。特别是,该Slice参数在 CentOS 中设置为system.slice

$ sudo systemctl show run-rf4fe2865d42240c1a95f1ed497575494.service | grep Slice=
Slice=system.slice

答案1

Systemd 服务配置不会接管子进程的创建,也不会将子进程移动到任何地方。这是由 PAM 配置sudo本身完成的,它会不必要地调用pam_systemd(可能是故意为了达到您不想要的结果,或者可能只是试图在人们尝试以 root 身份运行 GUI 应用程序时为目标用户设置 XDG_RUNTIME_DIR?我不知道)。

PAM 模块创建一个 systemd-logind 会话,这会导致 logind 将调用进程移至“会话”cgroup,与您自己的 shell 进程移出 sshd.service 或[电子邮件受保护]当您登录时。

编辑/etc/pam.d/sudo以禁用此模块。但是,请注意不要为其他 PAM 配置禁用它 – 如果文件包含 /etc/pam.d/system-auth (控制台和 SSH 登录也使用它),则您需要将 pam_systemd 保留在那里;相反,你可能需要插入一个pam_succeed_if欺骗 PAM 跳过它:

session [success=1 default=ignore] pam_succeed_if.so service = sudo
session whatever                   pam_systemd.so

(如果 pam_succeed_if 返回 PAM_SUCCESS,“success=1”会跳过 1 个下一个模块,而“default=ignore”会导致忽略所有其他结果。)

相关内容