Skip to content

Conversation

@outlook84
Copy link

@outlook84 outlook84 commented Aug 15, 2025

Strengthen the security of the openlist.service systemd unit by applying a comprehensive set of modern sandboxing and hardening directives.

This change sandboxes the process to limit its potential impact in case of a compromise. Key improvements include:

  • Restricting filesystem access (ProtectSystem, PrivateTmp, PrivateDevices)
  • Limiting the kernel attack surface with a strict system call filter
  • Preventing privilege escalation (NoNewPrivileges)
  • Dropping unnecessary capabilities (CapabilityBoundingSet)
  • Isolating the process from devices, IPC, and other system resources
  • Custom user/group for systemd service

Additionally, the network dependency is updated to network-online.target to ensure the network is fully available before the service starts.

Breaking changes on filesystem access:

  • When running as root, ProtectSystem=true makes /usr, /boot and /efi read-only.
  • When running as non-root, ProtectSystem=full makes /usr, /etc, /boot and /efi read-only.
  • PrivateTmp=true gives the service its own isolated /tmp and /var/tmp directories.

Strengthen the security of the `openlist.service` systemd unit by applying a comprehensive set of modern sandboxing and hardening directives.

This change sandboxes the process to limit its potential impact in case of a compromise. Key improvements include:
- Restricting filesystem access (`ProtectSystem`, `PrivateTmp`, `PrivateDevices`)
- Limiting the kernel attack surface with a strict system call filter
- Preventing privilege escalation (`NoNewPrivileges`)
- Dropping unnecessary capabilities (`CapabilityBoundingSet`)
- Isolating the process from devices, IPC, and other system resources

Additionally, the network dependency is updated to `network-online.target` to ensure the network is fully available before the service starts.
@dezhishen dezhishen requested a review from Copilot August 15, 2025 08:50
SystemCallFilter=~@resources
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
RemoveIPC=true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although uncertain, but it could potentially affect our upcoming plug-in system.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need @dezhishen check this.

This comment was marked as outdated.

Introduce `SYSTEMD_USER` and `SYSTEMD_GROUP` variables to configure the systemd service user.
Implement `parse_install_args` to allow specifying a custom installation path and user:group via command-line arguments.
Update the systemd service unit to run OpenList under the specified user and group, adjusting capabilities and `ProtectSystem` accordingly.
@jyxjjj jyxjjj requested a review from Copilot August 15, 2025 11:19
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR strengthens the security of the openlist.service systemd unit by adding comprehensive sandboxing and hardening directives. The implementation also adds support for specifying custom systemd service users and installation paths.

  • Adds robust systemd hardening with sandboxing, capability restrictions, and system call filtering
  • Implements support for custom user/group configuration for the systemd service
  • Modifies the script to accept user/group parameters alongside installation paths

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@outlook84
Copy link
Author

There is more secure way of sandboxing via systemd: DynamicUser=true.

The whole filesystem will be nearly totally read-only, persistent dir with DynamicUser ownership can be set with StateDirectory=openlist which is /var/lib/openlist.

Do developers think it is needed?

@jyxjjj
Copy link
Member

jyxjjj commented Aug 16, 2025

No, that will require users to manually modify the configuration and write their own folders to the service files. Otherwise, local storage will not be used.

@jyxjjj
Copy link
Member

jyxjjj commented Aug 16, 2025

Btw, i don't think we need further more.
The existing components you have committed are sufficient. If you can actually break in, then everything else is meaningless. The rest should be handled by SELinux. Most distributions don't have such extensive security measures.

@jyxjjj
Copy link
Member

jyxjjj commented Aug 16, 2025

@dezhishen @ILoveScratch2 @SenkjM
LGTM currently, after all conversations are resolved, it can be merged.
Please review again.

- Add a `CHECK_PERMISSIONS` function to verify that a non-root user has sufficient permissions to access the installation path before proceeding.
- Make the `.version` file path relative to the installation directory instead of hardcoded.
…directory.

Only execute (`x`) permission is required for a service user to traverse a directory path to access its subdirectories. The read (`r`) permission is not necessary for this purpose.
@ILoveScratch2 ILoveScratch2 changed the title feat(systemd): Harden openlist service unit feat(security): allow non-root operation and harden service Aug 21, 2025
@ILoveScratch2 ILoveScratch2 requested a review from xrgzs August 25, 2025 03:11
Copy link
Member

@xrgzs xrgzs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要确保用户是否存在

如下为输入了一个不存在的用户和用户组安装,导致无法启动:

└─$ systemctl status openlist
× openlist.service - OpenList service
     Loaded: loaded (/etc/systemd/system/openlist.service; enabled; preset: disabled)
     Active: failed (Result: exit-code) since Mon 2025-08-25 13:01:19 EDT; 1min 21s ago
   Duration: 5ms
 Invocation: 5bfd5fc580664ba19fe32299ddd55369
    Process: 2630 ExecStart=/opt/openlist/openlist server (code=exited, status=217/USER)
   Main PID: 2630 (code=exited, status=217/USER)
   Mem peak: 1.9M
        CPU: 4ms

Aug 25 13:01:19 kali systemd[1]: Started openlist.service - OpenList service.
Aug 25 13:01:19 kali (openlist)[2630]: openlist.service: Failed to determine user credentials: No such pr>
Aug 25 13:01:19 kali (openlist)[2630]: openlist.service: Failed at step USER spawning /opt/openlist/openl>
Aug 25 13:01:19 kali systemd[1]: openlist.service: Main process exited, code=exited, status=217/USER
Aug 25 13:01:19 kali systemd[1]: openlist.service: Failed with result 'exit-code'.

内容:

└─$ cat /etc/systemd/system/openlist.service
[Unit]
Description=OpenList service
After=network-online.target

[Service]
Type=simple
User=1001
Group=1001
WorkingDirectory=/opt/openlist
ExecStart=/opt/openlist/openlist server
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ProtectSystem=full
ProtectProc=invisible
ProtectControlGroups=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectClock=true
ProtectHostname=true
PrivateTmp=true
PrivateDevices=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictSUIDSGID=true
SystemCallFilter=@system-service
SystemCallFilter=~@privileged
SystemCallFilter=~@resources
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
RemoveIPC=true
IPAddressDeny=multicast
MemoryDenyWriteExecute=true
LockPersonality=true

[Install]
WantedBy=multi-user.target

Add a check to verify that the user and group specified for the systemd service exist on the system before proceeding with the installation.

Previously, the script would accept any user:group string, which could lead to a failed service configuration if the user or group was invalid.

This commit introduces a `check_user_group` function that uses `getent` for validation. This check is now integrated into both the command-line argument parsing (`--user`) and the interactive menu, ensuring a more robust installation process by preventing setup with non-existent credentials.
@outlook84
Copy link
Author

需要确保用户是否存在

Done.

@qianbinbin
Copy link

插个嘴,有的特性需要比较新的 systemd 版本,比如 ProtectProc 需要 247,相当于 Debian 11 或 Ubuntu 22.04

另外有人告诉过我群晖的 systemd 非常古老,不过也许他们可以用 docker?(我不是群晖用户)

@outlook84
Copy link
Author

插个嘴,有的特性需要比较新的 systemd 版本,比如 ProtectProc 需要 247,相当于 Debian 11 或 Ubuntu 22.04

另外有人告诉过我群晖的 systemd 非常古老,不过也许他们可以用 docker?(我不是群晖用户)

非关键参数,systemd 会忽略错误,继续启动服务的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants