systemd-timesyncd 以及对应的sevice说明

使用说明参考:systemd-timesyncd.service 中文手册

sevice

cat /lib/systemd/system/systemd-timesyncd.service

参考文档:

systemd.unit — Unit configuration

systemd.unit 中文手册

systemd.service 中文手册

systemd.exec 中文手册

systemd.exec — Execution environment configuration 

[Unit]
Description=Network Time Synchronization
# 服务文档
Documentation=man:systemd-timesyncd.service(8)
# Check whether the given capability exists in the capability bounding set of the service manager 
ConditionCapability=CAP_SYS_TIME
# 检测是否运行于(特定的)虚拟环境中 可以在这些关键字前面加上感叹号(!)前缀表示逻辑反转。
ConditionVirtualization=!container
#默认依赖与隐含依赖类似,不同之处在于默认依赖可以使用 DefaultDependencies= 选项进行开关(默认值 yes 表示开启默认依赖,而设为 no 则表示关闭默认依赖), 而隐含依赖永远有效。 对于各类单元的默认依赖关系,可以参考对应手册页的"默认依赖"小节。
DefaultDependencies=no
After=systemd-remount-fs.service systemd-sysusers.service
Before=time-sync.target sysinit.target shutdown.target
#指定单元之间的冲突关系。 接受一个空格分隔的单元列表,表明该单元不能与列表中的任何单元共存,
Conflicts=shutdown.target
Wants=time-sync.target

[Service]
Type=notify
#当服务进程 正常退出、异常退出、被杀死、超时的时候, 是否重新启动该服务
Restart=always
# 设置在重启服务(Restart=)前暂停多长时间。 默认值是100毫秒(100ms)
RestartSec=60
ExecStart=!!/lib/systemd/systemd-timesyncd
WatchdogSec=3min
User=systemd-timesync
DynamicUser=yes
CapabilityBoundingSet=CAP_SYS_TIME
AmbientCapabilities=CAP_SYS_TIME
PrivateDevices=yes
ProtectHome=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
SystemCallFilter=~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @swap
SystemCallArchitectures=native
LockPersonality=yes
StateDirectory=systemd/timesync

[Install]
WantedBy=sysinit.target

 ExecStart=!!/lib/systemd/systemd-timesyncd

前缀效果
"@"如果在绝对路径前加上可选的 "@" 前缀,那么其后的那些参数将依次作为"argv[0] argv[1] argv[2] …"传递给被执行的进程(注意,argv[0] 是可执行文件本身)。
"-"如果在绝对路径前加上可选的 "-" 前缀,那么即使该进程以失败状态(例如非零的返回值或者出现异常)退出,也会被视为成功退出,但同时会留下错误日志。
"+"如果在绝对路径前加上可选的 "+" 前缀,那么进程将拥有完全的权限(超级用户的特权),并且 User=Group=CapabilityBoundingSet= 选项所设置的权限限制以及 PrivateDevices=PrivateTmp= 等文件系统名字空间的配置将被该命令行启动的进程忽略(但仍然对其他 ExecStart=ExecStop= 有效)。
"!"与 "+" 类似(进程仍然拥有超级用户的身份),不同之处在于仅忽略 User=Group=SupplementaryGroups= 选项的设置,而例如名字空间之类的其他限制依然有效。注意,当与 DynamicUser= 一起使用时,将会在执行该命令之前先动态分配一对 user/group ,然后将身份凭证的切换操作留给进程自己去执行。
"!!"与 "!" 极其相似,仅用于让利用 ambient capability 限制进程权限的单元兼容不支持 ambient capability 的系统(也就是不支持 AmbientCapabilities= 选项)。如果在不支持 ambient capability 的系统上使用此前缀,那么 SystemCallFilter= 与 CapabilityBoundingSet= 将被隐含的自动修改为允许进程自己丢弃 capability 与特权用户的身份(即使原来被配置为禁止这么做),并且 AmbientCapabilities= 选项将会被忽略。此前缀在支持 ambient capability 的系统上完全没有任何效果。

WatchdogSec=3min

设置该服务的看门狗(watchdog)的超时时长。 看门狗将在服务成功启动之后被启动。 该服务在运行过程中必须周期性的以 "WATCHDOG=1" ("keep-alive ping")调用 sd_notify(3) 函数。

如果在两次调用之间的时间间隔大于这里设定的值, 那么该服务将被视为失败(failed)状态, 并会被强制使用 WatchdogSignal= 信号(默认为 SIGABRT)关闭。

通过将 Restart= 设为 on-failureon-watchdogon-abnormalalways 之一, 可以实现在失败状态下的自动重启该服务。 这里设置的值将会通过 WATCHDOG_USEC= 环境变量传递给守护进程, 这样就允许那些支持看门狗的服务自动启用"keep-alive ping"。

如果设置了此选项, 那么 NotifyAccess= 将只能设为非 none 值。 如果 NotifyAccess= 未设置,或者已经被明确设为 none , 那么将会被自动强制修改为 main 。

如果未指定时间单位,那么将视为以秒为单位。 例如设为"20"等价于设为"20s"。 默认值"0"表示禁用看门狗功能。 详见   sd_watchdog_enabled(3)   与   sd_event_set_watchdog(3)    手册。

User=systemd-timesyn

设置进程在执行时使用的用户与组。 既可以设为一个数字形式的 UID/GID 也可以设为一个字符串形式的名称。

对于系统服务(由 PID=1 的 systemd 系统实例管理)以及由 root 运行的用户服务(由 root 用户启动的 systemd --user 用户实例管理), User= 的默认值是 "root" ,同时亦可明确将 User= 设为其他用户。 对于普通用户运行的用户服务,User= 的默认值就是该用户自身,并且禁止将 User= 切换为其他用户。 如果没有明确设置 Group= 选项,则使用 User= 所属的默认组。 此选项不影响 带有 "+" 前缀的命令。

注意, 为了避免歧义以及确保在不同 Linux 系统之间的兼容性, 用户与组的名称必须满足以下规则: (1)仅可包含 a-z, A-Z, 0-9, "_", "-" 字符; (2)首字母只能是 a-z, A-Z, "_" 之一(也就是禁止使用数字与 "-" 字符); (3)字符串长度必须介于 1~31 之间。

当与 DynamicUser=yes 一起使用时, 指定的用户与组将在服务启动时动态分配,并在服务停止时自动释放,除非它们已经被静态的创建了(见下文)。 当与 DynamicUser=no 一起使用时, 指定的用户与组必须在服务启动之前就已经被静态的创建了, 例如在系统启动或安装软件包时,使用 sysusers.d(5) 机制所创建的用户与组。

DynamicUser=YES

设置是否动态分配用户。默认值为 "no" 。 设为 yes 表示在该单元启动时,为其动态分配一个 user/group 对,并在该单元停止时释放。

动态分配的 user/group 不会被添加到 /etc/passwd 或 /etc/group 文件中, 而是由 glibc 的 NSS 插件 nss-systemd(8) 进行维护,以确保能够从系统的 user/group 数据库中查询到动态分配的 user/group 对。

可以通过上文的 User= 与 Group= 明确指定动态分配的 user/group 的名称。 若未明确指定名称,则自动根据单元的名称生成: 如果单元名(不含类型后缀)恰好符合用户名规则,那么就直接使用单元名,否则将使用单元名的哈希值。

如果 User= 或 Group= 恰好指定了一个已经静态存在的名称, 那么将直接使用已经静态存在的 user/group (而不是动态分配)。注意,如果指定的 User= 名称恰好与某个静态组同名, 那么在 User= 中设置的用户名也必须是静态用户。同样, 如果指定的 Group= 名称恰好与某个静态用户同名,那么在 Group= 中设置的组名也必须是静态组。因为动态分配的 UID/GID 范围在 61184-65519 之间, 所以静态存在的 UID/GID 应该避免使用这个范围。

在任意时间点上, 每一个动态分配的 UID/GID 只能对应最多一个动态分配的 user/group 。 因为动态分配的 UID/GID 在单元停止后会被回收,并且会被反复循环使用, 所以使用动态分配用户的单元不应该在其停止后遗留下任何属于动态分配用户的文件或目录, 否则其他单元有可能在未来取得相同的 UID/GID ,从而成为这些遗留文件或目录的拥有者。

当 DynamicUser=yes 时,也同时隐含的设置了  RemoveIPC=yes  与  PrivateTmp=yes  ,从而确保将单元的 IPC 对象与临时文件的生存期 与单元自身的生存期、为该单元动态分配的 user/group 的生存期绑定在一起。 因为除 /tmp 与 /var/tmp 之外,通常不存在其他全局可写的目录, 所以,这通常也确保了使用动态分配 user/group 的单元,不可能在单元停止之后还遗留任何文件或目录。

进一步,DynamicUser=yes 还同时隐含了  ProtectSystem=strict  与 ProtectHome=read-only ,以禁止单元写入文件系统上的敏感路径。 如果想要允许单元写入某些特定的路径, 那么必须将这些路径使用 ReadWritePaths= 白名单明确列出。

注意,必须小心使用这个白名单,以避免由于循环使用 UID/GID 带来的安全问题。 可以使用下文的 RuntimeDirectory= 设置一个运行时的写入目录, 该目录的拥有者将会被自动设为动态分配的 user/group ,并会在单元停止后被自动删除。 可以使用下文的 StateDirectory=CacheDirectory=LogsDirectory= 来设置一组专门用途的可写目录, 以避免由于循环使用 UID/GID 带来的安全问题。 

PrivateDevices=yes

设为 yes 表示为该单元内的进程设置一个全新的 /dev 挂载点, 并仅在其中添加诸如 /dev/null/dev/zero/dev/random/dev/ptmx/dev/pts/ … 之类的虚拟设备。

注意,并不包括 /dev/sda/dev/md0/dev/mem/dev/port … 之类的物理设备。 这样可以有效的关闭进程对物理设备的访问。 设为 yes 将会安装一个禁止使用底层I/O系统调用(@raw-io)的过滤器、 强行从 CapabilityBoundingSet= 中移除 CAP_MKNOD 与 CAP_SYS_RAWIO 项、 强行设置 DevicePolicy=closed (详见 systemd.resource-control(5) 手册)。因此,不可将该选项用于需要在主机名字空间中挂载文件系统的服务。

注意:

(1)这个全新的 /dev 挂载点将以 "ro,noexec" 选项挂载(只读,不可执行)。

(2)"noexec"可能会导致某些老旧的程序故障,因为这些程序企图通过对 /dev/zero 使用 mmap(2) 来设置可执行内存,而不是使用新式的 MAP_ANON 方法。

注意,此选项并不确保在任何情况下都能提供有效的保护(尤其是主机与单元间的挂载传递), 它与 ReadOnlyPaths= 选项具有相同的局限性(详见前文)。 如果开启此选项,并且该单元运行于用户模式或者缺少 CAP_SYS_ADMIN capability 的系统模式(例如明确将 User= 设为普通用户), 那么将自动隐含 NoNewPrivileges=yes 的设置。

注意,因为此选项的设置有可能在实际上无法落实(例如挂载名字空间不可用), 所以,在编写单元文件的时候,不应该将单元的安全依赖于此选项必然生效的假定。 此选项仅可用于系统单元(不适用于用户单元)。

CapabilityBoundingSet=CAP_SYS_TIME

设置进程的 capability 集合(bounding, effective, permitted, inheritable)中应该包含哪些 capabilities(7) 。

选项值是一个空格分隔的 capability 名称(例如  CAP_SYS_ADMIN,   CAP_DAC_OVERRIDE,   CAP_SYS_PTRACE)列表 。 列表中的 capabilities 将会被包含在 capability 集合中, 而所有其他不在列表中的 capabilities 则会被剔除。

如果列表以 "~" 符号开头,那么表示取反, 也就是所有列表之外的 capabilities 将会被包含在 capability 集合中。

若未设置此选项,则表示不修改进程的 capability 集合。 若多次设置此选项,则表示将多个设置的 capability 集合合并: 一般情况下使用 OR 逻辑合并,但以"~"开头的行则用 AND 逻辑合并。

若设为空,则表示清空所有已设置的 capability 集合。 若设为一个单独的 "~" 字符, 则表示清空先前的所有设置,并将 capability 集合重置为包含所有的 capabilities 。 此选项不影响带有 "+" 前缀的命令。

例子:如果一个单元拥有如下设置:

CapabilityBoundingSet=CAP_A CAP_B
CapabilityBoundingSet=CAP_B CAP_C

那么表示 CAP_ACAP_BCAP_C 全部被设置。 如果在第二行前面加上 "~" 前缀:

CapabilityBoundingSet=CAP_A CAP_B
CapabilityBoundingSet=~CAP_B CAP_C

那么表示仅有 CAP_A 被设置

AmbientCapabilities=CAP_SYS_TIME

设置进程的 ambient capability 集合中应该包含哪些 capabilities(7) 。 选项值是一个空格分隔的 capability 名称列表, 例如  CAP_SYS_ADMIN,   CAP_DAC_OVERRIDE,   CAP_SYS_PTRACE 。

若多次设置此选项,则表示合并多个已设置的 ambient capability 集合(参见上文 CapabilityBoundingSet= 的例子)。

如果列表以 "~" 符号开头,那么表示取反, 也就是所有列表之外的 capabilities 将会被包含在 ambient capability 集合中。

若设为空,则表示清空所有已设置的 ambient capability 集合。

若设为一个单独的 "~" 字符,则表示清空先前的所有设置,并将 ambient capability 集合重置为包含所有的 capabilities 。

注意,添加到 ambient capability 集合中的 capabilities 也会被添加到进程的 inherited capability 集合中。 你可以使用 ambient capability 集合给以普通用户身份运行的进程赋予某些 capabilities 。

注意,此时 keep-caps 将被自动添加到 SecureBits= 中, 以确保此处设置的 capabilities 不受用户设置的影响。 此选项不影响带有 "+" 前缀的命令。

ProtectHome=yes

接受一个布尔值或特殊值 "read-only" 或 "tmpfs" 。 设为 yes 表示对该单元内的进程屏蔽 /home/root/run/user 目录(内容为空且不可访问)。

设为 "read-only" 表示这三个目录仅为只读(不可写入)。设为 "tmpfs" 表示在这三个目录上挂载只读模式的临时文件系统, 这样既可以隐藏与单元内的进程无关的用户目录,又可以让 BindPaths= 或 BindReadOnlyPaths= 中列出的目录仍然对单元内的进程可见。

设为 "yes" 相当于将这三个目录放入 InaccessiblePaths= 中;设为 "read-only" 相当于将这三个目录放入 ReadOnlyPaths= 中;设为 "tmpfs" 相当于将这三个目录放入 TemporaryFileSystem= 中。

推荐为所有需要长时间运行的服务开启此选项(特别是面向网络的服务),以确保其无法访问隐私数据。 当 DynamicUser=yes 时,此选项的默认值为 "yes" ,否则默认值为 "no" 。 注意,此选项并不确保在任何情况下都能提供有效的保护(尤其是主机与单元间的挂载传递), 它与 ReadOnlyPaths= 选项具有相同的局限性(详见后文)。 此选项仅可用于系统单元(不适用于用户单元)。

ProtectControlGroups=yes

设置是否保护 cgroups 。默认值为 no 。

设为 yes 表示仅允许该单元内的进程以只读模式访问 Linux Control Groups (cgroups(7)), 也就是仅允许以只读模式访问 /sys/fs/cgroup 。

除了容器管理程序,其他服务不应该对 cgroups 拥有控制权。因此,建议为绝大多数服务单元开启此选项。 注意,此选项并不确保在任何情况下都能提供有效的保护(尤其是主机与单元间的挂载传递), 它与 ReadOnlyPaths= 选项具有相同的局限性(详见前文)。 注意, ProtectControlGroups=yes 隐含了 MountAPIVFS=yes 。 此选项仅可用于系统单元(不适用于用户单元)。

 ProtectKernelTunables=yes

设置是否保护内核变量。设为 yes 表示所有通过 /proc/sys/sys/proc/sysrq-trigger/proc/latency_stats/proc/acpi/proc/timer_stats/proc/fs/proc/irq 访问的内核变量,对于该单元内的进程,将全部变为只读。

通常,仅在系统启动的时候设置内核变量, 比如通过 sysctl.d(5) 配置。 因为只有极少数服务需要在运行时修改内核变量,所以建议为绝大多数服务单元开启此选项。

注意,此选项并不确保在任何情况下都能提供有效的保护(尤其是主机与单元间的挂载传递),它与 ReadOnlyPaths= 选项具有相同的局限性(详见前文)。

默认值为 "no" 。如果将此选项设为 yes 并且该单元运行在用户模式, 或者运行在没有 CAP_SYS_ADMIN capability 的系统模式(也就是明确设置了 User= 为非特权用户), 那么将自动隐含 NoNewPrivileges=yes 的设置。

注意,此选项不能阻止通过 IPC 调用其他进程的方式间接修改内核变量。 不过可以使用 InaccessiblePaths= 来屏蔽 IPC 对象。

注意, ProtectKernelTunables=yes 隐含的设置了 MountAPIVFS=yes 。 此选项仅可用于系统单元(不适用于用户单元)。

ProtectKernelModules=yes
 

设置是否保护内核模块。此选项仅可用于系统单元(不适用于用户单元)。 默认值为 no 。

设为 yes 表示禁止显式加载/卸载内核模块。 对于绝大多数不需要使用特别的文件系统或内核模块才能工作的服务,建议明确将此选项设为 yes 。

设为 yes 之后,将会删除该单元的 CAP_SYS_MODULE capability 并且添加一个系统调用过滤器,以禁止加载或卸载内核模块,同时,禁止访问 /usr/lib/modules 目录。

注意,此选项并不确保在任何情况下都能提供有效的保护(尤其是主机与单元间的挂载传递), 它与 ReadOnlyPaths= 选项具有相同的局限性(详见前文)。

注意,将此选项设为 yes ,既不会阻止自动加载用户明确配置为自动加载的内核模块, 也不会阻止内核自身为了完成特定功能而自动加载的内核模块。

要想彻底禁止内核模块的自动加载功能,可以参考 sysctl.d(5) 中的   kernel.modules_disabled  参数,以及讲解 /proc/sys/kernel/modules_disabled 的文档。如果开启了此选项, 并且该服务运行在用户模式或者没有 CAP_SYS_ADMIN capability 的系统模式(例如明确将 User= 设为普通用户),那么将自动隐含 NoNewPrivileges=yes 。

MemoryDenyWriteExecute=yes

接受一个布尔值。设为 yes 表示:禁止创建可写可执行的内存映射、 禁止将已存在的内存映射修改为可执行、禁止将共享内存段映射为可执行。

具体说来就是将会拒绝: 同时设置了 PROT_EXEC 与 PROT_WRITE 的 mmap(2) 系统调用、 设置了 PROT_EXEC 的 mprotect(2) 或 pkey_mprotect(2) 系统调用、 设置了 SHM_EXEC 的 shmat(2) 系统调用。

注意,此选项与那些会在运行时动态生成可执行代码的程序与库有冲突, 包括JIT(运行时编译执行)执行引擎、可执行堆栈、以及利用了C编译器"trampoline"特性生成的可执行程序。 此选项可用于提升服务的安全性,因为它使得利用软件漏洞来动态改变运行时代码变得困难。 不过服务单元可以写入没有设置 noexec 选项的文件系统(例如 /dev/shm)、或者使用 memfd_create() 系统调用来破解这种保护措施。 为了应对这种可能的破解手段, 可以通过屏蔽相关文件系统(例如 InaccessiblePaths=/dev/shm)、 设置系统调用过滤器(例如 SystemCallFilter=~memfd_create),这样的手段来预防。

注意, x86-64 完整支持此特性,但 x86 仅部分支持。特别地,在 x86 上不能使用 shmat() 保护。 在支持混合ABI的系统上(例如 x86/x86-64), 建议关闭次要的ABI(例如关闭 x86 以使用纯 x86-64 环境), 以确保进程无法通过次要ABI接口绕过此处的限制。 在实践中,明确设置 SystemCallArchitectures=native 是一种非常好的做法。 如果以用户模式运行或者以不含 CAP_SYS_ADMIN capability 的系统模式运行(例如明确将 User= 设为普通用户),那么将自动隐含 NoNewPrivileges=yes 的设置。

RestrictRealtime=yes

接受一个布尔值。设为 yes 表示禁止实时调度单元中的进程。 也就是禁止访问 SCHED_FIFOSCHED_RRSCHED_DEADLINE 这些实时任务调度策略(参见 sched(7)手册)。

如果以用户模式运行或者以不含 CAP_SYS_ADMIN capability 的系统模式运行(例如明确将 User= 设为普通用户), 那么将自动隐含 NoNewPrivileges=yes 的设置。

实时调度策略可能会导致CPU被长时间独占,进而导致系统失去响应或导致拒绝服务攻击。 应该仅允许个别确实需要实时调度的单元使用实时调度策略。 默认值为 no

 RestrictSUIDSGID=yes

boolean值

如果=yes, any attempts to set the set-user-ID (SUID) or set-group-ID (SGID) bits on files or directories will be denied (for details on these bits see inode(7))

 If running in user mode, or in system mode, but without the CAP_SYS_ADMIN capability (e.g. setting User=), NoNewPrivileges=yes is implied.

As the SUID/SGID bits are mechanisms to elevate privileges, and allows users to acquire the identity of other users, it is recommended to restrict creation of SUID/SGID files to the few programs that actually require them.

Note that this restricts marking of any type of file system object with these bits, including both regular files and directories (where the SGID is a different meaning than for files, see documentation). This option is implied if DynamicUser= is enabled. Defaults to off.

 RestrictNamespaces=yes

限制该单元内的进程对名字空间的访问。可设为一个布尔值,或者一个空格分隔的名字空间类型标识符列表。 有关 Linux 名字空间的详细解说,参见 namespaces(7) 手册。

默认值 no 表示不对名字空间的创建和切换做任何限制。 设为 yes 表示禁止访问任何类型的名字空间。 可使用的名字空间类型标识符如下:  cgroupipc,   netmnt,   piduser,   uts 。

列表默认为白名单,表示仅允许访问明确列出的名字空间类型。 可以在列表开头添加 "~" 字符表示反转(变成黑名单), 也就是仅禁止访问明确列出的名字空间类型。

设为空字符串等价于重置为默认值 no (不作任何限制)。 可以多次使用此选项,表示将多个名字空间类型使用 OR 逻辑合并(但以"~"开头的行则用 AND 逻辑合并)(参见下面的例子)。

在系统内部,此处的设置实际上是限制可以对 unshare(2)clone(2)setns(2) 系统调用使用那些标记参数。

注意,如果使用此选项限制了对特定类型的名字空间的创建与切换,那么同时也将禁止对 setns() 系统调用使用空标记参数。 此选项仅在 x86, x86-64, mips, mips-le, mips64, mips64-le, mips64-n32, mips64-le-n32, ppc64, ppc64-le, s390, s390x, 架构上有意义。

如果以用户模式运行或者以不含 CAP_SYS_ADMIN capability 的系统模式运行(例如设置了 User=nobody), 那么将自动隐含 NoNewPrivileges=yes 的设置。

例如,如果在一个单元中存在如下设置:

RestrictNamespaces=cgroup ipc
RestrictNamespaces=cgroup net

那么 cgroupipcnet 将会被设置。 如果第二行带有 "~" 前缀,例如

RestrictNamespaces=cgroup ipc
RestrictNamespaces=~cgroup net

那么将只有 ipc 被设置。

RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6

限制该单元内的进程可以访问的套接字类型。

值是一个空格分隔的地址族列表(默认为白名单)。 例如 AF_UNIXAF_INETAF_INET6 … 列表默认解释为白名单。 但也可以在列表开头添加 "~" 字符表示反转(变成黑名单),也就是仅禁止使用列出的套接字。

注意,此限制仅作用于 socket(2) 系统调用。 通过其他方式传递给进程的套接字(例如,基于套接字启动的单元,参见 systemd.socket(5))、 以及由 socketpair() 创建的 AF_UNIX 套接字,不受此选项影响。

此外,此选项在 32-bit x86, s390, s390x, mips, mips-le, ppc, ppc-le, pcc64, ppc64-le 架构上是无效的(注意,在 x86-64 上是有效的)。 在支持混合ABI的系统上(例如 x86/x86-64),建议关闭次要的ABI(例如关闭 x86 以使用纯 x86-64 环境), 以确保进程无法通过次要ABI接口绕过此处的限制。

在实践中, 明确设置 SystemCallArchitectures=native 是一种非常好的做法。 如果以用户模式运行或者以不含 CAP_SYS_ADMIN capability 的系统模式运行(例如设置了 User=nobody),那么将自动隐含 NoNewPrivileges=yes 的设置。 该选项默认不作任何限制。明确设为空字符串表示撤销先前所有的限制(也就是重置为默认值)。 此选项不影响带有 "+" 前缀的命令。

此选项旨在限制对进程的远程访问,特别是通过例如 AF_PACKET 这样敏感的协议。 注意,在大多数情况下,应该将 AF_UNIX 包含在白名单中, 因为包括通过 syslog(2) 发送日志之类的本地进程间通信需要使用它。

SystemCallFilter=~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @swap

设置该单元内进程的系统调用过滤器。 值是一个空格分隔的系统调用名称列表(默认为白名单)。 如果该单元内的进程使用了白名单列表之外的系统调用,将会立即被 SIGSYS 信号杀死。

可以在列表开头添加 "~" 字符表示反转(变成黑名单), 也就是仅禁止使用列表中列出的系统调用。

对于在黑名单列表中列出的每一个系统调用(或系统调用集合)项,可选地, 都可以使用冒号(":")来添加 "errno" 错误代码(0~4095)或错误名称(例如 EPERMEACCESEUCLEAN)后缀, 其含义是,如果进程使用了黑名单中的系统调用,那么直接返回该系统调用后缀中指定的错误代码或错误名称(而不是简单的直接杀死进程)。

通过后缀指定的错误代码或错误名称的优先级高于在 SystemCallErrorNumber= 中设置的值。 如果以用户模式运行、或者以不含 CAP_SYS_ADMIN capability 的系统模式运行(例如设置了 User=nobody), 那么将自动隐含 NoNewPrivileges=yes 的设置。 该选项依赖于内核的 Secure Computing Mode 2 接口("seccomp filtering"),常用于强制建立一个最小化的沙盒环境。

注意,execveexitexit_groupgetrlimitrt_sigreturnsigreturn 以及查询系统时间与暂停执行(sleep)的系统调用是默认隐含于白名单中的。 可以多次使用此选项以融合多个过滤器。 若设为空,则表示清空先前所有已设置的过滤器。 此选项不影响带有 "+" 前缀的命令。

注意,在支持混合ABI的系统上(例如 x86/x86-64),建议关闭次要的ABI(例如关闭 x86 以使用纯 x86-64 环境), 以确保进程无法通过次要ABI接口绕过此处设置的限制。 我们强烈建议将此选项与例如 SystemCallArchitectures=native 这样的设置一起使用。

注意,过于严苛的系统调用过滤器有可能会对服务单元的正常进程执行与故障处理机制产生不良影响。 特别地,如果 execve 系统调用被屏蔽, 那么将无法启动服务进程。 此外,如果服务进程启动失败(例如未找到可执行文件), 那么故障处理机制有可能需要额外访问更多的系统调用,以确保可以正常的收拾残局与记录错误日志。 为了调试是否是因为系统调用过滤器过于严苛而导致的单元故障, 可以临时禁用系统调用过滤器。

如果同时设置了白名单和黑名单,那么以先出现的名单为基准, 后出现的名单将基于第一个名单对列表项进行加减。 例如,首个列表为白名单,包含 read 与 write 两项, 随后又是一个仅包含一个 write 的黑名单, 那么最终结果将是一个仅包含 read 的白名单。

因为系统调用的数量非常巨大, 所以 systemd 预定义了一些以 "@" 字符开头的系统调用的集合,以方便使用。

表 3. 预定义的系统调用集合

集合名称描述
@aio异步 I/O 操作 (io_setup(2)io_submit(2), …)
@basic-io基本的 I/O 操作:读取、写入、寻址、文件描述符的复制与关闭 (read(2)write(2), …)
@chown更改文件归属 (chown(2)fchownat(2), …)
@clock更改系统时钟 (adjtimex(2)settimeofday(2), …)
@cpu-emulationCPU 模拟 (vm86(2) …)
@debug调试、性能监控、跟踪 (ptrace(2)perf_event_open(2) …)
@file-system文件系统操作:打开文件/目录、创建文件/目录、读写文件/目录、重命名文件/目录、删除文件/目录、读取文件属性、创建硬连接/软连接
@io-event事件循环 (poll(2)select(2)epoll(7)eventfd(2) …)
@ipc管道, SysV IPC, POSIX 消息队列, 其他IPC (mq_overview(7)svipc(7))
@keyring内核密钥环 (keyctl(2) …)
@memlock将内存锁定在 RAM 中 (mlock(2)mlockall(2) …)
@module加载/卸载内核模块 (init_module(2)delete_module(2) …)
@mount挂载/卸载文件系统 (mount(2)chroot(2), …)
@network-ioSocket I/O (包括 AF_UNIX): socket(7)unix(7)
@obsolete不常用/反对使用/未实现的系统调用 (create_module(2)gtty(2), …)
@privileged所有需要特权的调用 (capabilities(7))
@process进程控制、执行、名字空间操作 (clone(2)kill(2)namespaces(7), …
@raw-io原始 I/O 端口访问 (ioperm(2)iopl(2)pciconfig_read(), …
@reboot重新启动与准备重启 (reboot(2)kexec(), …)
@resources更改资源限制、内存使用、进程调度 (setrlimit(2)setpriority(2), …)
@setuid更改 UID/GID 凭证 (setuid(2)setgid(2)setresuid(2), …)
@signal操纵与处理进程信号 (signal(2)sigprocmask(2), …)
@swap挂载与卸载 swap 设备 (swapon(2)swapoff(2))
@sync将内存中的缓存刷写到磁盘上 (fsync(2)msync(2), …)
@system-service一组仅供常规系统服务使用的、合理的系统调用,不包含任何特殊用途的系统调用。建议以此作为设置系统服务的系统调用白名单的起点,因为它仅包含系统服务通常必需的系统调用,但不包括某些特定用途的系统调用(例如排除了 "@clock", "@mount", "@swap", "@reboot")。
@timer按时间编排执行计划 (alarm(2)timer_create(2), …)


注意,当内核增加新的系统调用时,上述集合的内容可能会随之发生变化。 此外,集合的内容也会跟随内核版本以及编译 systemd 的目标架构的不同而变化。 可以使用 systemd-analyze syscall-filter 精确的列出 每个过滤器中的系统调用。

通常,使用白名单(而不是黑名单)是更安全的模式。 建议对所有长期运行的系统服务使用系统调用白名单进行限制。 对于大多数系统服务来说,可以使用下面的设置作为安全设置的起点:

[Service]
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM

推荐将文件系统名字空间相关的选项与 SystemCallFilter=~@mount 一起使用,以阻止单元内的进程改变挂载属性。 文件系统名字空间相关的选项有: PrivateTmp=PrivateDevices=ProtectSystem=ProtectHome=ProtectKernelTunables=ProtectControlGroups=ReadOnlyPaths=InaccessiblePaths=ReadWritePaths=

 SystemCallArchitectures=native

接受一个空格分隔的体系结构标识符列表,设置进程可以使用哪些体系结构的系统调用。

可以使用的标识符与 ConditionArchitecture= 相同(参见 systemd.unit(5) 手册), 此外还包括 x32mips64-n32mips64-le-n32native(编译 systemd 时的目标架构)。 如果以用户模式运行或者以不含 CAP_SYS_ADMIN capability 的系统模式运行(例如设置了 User=nobody), 那么将自动隐含 NoNewPrivileges=yes 的设置。 该选项的默认值为空,表示不作任何限制。

如果设置了此选项,那么该单元中的进程就只能使用此选项指定体系结构的系统调用。 注意,当此选项非空时,native 将被自动隐含的包含在列表中。 为了此选项的目的, x32 体系结构被视为包括 x86-64 系统调用。 然而,此选项仍然可以在 x32 上实现它的目的,如下所述。

系统调用过滤器并非在所有体系结构上都完全一致。例如,由于 ABI 的限制, 无法在 x86 上对网络套接字相关的系统调用进行过滤,但是 x86-64 却不存在这个问题(也就是可以过滤)。 在支持混合ABI的系统上(例如 x86/x86-64), 建议关闭次要的ABI(例如关闭 x86 以使用纯 x86-64 环境), 以确保进程无法通过次要ABI接口绕过系统调用过滤器的限制。在实践中,明确设置 SystemCallArchitectures=native 是一种非常好的做法。

还可以通过 SystemCallArchitectures= 在全局范围内限制可使用的ABI架构。详见 systemd-system.conf(5) 手册。

LockPersonality=yes

接受一个布尔值,表示是否锁定 personality(2) 系统调用。

设为 yes 表示禁止更改内核的执行域,也就是只能使用默认值或 Personality= 设置的值,这有助于提升系统的安全性。

如果以用户模式运行或者以不含 CAP_SYS_ADMIN capability 的系统模式运行(例如设置了 User=), 那么将自动隐含 NoNewPrivileges=yes 的设置。 

StateDirectory=systemd/timesync

RuntimeDirectory=StateDirectory=CacheDirectory=LogsDirectory=ConfigurationDirectory=

这些选项接受一个空格分隔的目录名称列表。 目录名称必须是相对路径,并且不能包含 ".." 成分。 如果设置了这里的选项,那么在单元启动时,将会在下表指定的父目录之下, 按照指定的名称创建一个或多个目录(含上级目录)。 同时,还会以目录的完整路径为值,定义与选项对应的环境变量, 如果设置了多个目录,那么环境变量中的多个路径之间使用冒号分隔。

表 2. 自动目录创建与环境变量

目录用于系统单元的父目录用于用户单元的父目录自动设置的环境变量
RuntimeDirectory=/run$XDG_RUNTIME_DIR$RUNTIME_DIRECTORY
StateDirectory=/var/lib$XDG_CONFIG_HOME$STATE_DIRECTORY
CacheDirectory=/var/cache$XDG_CACHE_HOME$CACHE_DIRECTORY
LogsDirectory=/var/log$XDG_CONFIG_HOME/log$LOGS_DIRECTORY
ConfigurationDirectory=/etc$XDG_CONFIG_HOME$CONFIGURATION_DIRECTORY

对于 RuntimeDirectory= 来说, 除非 RuntimeDirectoryPreserve= 被设为 restart 或 yes , 否则,当单元停止时,将会自动删除已经创建的目录(实际仅删除最末级的目录)。

但是对于 StateDirectory=,   CacheDirectory=,   LogsDirectory=,   ConfigurationDirectory= 来说,即使单元已经停止,也不会删除已经创建的目录。

对于除 ConfigurationDirectory= 之外的其他选项来说, 在创建指定的目录时,将会以 User= 与 Group= 作为拥有者(实际仅为最末级的目录)。 如果指定的目录已经存在,并且这些目录自身并不符合 User= 与 Group= 的设置, 那么将会强制按照 User= 与 Group= 的设置,递归的修改这些目录。

作为一种优化措施,如果指定的目录已经存在,并且这些目录自身已经符合 User= 与 Group= 的设置, 那么即使这些目录下的内容并不符合 User= 与 Group= 的设置,也会按原样保持这些目录下的内容不变。 对指定的目录(实际仅为最末级的目录),将会分别按照 RuntimeDirectoryMode=StateDirectoryMode=CacheDirectoryMode=LogsDirectoryMode=ConfigurationDirectoryMode= 强制设置其访问权限。

这些选项创建的目录都被隐含的添加到了 BindPaths= 之中。当这些选项与 RootDirectory= 或 RootImage= 一起使用时, 这些路径将始终驻留在宿主系统中,并且会被挂载到单元内的文件系统名字空间中。

如果 DynamicUser=yes ,那么 StateDirectory=,   CacheDirectory=,   LogsDirectory=  将会分别在主机的 /var/lib/private,   /var/cache/private,   /var/log/private 目录中创建指定的目录。 因为非特权用户无法访问主机上的这些目录,所以这些目录不会因为动态用户UID循环而被意外访问, 同时,自动创建的软连接,也消除了这种做法造成的路径差异。 最终,无论是从宿主系统的视角,还是从单元内部的视角,这些目录都将始终直接位于 /var/lib/var/cache/var/log 目录之中。

使用 RuntimeDirectory= 来管理单元的运行时目录, 可以将运行时目录与单元的生命周期绑定在一起, 以确保这些运行时目录在单元启动时自动创建、并在单元停止时自动删除。 这非常适合于那些没有权限在 /run 中创建运行时目录的非特权守护进程。 对于需要更复杂配置或者生存期保证的运行时目录,可以考虑使用 tmpfiles.d(5) 功能。

例如,如果在一个系统服务单元中存在如下设置:

RuntimeDirectory=foo/bar baz

那么,当该服务启动时,将会自动创建 /run/foo(若不存在), /run/foo/bar/run/baz 目录并将 /run/foo/bar 与 /run/baz (/run/foo 除外) 的拥有者设置为 User= 与 Group=; 当该服务停止时,这两个目录(/run/foo 除外)也会被自动删除。

例如,如果在一个系统服务单元中存在如下设置:

RuntimeDirectory=foo/bar
StateDirectory=aaa/bbb ccc

那么环境变量 "RUNTIME_DIRECTORY" 与 "STATE_DIRECTORY" 将被创建, 并且分别被赋值为 "/run/foo/bar" 与 "/var/lib/aaa/bbb:/var/lib/ccc" 。

### Ubuntu `systemd-networkd` 配置缺失解决方案 对于Ubuntu系统中遇到的`network.service`找不到的问题,通常是因为`systemd-networkd`服务未被启用或配置不正确。以下是详细的排查和修复方法: #### 1. 检查网络管理器状态 确认当前使用的网络管理工具是否为`NetworkManager`或其他替代方案。如果使用的是`systemd-networkd`,则应确保其已正确安装并激活。 ```bash sudo systemctl status systemd-networkd ``` 若显示未运行,则继续下一步操作[^1]。 #### 2. 安装与启动`systemd-networkd` 通过APT包管理系统来获取必要的组件,并开启相应的服务单元文件。 ```bash sudo apt update && sudo apt install -y systemd-timesyncd systemd-resolved systemd-networkd ``` 接着重启相关联的服务以应用更改: ```bash sudo systemctl enable --now systemd-networkd ``` 这一步骤会创建默认链接配置(/etc/systemd/network/99-default.link),从而允许基本联网功能正常运作。 #### 3. 创建静态IP地址配置(可选) 如果有特定需求如固定IP地址分配,可以在/etc/systemd/network目录下新建一个`.netdev`文件用于定义虚拟设备以及对应的`.network`文件指定属性参数。 例如,在此路径下建立名为`eth0.network`的新文档,内容如下所示: ```ini [Match] Name=eth0 [Network] Address=192.168.x.y/24 ; 替换成实际想要设定的IPv4地址及子网掩码长度 Gateway=192.168.x.z ; 默认路由下一跳地址 DNS=8.8.8.8 ; 可选项,自定义首选DNS服务器 Domains=~example.com ; 域名解析范围限定符 ``` 保存修改后再次重载守护进程和服务实例以便生效新设置: ```bash sudo systemctl daemon-reload sudo systemctl restart systemd-networkd ``` 以上措施能够有效解决因缺少适当配置而导致无法识别`network.service`的情况。值得注意的是,某些发行版可能预设启用了其他类型的网络管理程序(比如NetworkManager),此时建议先禁用冲突项再尝试上述指导方针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值