10 Commits
Author SHA1 Message Date
SymbX 2731560250 workaround for waitpid 2026-10-29 22:33:28 +02:00
SymbX afa212d153 workaround to support pidfd_open (backported) while waitpid is missing 2026-10-29 22:33:28 +02:00
SymbX 93b7d20dcc revert changes to apply with system where kernel is 4.19 2026-10-29 22:33:27 +02:00
Luca Boccassi 73612ea502 meson: bump version to 262.1 2026-10-16 17:24:52 +01:00
Luca Boccassi aa0c421647 hwdb: update to main@{2026-10-15}
git restore -s origin/main hwdb.d/ test/hwdb.d
2026-10-16 17:24:52 +01:00
Yu Watanabe 29b1d05549 mkosi: update nura commit reference to 7a6b81a4f1a7a510d088a5874bebcf2b200b69b3
* 7a6b81a4f1 Revert "systemd/systemd: build with SELinux support"
* 1e70e1b89a systemd/systemd: add patch to fix nsresourced failure

Alpine updated linux-pam 1.7.1-r3 to 1.7.1-r4, which disables SELinux
support again [1]. Hence, systemd also needs to be built without
SELinux support [2]. Otherwise, all operations that require PAM fail.

[1] https://gitlab.alpinelinux.org/alpine/aports/-/commit/f3734bec196117b7972c32545594f3ab3a53a111
[2] https://gitlab.postmarketos.org/postmarketOS/pmaports/-/commit/7a6b81a4f1a7a510d088a5874bebcf2b200b69b3

(cherry picked from commit 6645aa57a2e20678007424ca9125efa99df2925d)
2026-10-16 17:24:52 +01:00
Paul Meyer 659d194912 ci: skip push-triggered jobs on forks
Syncing a fork's main branch triggers the push workflows if actions are
enabled, which then run the full CI matrix and use up the fork owner's
Actions minutes for no benefit. Only skip push events so that PRs within
a fork still run CI, which is useful for testing actions.

Signed-off-by: Paul Meyer <katexochen0@gmail.com>
(cherry picked from commit 4c63532c28094aeba6dccc5afb9690e02fd98d66)
2026-10-16 17:24:52 +01:00
dependabot[bot] f9f3c11f40 build(deps): bump the actions group with 4 updates
Bumps the actions group with 4 updates: [github/codeql-action/upload-sarif](https://github.com/github/codeql-action), [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials), [redhat-plumbers-in-action/differential-shellcheck](https://github.com/redhat-plumbers-in-action/differential-shellcheck) and [softprops/action-gh-release](https://github.com/softprops/action-gh-release).

Updates `github/codeql-action/upload-sarif` from 4.37.8 to 4.38.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2)

Updates `aws-actions/configure-aws-credentials` from 6.2.3 to 6.3.0
- [Release notes](https://github.com/aws-actions/configure-aws-credentials/releases)
- [Changelog](https://github.com/aws-actions/configure-aws-credentials/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws-actions/configure-aws-credentials/compare/e6de054238d6b7531b4efff3b6587d9aade6a06c...e1253824e5c10ff9df46874f81ed3ec929e19cfd)

Updates `redhat-plumbers-in-action/differential-shellcheck` from 5.5.6 to 5.5.7
- [Release notes](https://github.com/redhat-plumbers-in-action/differential-shellcheck/releases)
- [Changelog](https://github.com/redhat-plumbers-in-action/differential-shellcheck/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/redhat-plumbers-in-action/differential-shellcheck/compare/d965e66ec0b3b2f821f75c8eff9b12442d9a7d1e...f51c7c0d32777d00de777131d25918617a246415)

Updates `softprops/action-gh-release` from 3.0.2 to 3.0.3
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/3d0d9888cb7fd7b750713d6e236d1fcb99157228...efb35369e0ad2afab669f228072c1b0d510eae64)

---
updated-dependencies:
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.38.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: aws-actions/configure-aws-credentials
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: redhat-plumbers-in-action/differential-shellcheck
  dependency-version: 5.5.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit 8de82afa1055428b1a0adc0f78be789a62fb7a9f)
2026-10-16 17:24:52 +01:00
dependabot[bot] 69dde70fba build(deps): bump ninja from 1.13.0 to 1.13.2 in /.github/workflows
Bumps [ninja](https://github.com/ninja-build/ninja) from 1.13.0 to 1.13.2.
- [Release notes](https://github.com/ninja-build/ninja/releases)
- [Commits](https://github.com/ninja-build/ninja/compare/v1.13.0...v1.13.2)

---
updated-dependencies:
- dependency-name: ninja
  dependency-version: 1.13.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit 7c6462fe374fd1426835896ee7a9d4e1fa417e11)
2026-10-16 17:24:52 +01:00
LevitatingBusinessMan (Rein Fernhout) 67e054aa5a mkosi,test: rename postmarketos to nura
Recently, postmarketOS is renamed to Nura:
See https://postmarketos.org/blog/2026/09/27/nura-rename/

mkosi already renamed postmarketOS to Nura:
https://github.com/systemd/mkosi/commit/580c4d94d75ef18f2a0983626cfd80bea9c44ece

Co-authored-by: Yu Watanabe <watanabe.yu+github@gmail.com>
(cherry picked from commit e9090fe18086edf48ef9f2ab420366b3c5f1d027)
2026-10-16 17:24:52 +01:00
67 changed files with 802 additions and 135 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ jobs:
path: ./out/artifacts
- name: Upload Sarif
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2
with:
# Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif
+1 -1
View File
@@ -291,7 +291,7 @@ jobs:
"$HOME/.local/bin/claude" --version
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c
uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-session-name: GitHubActions-Claude-${{ github.run_id }}
@@ -15,7 +15,9 @@ permissions:
jobs:
lint:
if: github.event.repository.name != 'systemd-security'
if: >
github.event.repository.name != 'systemd-security' &&
(github.event_name != 'push' || github.repository == 'systemd/systemd')
runs-on: ubuntu-24.04
permissions:
@@ -29,7 +31,7 @@ jobs:
persist-credentials: false
- name: Differential ShellCheck
uses: redhat-plumbers-in-action/differential-shellcheck@d965e66ec0b3b2f821f75c8eff9b12442d9a7d1e
uses: redhat-plumbers-in-action/differential-shellcheck@f51c7c0d32777d00de777131d25918617a246415
with:
# exclude all `.in` files because they may contain unsupported syntax, and they have to be preprocessed first
# TEMPORARY: exclude bash completion files, they would generate too many defects in Code scanning dashboard (600+)
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
steps:
- name: Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64
with:
prerelease: ${{ contains(github.ref_name, '-rc') }}
draft: ${{ github.repository == 'systemd/systemd' }}
+5 -3
View File
@@ -46,6 +46,8 @@ permissions:
jobs:
ci:
# Don't run on pushes to forks, only on pushes to the upstream repositories
if: github.event_name != 'push' || github.repository == 'systemd/systemd' || github.repository == 'systemd/systemd-stable'
runs-on: ${{ matrix.runner || 'ubuntu-24.04' }}
concurrency:
group: ${{ github.workflow }}-${{ matrix.distro }}-${{ matrix.release }}-${{ github.ref }}-${{ matrix.runner || 'ubuntu-24.04' }}
@@ -84,7 +86,7 @@ jobs:
release: "9"
- distro: centos
release: "10"
- distro: postmarketos
- distro: nura
release: edge
libc: musl
skip: TEST-92-TPM2-SWTPM
@@ -95,8 +97,8 @@ jobs:
persist-credentials: false
- uses: systemd/mkosi@71d7b67e01dc47ab5c51f24866c3e2195b9701d2
with:
# Bootstrapping a postmarketOS tools tree on the Ubuntu host needs apk
apk: ${{ matrix.distro == 'postmarketos' }}
# Bootstrapping a Nura tools tree on the Ubuntu host needs apk
apk: ${{ matrix.distro == 'nura' }}
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location
+20 -20
View File
@@ -1,23 +1,23 @@
meson==1.11.2 \
--hash=sha256:698feae069cef3ecd4d7aaf281d7df359bdfcf555a9a1564383d3b913fa8a736 \
--hash=sha256:7e4f6e83fec83e3eaac928e058b073c7557b282c35b6a2024cea143a39926a39
ninja==1.13.0 \
--hash=sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f \
--hash=sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988 \
--hash=sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9 \
--hash=sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630 \
--hash=sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db \
--hash=sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978 \
--hash=sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1 \
--hash=sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72 \
--hash=sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e \
--hash=sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2 \
--hash=sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9 \
--hash=sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714 \
--hash=sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200 \
--hash=sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c \
--hash=sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5 \
--hash=sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96 \
--hash=sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1 \
--hash=sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa \
--hash=sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e
ninja==1.13.2 \
--hash=sha256:09de9ab04f7352f51570c73fd4913acb1e6c24be0a72cd8b80243d4d3ed04925 \
--hash=sha256:0e083700470c02ca154a855ae6d692d03564f5064cae52e113896f9ccc078418 \
--hash=sha256:1293f4078278b70d0ee4b6cc8f3a9e030656c9b2f59909970343c4fe76070118 \
--hash=sha256:1684c60d031c54c1d049541b64243c0c567dca5463dbd77682a8901780af293d \
--hash=sha256:1db9852e528efa7702f5123969f86678663e46d57ff28ab13f5fd84d64a85fb1 \
--hash=sha256:227cbc3ae3e5e429692388103cae8c09451df086cd2d342dae0795af0d162547 \
--hash=sha256:525bfa3fc88aa30a4467df270fd5be6f9fcae8061d54d4df74ea1dc5abd5a975 \
--hash=sha256:59d71c3e15b6b6f3d903eb0c27285544e0747ca59925ada7037bb1af781ad4b3 \
--hash=sha256:65a24341b5ac09fcadcc37082660be40a94174e51a937fabf6e2cae26225fa2c \
--hash=sha256:6a87bf42b123abe2f37737300185f0a303a891899da85d73a3613ee80547e578 \
--hash=sha256:792cadbb9decfd1f776d4d0a6930feb46d08302eb57c176bcf26b09de5748e9f \
--hash=sha256:81d95081c0ad7c95f67bf682220361ed2a32659d7861b4766b03433c58f22516 \
--hash=sha256:915bd482c4be41c75120fd67a22e0bb3f0fbb3bbc5f95b89787deadd59e27ef2 \
--hash=sha256:919572cbc3f233261ecd41fe1f3efc9d44aa02464a4588867e06a8b4f6f416ea \
--hash=sha256:aa3d2ae5706a2c4d1e93edc951d1c6cbb45107413c404f8fde1741239efbc9a0 \
--hash=sha256:b2f687437fac460b27b7eadc99039b1163016fb4ba7276e2782a192d9f24ee0e \
--hash=sha256:d775a5e43e9088f507a6250d57fcf5678eb31268c545feb5064ffeee33735622 \
--hash=sha256:f90f84affc441e219f15fe52532806c1c9dbd22fb66c3addddce88a3deaabab7 \
--hash=sha256:fd82e26c0706ad4ab88e5fdd26f3fab0a987a90f810160f6c322e752c6af298b
+3 -3
View File
@@ -63,7 +63,7 @@ jobs:
run: sudo --preserve-env=GITHUB_ACTIONS,CI,CROSS_ARCH .github/workflows/unit-tests.sh RUN_${{ matrix.run_phase }}
build-musl:
name: Build & test (musl, postmarketOS)
name: Build & test (musl, Nura)
runs-on: ubuntu-24.04
concurrency:
group: ${{ github.workflow }}-musl-${{ github.ref }}
@@ -76,14 +76,14 @@ jobs:
- uses: systemd/mkosi@71d7b67e01dc47ab5c51f24866c3e2195b9701d2
with:
# Bootstrapping a postmarketOS tools tree on the Ubuntu host needs apk
# Bootstrapping a Nura tools tree on the Ubuntu host needs apk
apk: true
- name: Build tools tree
run: |
tee mkosi/mkosi.local.conf <<EOF
[Build]
ToolsTreeDistribution=postmarketos
ToolsTreeDistribution=nura
EOF
mkosi -f box -- true
+88
View File
@@ -0,0 +1,88 @@
# ANCIENT-MOD: running on old kernels (target: 4.19)
Upstream requires kernel ≥ 5.10 (see `README`, "REQUIREMENTS") and dropped the fallback code for
older kernels. This branch restores or adds fallbacks so the system can at least boot on 4.19.
Code touched by this effort is marked with `ANCIENT-MOD` comments where practical.
Legend: **revert** = reverse-applied an upstream commit (possibly adjusted), **new** = new code
because upstream code was refactored since the fallback was removed.
## Boot-critical
| Area | Kernel feature | Change | Where |
|---|---|---|---|
| Mount point checks (`is_mount_point_at()`, `path_is_mount_point()`), used by early `mount_setup()` for `/proc`, `/sys`, `/dev` with `MNT_FATAL` | `STATX_ATTR_MOUNT_ROOT` (5.8) | **new**: `xstatx_full()` emulates the attribute when it is required but missing: compares the mount id (from `/proc/self/fdinfo`) of the inode with its parent's (`..` for directories, parent path for others); same inode as parent ⇒ root ⇒ mount point. Replaces upstream fallback removed in `a98a6eb95c`. | `src/basic/stat-util.c` (`xstatx_emulate()`) |
| `chase()` (used everywhere), `path_get_mnt_id_at()`, `fds_inode_and_mount_same()`, `XSTATX_MNT_ID_BEST` | `STATX_MNT_ID` (5.8/5.10) | **new**: same emulation fills `stx_mnt_id` from `/proc/self/fdinfo/<fd>` `mnt_id:` (available since 3.15). Replaces removals in `7ecfa87c56`, `e5a3127339`. | `src/basic/stat-util.c` |
| cgroup2 mount | `memory_recursiveprot` (5.7) | **revert** (adjusted) of `80c5b63db5`: option is probed again instead of always passed; if it cannot be probed because `fsopen()` is missing (< 5.2) it is not used. | `src/shared/mount-setup.c` |
| `mount_option_supported()` | `fsopen()` (5.2) | **revert** of part of `c2198d0c3f`: return `-EAGAIN` ("don't know") when the new mount API is unavailable. | `src/basic/mountpoint-util.c` |
| `close_all_fds*()` (every fork/exec, `systemd-executor`) | `close_range()` (5.9) | **revert** of `c471cca093` and `d58c826c54`: fall back to iterating `/proc/self/fd` (or the frugal loop). | `src/basic/fd-util.c`, `src/basic/fd-util.h`, `src/test/test-fd-util.c` |
| `pidref_set_pid()` (every process PID1 tracks, `safe_fork()`, `posix_spawn_wrapper()`) | `pidfd_open()` (5.3) | **revert** (adjusted) of part of `6e14c46bac`: ENOSYS ⇒ PidRef without fd (plain PID). | `src/basic/pidref.c` |
| `pidfd_open()` shim (all pidfd users), `pidfd_waitid()` | `waitid(P_PIDFD)` (5.4) | **new**: vendor kernels (Android 4.19) backport `pidfd_open()` but not `waitid(P_PIDFD)`, so every wait failed with EINVAL (PID1 froze after generators). The shim probes once on a pidfd of self that `pidfd_send_signal()` and `poll()` work (without pidfd poll support a live process reports readable); if not, `pidfd_open()` returns ENOSYS so the plain-PID fallbacks above apply. Waits go through `pidfd_waitid()`, which probes `waitid(P_PIDFD)` (ECHILD = supported, EINVAL = not) and otherwise uses `waitid(P_PID)` with the known PID (safe for children: the PID cannot be reused before reaping). Keeping pidfds is required by logind, which since v258 refuses sessions whose leader has no pidfd (`NoSessionPIDFD`). | `src/libc/pidfd.c`, `src/include/override/sys/pidfd.h`, `src/basic/pidref.c`, `src/libsystemd/sd-event/sd-event.c` |
| `pidref_wait_for_terminate_full()` with timeout | pidfd (5.3) | **new**: without pidfd poll `waitid(P_PID, …, WNOHANG)` every 10 ms instead of returning `-ENOMEDIUM`. | `src/basic/pidref.c` |
| `pidfd_check_pidfs()`, `pidfd_info_mask_is_supported()`, `pidfd_get_inode_id_self_cached()` | pidfd (5.3) | **revert**/new: ENOSYS ⇒ "not supported" instead of hard error. | `src/basic/pidfd-util.c` |
| sd-event child sources (`sd_event_add_child()`, used by udevd, logind, …) | pidfd (5.3), `waitid(P_PIDFD)` (5.4) | **new** (upstream removed the non-pidfd path in `6e14c46bac` and later made the code pidfd-only): if `pidfd_open()` is unsupported the source works on the PID via `waitid(P_PID)` + SIGCHLD signalfd. SIGCHLD is blocked automatically in that case (upstream no longer requires callers to block it). `send_child_signal()` falls back to `kill()`/`rt_sigqueueinfo()`; `set_child_pidfd_own()` returns `-EOPNOTSUPP` without pidfd. | `src/libsystemd/sd-event/sd-event.c` |
| `pam_systemd` session creation | pidfd (5.3) | **revert** of part of `6e14c46bac`: fall back to `CreateSession` (PID based). Ineffective on its own: logind (Varlink and D-Bus) rejects leaders without pidfd, so sessions need a kernel with `pidfd_open()` + pidfd poll. | `src/login/pam_systemd.c` |
| Unit cgroup-empty tracking (`unit_check_cgroup_events()`) | `frozen` key in `cgroup.events` (5.2) | **new**: if the key is missing, read only `populated`. Without this every cgroup event read failed and stopped units were never noticed as empty. | `src/core/cgroup.c` |
| Freeze/thaw | cgroup v2 freezer (5.2) | **revert** of `3c86a935ad`: `cg_freezer_supported()` restored; freeze is `-EOPNOTSUPP` / no-op when `cgroup.freeze` is absent. | `src/basic/cgroup-util.[ch]`, `src/core/cgroup.c`, `src/core/unit.c` |
| Credentials (`LoadCredential=`, `SetCredential=`, `ImportCredential=` — used by many stock units) | new mount API `fsopen`/`fsmount`/`move_mount` (5.2) | **new**: if the credentials fs cannot be created because the API is missing, use the existing "plain directory" fallback (previously only used on EPERM). | `src/core/exec-credential.c` |
| `ProtectProc=` / `ProcSubset=` (used by logind, networkd, timesyncd, hostnamed, …) | per-instance procfs, textual `hidepid=`, `subset=` (5.8) | **new**: on kernels < 5.8 the options are ignored (they would either fail with EINVAL or, worse, change the host's shared `/proc` superblock). `/proc/sys` & friends are then still protected by the normal ProtectKernel* mounts. Upstream removed the old fallback in `0cba5bdcf1`. | `src/core/namespace.c` |
| `RootDirectory=` | `open_tree()` (5.2) | **new**: tolerate ENOSYS when cloning the root directory mount and use the classic bind mount path. | `src/core/namespace.c` |
| `futimens_opath()`, `access_fd()` | `AT_EMPTY_PATH` for `utimensat()`/`faccessat()` (5.8) | **revert** of `52bf232e82` (manually): fall back to `/proc/self/fd/<fd>`. | `src/basic/fs-util.c` |
## Networking
| Area | Kernel feature | Change | Where |
|---|---|---|---|
| `socket_bind_to_ifindex()` (DHCP client, resolved, networkd, …) | `SO_BINDTOIFINDEX` (5.1) | **revert** of `ddbbc98bd5` (manually): fall back to `SO_BINDTODEVICE`. | `src/basic/socket-util.c` |
| `rtnl_resolve_ifname_full()` (alternative names) | `IFLA_ALT_IFNAME` lookup (5.5) | **revert** of `42b09813f4`: treat EINVAL like ENODEV. | `src/libsystemd/sd-netlink/netlink-util.c` |
| networkd startup enumeration | nexthop (5.3) | **revert** of `034b69d8b8` (manually): ignore `-EOPNOTSUPP` from nexthop enumeration, otherwise networkd refuses to start. | `src/network/networkd-manager.c` |
| networkd permanent MAC address | `IFLA_PERM_ADDRESS` (5.6) | **revert** of `04f05d9bd7`: fall back to ethtool. | `src/network/networkd-link.c` |
| IPv6 DNAT (nspawn port forwarding / firewall-util) | nft concatenation fix (5.8) | **revert** of `58fb46ecd5` (manually): `-EOVERFLOW` ⇒ `-EOPNOTSUPP`. | `src/shared/firewall-util.c` |
## Other
| Area | Kernel feature | Change | Where |
|---|---|---|---|
| `SurviveFinalKillSignal=` | `user.*` xattrs on cgroupfs (5.7) | **revert** of `8292b859f3`: fall back to `trusted.survive_final_kill_signal`. | `src/core/cgroup.c`, `src/shared/killall.c` |
| Loop devices via `LOOP_SET_STATUS64` fallback | buffer cache invalidation bug (fixed in 5.0) | **revert** of `5e3887e6c1`: issue `BLKFLSBUF` when offset/size is set. | `src/shared/loop-util.c` |
## Known remaining gaps (not addressed)
- **cgroup v1 is gone upstream**: the kernel must boot with a cgroup v2 hierarchy. 4.19's cgroup v2
lacks the `cpuset` (5.0) and `freezer` (5.2) controllers, `cgroup.kill` (5.14, already graceful).
- **PSI** (4.20): `systemd-oomd` does not work; memory-pressure event sources are already optional.
- **BPF**: features needing BPF links / BPF LSM / bounded loops (5.3–5.7) — `RestrictFileSystems=`,
`RestrictNetworkInterfaces=`, `SocketBind*=`, `BindNetworkInterface=`, … — report "not supported"
(upstream probing, `ef12eadfc8`).
- **New mount API without fallback** (5.2/5.12): `PrivateBPF=`, `ExtensionImages=`/`ExtensionDirectories=`
(overlay via `fsopen`), `MountImages=`, runtime `systemctl bind`/`mount-image`, idmapped mounts,
mountfsd, nsresourced, sysext/confext, homed (also needs fscrypt v2 / 5.4), coredump's mount of
the crashed process' root.
- **`MS_NOSYMFOLLOW`** (5.10) is passed as a legacy `mount(2)` flag; older kernels silently ignore
unknown flags, so the mount just lacks `nosymfollow`.
- **Credentials** use a plain directory instead of a dedicated (noswap) tmpfs, i.e. less isolation.
- **Per-device IO weight** (`IODeviceWeight=`, BFQ per-device weight, 5.4): upstream dropped the
EINVAL workaround (`00c4851af0`), expect warnings when used.
- **udev net_id** for IP-over-InfiniBand (`dev_port`, 4.20): `d3d375a686` not reverted; multi-port
IPoIB devices may get colliding names.
- `test-event`'s `test_pidfd` inherently requires pidfds and fails without them; it and
`test_child_pidfd_wnowait` also call `waitid(P_PIDFD)` directly and fail without it.
- logind sessions require pidfds (see `pam_systemd` row); on kernels without `pidfd_open()` no
login session can be created.
- Anything else newer than 5.10 listed in `README` as "recommended baseline" is expected to fall
back gracefully upstream, but that has not been verified on a real old kernel.
## Testing done
- Full native test suite (`meson test -C build`) on a 7.x kernel.
- Selected tests (`test-stat-util`, `test-mountpoint-util`, `test-chase`, `test-fs-util`,
`test-fd-util`, `test-pidref`, `test-process-util`, `test-socket-util`, `test-mount-util`,
`test-udev-spawn`, `test-async`, `test-event` except `test_pidfd`) and `systemd --test --system`
(with the built generators) under an `LD_PRELOAD` shim that simulates an old kernel: strips
`STATX_MNT_ID*`/`STATX_ATTR_MOUNT_ROOT` from `statx()` results and makes `pidfd_open`,
`pidfd_send_signal`, `pidfd_spawn`, `close_range` and the new mount API return ENOSYS.
- `test-pidref`, `test-process-util`, `test-event` (except `test_pidfd`, `test_child_pidfd_wnowait`)
under an `LD_PRELOAD` shim that only makes `waitid(P_PIDFD)` fail with EINVAL (Android 4.19
vendor kernel case: pidfds stay enabled, waits use the `P_PID` fallback).
- Booted on an Android 4.19 vendor kernel (Xiaomi vince): reaches `graphical.target`; login
sessions not verified yet.
+8
View File
@@ -72,6 +72,14 @@ dmi:bvnLENOVO*
dmi:bvnMicrosoft Corporation*:pvrSurface with Windows 8 Pro*
ID_CHASSIS=tablet
# Microsoft Surface Go 3 is a detachable, but reports chassis type 9 (Laptop)
dmi:*:svnMicrosoftCorporation:pnSurfaceGo3:*
ID_CHASSIS=convertible
# GPD Pocket 4 chassis type
dmi:bvnAmericanMegatrendsInternational*:rvnGPD:rnG1628-04*
ID_CHASSIS=convertible
# Google Pixelbook (Eve) is a convertible, but reports chassis type 3 (Desktop)
dmi:*:svnGoogle:pnEve:*
ID_CHASSIS=convertible
+9
View File
@@ -1023,6 +1023,15 @@ evdev:input:b0003v2179p0004*
EVDEV_ABS_00=::234
EVDEV_ABS_01=::328
#########################################
# VEIKK
#########################################
# VEIKK A15 Pro
evdev:input:b0003v2FEBp0006*
EVDEV_ABS_00=::129
EVDEV_ABS_01=::215
#########################################
# Waltop
#########################################
+10
View File
@@ -139,3 +139,13 @@ id-input:modalias:input:b0003v06A3p0763*
# PXN HB S handbrake
id-input:modalias:input:b0003v11FFpA701*
ID_INPUT_JOYSTICK=1
# Retoo E803 Air Mouse
id-input:usb:v1915p1025:name:*Consumer Control*:*
ID_INPUT_TABLET=0
ID_INPUT_TABLET_PAD=0
# Samsung Galaxy Book2 Go internal keyboard
id-input:modalias:input:b0018v0CF2p9028e0100-e0,1,2,3,4*
ID_INPUT_TABLET=
ID_INPUT_TABLET_PAD=
+29
View File
@@ -345,6 +345,15 @@ evdev:name:AT Translated Set 2 keyboard:dmi:*:svnAYANEO:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*BenQ*:pn*Joybook*R22*:*
KEYBOARD_KEY_6e=wlan
###########################################################
# Casper
###########################################################
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*CASPER*:pn*NIRVANA*:*
KEYBOARD_KEY_a0=!mute
KEYBOARD_KEY_ae=!volumedown
KEYBOARD_KEY_b0=!volumeup
###########################################################
# Clevo
###########################################################
@@ -639,6 +648,21 @@ evdev:input:b0003v18D1p8001*
evdev:input:b0003v18D1p8007*
KEYBOARD_KEY_b002f=reserved # Disable micmute key
# Google Pixelbook (Eve)
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGoogle:pnEve:*
KEYBOARD_KEY_3b=back # F1 Back
KEYBOARD_KEY_3c=refresh # F2 Refresh
KEYBOARD_KEY_3d=zoom # F3 Fullscreen
KEYBOARD_KEY_3e=scale # F4 Overview
KEYBOARD_KEY_3f=brightnessdown # F5 Brightness down
KEYBOARD_KEY_40=brightnessup # F6 Brightness up
KEYBOARD_KEY_41=playpause # F7 Play/Pause
KEYBOARD_KEY_42=mute # F8 Mute
KEYBOARD_KEY_43=volumedown # F9 Volume down
KEYBOARD_KEY_44=volumeup # F10 Volume up
KEYBOARD_KEY_5d=controlpanel # Menu key
KEYBOARD_KEY_d8=assistant # Assistant key
###########################################################
# Haier
###########################################################
@@ -1176,6 +1200,11 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn21N5*:pvrThinkBook16pG5IRX:*
evdev:name:Ideapad extra buttons:dmi:*:svnLENOVO:pn21MV:pvrThinkBook14G7ARP:*
KEYBOARD_KEY_13e=unknown # Fn+F4 mic mute, also emitted as scan code 0x8, ignore
# Lenovo ThinkBook 16 G7 ARP (Type 21MW)
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn21MW*:pvr*
KEYBOARD_KEY_ae=!volumedown
KEYBOARD_KEY_b0=!volumeup
evdev:atkbd:dmi:*:svnLENOVO:*:pvrLenovoYoga300-11IBR:*
KEYBOARD_KEY_62=unknown # Touchpad on, also emitted by "Ideapad extra buttons", ignore
KEYBOARD_KEY_63=unknown # Touchpad off, also emitted by "Ideapad extra buttons", ignore
+7
View File
@@ -794,6 +794,13 @@ sensor:modalias:acpi:KIOX000A:*:dmi:*:rvnMETAPHYUNI:rnMetawillBook01:* # Meta
sensor:modalias:acpi:KIOX000A:*:dmi:*:svnMicrotech:pne-tabPro:* # Microtech e-tab Pro
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
#########################################
# Minisforum
#########################################
sensor:modalias:acpi:SMOCF05:*:dmi:*:svnMicroComputer(HK)TechLimited:pnV3*:* # V3, V3 SE
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, 1
#########################################
# MPMAN
#########################################
+15
View File
@@ -253,6 +253,21 @@ usb:v17CCp1130*
usb:v17CCp2420*
ID_AV_PRODUCTION_CONTROLLER=1
####################
# PCPanel
####################
# PCPanel Mini
usb:v0483pA3C4*
ID_AV_PRODUCTION_CONTROLLER=1
# PCPanel Pro
usb:v0483pA3C5*
ID_AV_PRODUCTION_CONTROLLER=1
# PCPanel RGB
usb:v04D8pEB52*
ID_AV_PRODUCTION_CONTROLLER=1
####################
# Pioneer
####################
+1 -1
View File
@@ -1 +1 @@
262
262.1
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=postmarketos
Distribution=nura
[Distribution]
Release=edge
@@ -1,4 +1,4 @@
# postmarketOS does not support userdbd, so creating the test user via
# Nura does not support userdbd, so creating the test user via
# userdbd credentials does not work. We need to create the user entries
# in /etc/passwd and /etc/group using sysusers instead.
u testuser 4711 testuser /home/testuser /bin/bash
@@ -1,4 +1,4 @@
# postmarketOS does not support userdbd, so creating the test user via
# Nura does not support userdbd, so creating the test user via
# userdbd credentials does not work. We need to create the user's home
# directory using tmpfiles instead.
Q /home/testuser 0700 testuser testuser - -
@@ -19,7 +19,7 @@ enable systemd-networkd-wait-online.service
# systemd-resolved is disabled by default on CentOS so make sure it is enabled.
enable systemd-resolved.service
# systemd-time-wait-sync.service is enabled by default on postmarketOS.
# systemd-time-wait-sync.service is enabled by default on Nura.
# It pulls in time-sync.target, but the target is never reached because the
# test environment has no Internet connectivity. As a result, timer units
# cannot be started. Disable the service explicitly to allow timer units to
@@ -69,11 +69,11 @@ disable multipathd.service
# https://github.com/opensvc/multipath-tools/commit/346e9adda4e5f0ccfcbb7a3eccf5f96001d95027
disable multipathd.socket
# rtkit-daemon.service randomly fails with the following error on postmarketOS:
# rtkit-daemon.service randomly fails with the following error on Nura:
# rtkit-daemon[54]: pthread_create failed: Resource temporarily unavailable
# The service is not necessary on our test suites, let's disable it.
disable rtkit-daemon.service
# Disable postmarketOS specific zram swap service.
# Disable Nura specific zram swap service.
# Maybe better to replace it with zram-generator?
disable zram_swap.service
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=postmarketos
Distribution=nura
[Content]
Packages=
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=postmarketos
Distribution=nura
[Content]
Packages=
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=postmarketos
Distribution=nura
[Content]
Packages=
@@ -1,12 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=postmarketos
Distribution=nura
[Build]
Environment=
GIT_URL=https://gitlab.postmarketos.org/postmarketOS/pmaports
GIT_SUBDIR=extra-repos/systemd/systemd
GIT_BRANCH=main
GIT_COMMIT=f908244ec2a0f85a84f44927183711160a798705
PKG_SUBDIR=postmarketos
GIT_COMMIT=7a6b81a4f1a7a510d088a5874bebcf2b200b69b3
PKG_SUBDIR=nura
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=postmarketos
Distribution=nura
[Content]
PrepareScripts=%D/mkosi/mkosi.images/build/mkosi.conf.d/postmarketos/mkosi.prepare
PrepareScripts=%D/mkosi/mkosi.images/build/mkosi.conf.d/nura/mkosi.prepare
Packages=
alpine-sdk
postmarketos-base
+17
View File
@@ -206,6 +206,23 @@ bool cg_kill_supported(void) {
return (supported = false);
}
/* ANCIENT-MOD: cgroup v2 freezer is available since kernel 5.2 */
bool cg_freezer_supported(void) {
static thread_local int supported = -1;
if (supported >= 0)
return supported;
if (cg_is_available() <= 0)
return (supported = false);
if (access("/sys/fs/cgroup/init.scope/cgroup.freeze", F_OK) >= 0)
return (supported = true);
if (errno != ENOENT)
log_debug_errno(errno, "Failed to check whether cgroup freezer is available, assuming not: %m");
return (supported = false);
}
int cg_enumerate_subgroups(const char *path, DIR **ret) {
_cleanup_free_ char *fs = NULL;
DIR *d;
+1
View File
@@ -235,6 +235,7 @@ int cg_mask_from_string(const char *s, CGroupMask *ret);
int cg_mask_to_string(CGroupMask mask, char **ret);
bool cg_kill_supported(void);
bool cg_freezer_supported(void);
DECLARE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);
+78 -14
View File
@@ -260,9 +260,10 @@ int close_all_fds_frugal(const int except[], size_t n_except) {
assert(except || n_except == 0);
/* This is the inner fallback core of close_all_fds(). This never calls malloc() or so and hence is
* safe to be called in signal handler context. Most users should call close_all_fds(), but when we
* assume we are called from signal handler context, then use this simpler call instead. */
/* This is the inner fallback core of close_all_fds(). This never calls malloc() or opendir() or so
* and hence is safe to be called in signal handler context. Most users should call close_all_fds(),
* but when we assume we are called from signal handler context, then use this simpler call
* instead. */
max_fd = get_max_fd();
if (max_fd < 0)
@@ -288,6 +289,44 @@ int close_all_fds_frugal(const int except[], size_t n_except) {
return r;
}
int close_all_fds_by_proc(const int except[], size_t n_except) {
_cleanup_closedir_ DIR *d = NULL;
int r = 0;
d = opendir("/proc/self/fd");
if (!d)
return close_all_fds_frugal(except, n_except); /* ultimate fallback if /proc/ is not available */
FOREACH_DIRENT(de, d, return -errno) {
int fd = -EBADF, q;
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
continue;
fd = parse_fd(de->d_name);
if (fd < 0)
/* Let's better ignore this, just in case */
continue;
if (fd < 3)
continue;
if (fd == dirfd(d))
continue;
if (fd_in_set(fd, except, n_except))
continue;
q = close_nointr(fd);
if (q != -EBADF) /* Valgrind has its own FD and doesn't want to have it closed */
RET_GATHER(r, q);
}
return r;
}
static bool have_close_range = true; /* Assume we live in the future */
static int close_all_fds_special_case(const int except[], size_t n_except) {
assert(n_except == 0 || except);
@@ -295,6 +334,9 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
* nicely, since we won't need sorting for them. Returns > 0 if the special casing worked, 0
* otherwise. */
if (!have_close_range)
return 0;
if (n_except == 1 && except[0] < 0) /* Minor optimization: if we only got one fd, and it's invalid,
* we got none */
n_except = 0;
@@ -303,23 +345,32 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
case 0:
/* Close everything. Yay! */
if (close_range(3, INT_MAX, 0) < 0)
return -errno;
if (close_range(3, INT_MAX, 0) >= 0)
return 1;
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
have_close_range = false;
return 0;
}
return -errno;
case 1:
/* Close all but exactly one, then we don't need no sorting. This is a pretty common
* case, hence let's handle it specially. */
if (except[0] > 3 && close_range(3, except[0] - 1, 0) < 0)
return -errno;
if (except[0] < INT_MAX && close_range(MAX(3, except[0] + 1), -1, 0) < 0)
return -errno;
if ((except[0] <= 3 || close_range(3, except[0]-1, 0) >= 0) &&
(except[0] >= INT_MAX || close_range(MAX(3, except[0]+1), -1, 0) >= 0))
return 1;
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
have_close_range = false;
return 0;
}
return -errno;
default:
return 0;
}
@@ -350,6 +401,9 @@ int close_all_fds(const int except[], size_t n_except) {
if (r > 0) /* special case worked! */
return 0;
if (!have_close_range)
return close_all_fds_by_proc(except, n_except);
_cleanup_free_ int *sorted_malloc = NULL;
size_t n_sorted;
int *sorted;
@@ -369,7 +423,7 @@ int close_all_fds(const int except[], size_t n_except) {
sorted = newa(int, n_sorted);
if (!sorted) /* Fallback on OOM. */
return close_all_fds_frugal(except, n_except);
return close_all_fds_by_proc(except, n_except);
memcpy(sorted, except, n_except * sizeof(int));
@@ -391,8 +445,13 @@ int close_all_fds(const int except[], size_t n_except) {
continue;
/* Close everything between the start and end fds (both of which shall stay open) */
if (close_range(start + 1, end - 1, 0) < 0)
if (close_range(start + 1, end - 1, 0) < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
have_close_range = false;
return close_all_fds_by_proc(except, n_except);
}
}
/* The loop succeeded. Let's now close everything beyond the end */
@@ -400,9 +459,14 @@ int close_all_fds(const int except[], size_t n_except) {
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
return 0;
if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) < 0)
if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
have_close_range = false;
return close_all_fds_by_proc(except, n_except);
}
return 0;
}
+1
View File
@@ -127,6 +127,7 @@ int get_max_fd(void);
int close_all_fds(const int except[], size_t n_except);
int close_all_fds_without_malloc(const int except[], size_t n_except);
int close_all_fds_by_proc(const int except[], size_t n_except);
int close_all_fds_frugal(const int except[], size_t n_except);
int pack_fds(int fds[], size_t n);
+28 -2
View File
@@ -322,7 +322,20 @@ int futimens_opath(int fd, const struct timespec ts[2]) {
assert(fd >= 0);
return RET_NERRNO(utimensat(fd, "", ts, AT_EMPTY_PATH));
if (utimensat(fd, "", ts, AT_EMPTY_PATH) >= 0)
return 0;
if (errno != EINVAL)
return -errno;
/* ANCIENT-MOD: AT_EMPTY_PATH is supported since kernel 5.8, fall back to /proc/self/fd/ */
if (utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, /* flags= */ 0) < 0) {
if (errno != ENOENT)
return -errno;
return proc_fd_enoent_errno();
}
return 0;
}
int stat_warn_permissions(const char *path, const struct stat *st) {
@@ -371,7 +384,20 @@ int access_fd(int fd, int mode) {
assert(fd >= 0);
return RET_NERRNO(faccessat(fd, "", mode, AT_EMPTY_PATH));
if (faccessat(fd, "", mode, AT_EMPTY_PATH) >= 0)
return 0;
if (errno != EINVAL)
return -errno;
/* ANCIENT-MOD: AT_EMPTY_PATH is supported since kernel 5.8, fall back to /proc/self/fd/ */
if (access(FORMAT_PROC_FD_PATH(fd), mode) < 0) {
if (errno != ENOENT)
return -errno;
return proc_fd_enoent_errno();
}
return 0;
}
int touch_fd(int fd, usec_t stamp) {
+2
View File
@@ -681,6 +681,8 @@ int mount_option_supported(const char *fstype, const char *key, const char *valu
if (fd < 0) {
if (errno == ENODEV)
return log_debug_errno(errno, "Kernel does not support file system type '%s'.", fstype);
if (ERRNO_IS_NOT_SUPPORTED(errno))
return -EAGAIN; /* ANCIENT-MOD: new mount API not available (kernel < 5.2) → don't know */
return log_debug_errno(errno, "Failed to open superblock context for '%s': %m", fstype);
}
+10 -2
View File
@@ -28,8 +28,11 @@ int pidfd_check_pidfs(int pid_fd) {
_cleanup_close_ int our_fd = -EBADF;
if (pid_fd < 0) {
our_fd = pidfd_open(getpid_cached(), /* flags= */ 0);
if (our_fd < 0)
if (our_fd < 0) {
if (ERRNO_IS_NOT_SUPPORTED(errno)) /* ANCIENT-MOD: kernel < 5.3 */
return (have_pidfs = false);
return -errno;
}
pid_fd = our_fd;
}
@@ -102,6 +105,8 @@ int pidfd_info_mask_is_supported(uint64_t mask) {
if (cached == 0) {
_cleanup_close_ int pidfd = r = RET_NERRNO(pidfd_open(getpid_cached(), /* flags= */ 0));
if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) /* ANCIENT-MOD: kernel < 5.3 */
return (cached = -EOPNOTSUPP);
if (r < 0)
return r;
@@ -334,8 +339,11 @@ int pidfd_get_inode_id_self_cached(uint64_t *ret) {
return initialized;
_cleanup_close_ int fd = pidfd_open(getpid_cached(), 0);
if (fd < 0)
if (fd < 0) {
if (ERRNO_IS_NOT_SUPPORTED(errno)) /* ANCIENT-MOD: kernel < 5.3 */
return (initialized = -EOPNOTSUPP);
return -errno;
}
r = pidfd_get_inode_id(fd, &cached);
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
+28 -9
View File
@@ -106,9 +106,10 @@ int pidref_set_pid_full(PidRef *pidref, pid_t pid, unsigned flags) {
fd = pidfd_open(pid, flags);
if (fd < 0) {
/* Graceful fallback in case the kernel is out of fds.
/* Graceful fallback in case the kernel is out of fds or lacks pidfd_open() (ANCIENT-MOD: < 5.3).
* The PIDFD_THREAD flag is supported since kernel v6.9 (64bef697d33b75fc06c5789b3f8108680271529f). */
if (!(ERRNO_IS_RESOURCE(errno) || (errno == EINVAL && FLAGS_SET(flags, PIDFD_THREAD))))
if (!(ERRNO_IS_RESOURCE(errno) || ERRNO_IS_NOT_SUPPORTED(errno) ||
(errno == EINVAL && FLAGS_SET(flags, PIDFD_THREAD))))
return log_debug_errno(errno, "Failed to open pidfd for pid " PID_FMT ": %m", pid);
fd = -EBADF;
@@ -468,16 +469,34 @@ int pidref_wait_for_terminate_full(PidRef *pidref, usec_t timeout, siginfo_t *re
if (pidref->pid == 1 || pidref_is_self(pidref))
return -ECHILD;
if (pidref->fd < 0 && (timeout != USEC_INFINITY || fiber_ops_is_set()))
return -ENOMEDIUM;
usec_t ts = timeout == USEC_INFINITY ? USEC_INFINITY : usec_add(now(CLOCK_MONOTONIC), timeout);
/* ANCIENT-MOD: no pidfd (kernel < 5.3), poll with waitid(WNOHANG) to honour the timeout */
if (pidref->fd < 0 && ts != USEC_INFINITY)
for (;;) {
siginfo_t si = {};
r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, WEXITED|WNOHANG));
if (r == -EINTR)
continue;
if (r < 0)
return r;
if (si.si_pid != 0) {
if (ret_si)
*ret_si = si;
return 0;
}
if (now(CLOCK_MONOTONIC) >= ts)
return -ETIMEDOUT;
(void) usleep_safe(10 * USEC_PER_MSEC);
}
/* Poll the pidfd before waitid() if either there's a finite timeout (so we can honor it) or
* we're on a fiber (so fd_wait_for_event() can suspend us instead of blocking the event loop
* inside waitid()). Otherwise let waitid() block directly. The precondition above guarantees
* pidref->fd >= 0 in both cases. */
bool poll_first = ts != USEC_INFINITY || fiber_ops_is_set();
* inside waitid()). Otherwise let waitid() block directly. */
bool poll_first = pidref->fd >= 0 && (ts != USEC_INFINITY || fiber_ops_is_set());
for (;;) {
if (poll_first) {
@@ -503,7 +522,7 @@ int pidref_wait_for_terminate_full(PidRef *pidref, usec_t timeout, siginfo_t *re
siginfo_t si = {};
if (pidref->fd >= 0)
r = RET_NERRNO(waitid(P_PIDFD, pidref->fd, &si, WEXITED));
r = RET_NERRNO(pidfd_waitid(pidref->fd, pidref->pid, &si, WEXITED));
else
r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, WEXITED));
if (r >= 0) {
+13 -1
View File
@@ -1419,13 +1419,25 @@ int socket_bind_to_ifname(int fd, const char *ifname) {
}
int socket_bind_to_ifindex(int fd, int ifindex) {
char ifname[IF_NAMESIZE];
int r;
assert(fd >= 0);
if (ifindex <= 0)
/* Drop binding */
return RET_NERRNO(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0));
return setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex);
r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex);
if (r != -ENOPROTOOPT)
return r;
/* ANCIENT-MOD: fall back to SO_BINDTODEVICE on kernels < 5.1 which didn't have SO_BINDTOIFINDEX */
r = format_ifname(ifindex, ifname);
if (r < 0)
return r;
return socket_bind_to_ifname(fd, ifname);
}
int socket_autobind(int fd, char **ret_name) {
+111
View File
@@ -11,14 +11,17 @@
#include "dirent-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "filesystems.h"
#include "fs-util.h"
#include "hash-funcs.h"
#include "log.h"
#include "mountpoint-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "siphash24.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "time-util.h"
@@ -413,6 +416,102 @@ static const char* statx_attribute_to_name(uint64_t attr);
DEFINE_STATX_BITS_TO_STRING(statx_mask, unsigned, statx_mask_one_to_name, "0x%x");
DEFINE_STATX_BITS_TO_STRING(statx_attributes, uint64_t, statx_attribute_to_name, "0x%" PRIx64);
/* ANCIENT-MOD: emulation of STATX_MNT_ID and STATX_ATTR_MOUNT_ROOT for kernels < 5.8 */
static int fd_fdinfo_mnt_id(int fd, uint64_t *ret) {
char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *p = NULL;
int r;
assert(fd >= 0);
assert(ret);
xsprintf(path, "/proc/self/fdinfo/%i", fd);
r = get_proc_field(path, "mnt_id", &p);
if (r == -ENOENT)
return proc_fd_enoent_errno();
if (r == -ENODATA)
return -EUNATCH;
if (r < 0)
return r;
return safe_atou64(p, ret);
}
static int fd_open_parent(int fd, const struct statx *sx) {
_cleanup_free_ char *p = NULL, *d = NULL;
int r;
if (FLAGS_SET(sx->stx_mask, STATX_TYPE) ? S_ISDIR(sx->stx_mode) : fd_verify_directory(fd) >= 0)
return RET_NERRNO(openat(fd, "..", O_PATH|O_DIRECTORY|O_CLOEXEC));
r = fd_get_path(fd, &p);
if (r < 0)
return r;
r = path_extract_directory(p, &d);
if (r < 0)
return r;
return RET_NERRNO(open(d, O_PATH|O_DIRECTORY|O_CLOEXEC));
}
static int xstatx_emulate(
int fd,
const char *path,
int statx_flags,
bool want_mnt_id,
bool want_mount_root,
struct statx *sx) {
_cleanup_close_ int target_fd = -EBADF, parent_fd = -EBADF;
uint64_t mnt_id, parent_mnt_id;
int r;
assert(sx);
if (isempty(path) && fd >= 0)
target_fd = RET_NERRNO(fcntl(fd, F_DUPFD_CLOEXEC, 3));
else
target_fd = RET_NERRNO(openat(fd, isempty(path) ? "." : path,
O_PATH|O_CLOEXEC|(FLAGS_SET(statx_flags, AT_SYMLINK_NOFOLLOW) ? O_NOFOLLOW : 0)));
if (target_fd < 0)
return target_fd;
r = fd_fdinfo_mnt_id(target_fd, &mnt_id);
if (r < 0)
return r;
if (want_mnt_id) {
sx->stx_mnt_id = mnt_id;
sx->stx_mask |= STATX_MNT_ID;
}
if (!want_mount_root)
return 0;
bool is_root = false;
parent_fd = fd_open_parent(target_fd, sx);
if (parent_fd < 0)
log_debug_errno(parent_fd, "Failed to open parent to determine mount root, assuming not a mount root: %m");
else {
struct stat a, b;
r = fd_fdinfo_mnt_id(parent_fd, &parent_mnt_id);
if (r < 0)
return r;
if (mnt_id != parent_mnt_id)
is_root = true;
else if (fstat(target_fd, &a) >= 0 && fstat(parent_fd, &b) >= 0)
is_root = stat_inode_same(&a, &b);
}
SET_FLAG(sx->stx_attributes, STATX_ATTR_MOUNT_ROOT, is_root);
sx->stx_attributes_mask |= STATX_ATTR_MOUNT_ROOT;
return 0;
}
int xstatx_full(int fd,
const char *path,
int statx_flags,
@@ -457,6 +556,18 @@ int xstatx_full(int fd,
&sx) < 0)
return negative_errno();
bool want_mnt_id =
(FLAGS_SET(xstatx_flags, XSTATX_MNT_ID_BEST) && !(sx.stx_mask & (STATX_MNT_ID|STATX_MNT_ID_UNIQUE))) ||
(FLAGS_SET(request_mask, STATX_MNT_ID) && !FLAGS_SET(sx.stx_mask, STATX_MNT_ID));
bool want_mount_root =
FLAGS_SET(mandatory_attributes, STATX_ATTR_MOUNT_ROOT) &&
!FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT);
if (want_mnt_id || want_mount_root) {
r = xstatx_emulate(fd, path, statx_flags, want_mnt_id, want_mount_root, &sx);
if (r < 0)
log_debug_errno(r, "Failed to emulate statx() mount fields, ignoring: %m");
}
if (FLAGS_SET(xstatx_flags, XSTATX_MNT_ID_BEST) &&
!(sx.stx_mask & (STATX_MNT_ID|STATX_MNT_ID_UNIQUE)))
return log_debug_errno(SYNTHETIC_ERRNO(EUNATCH), "statx() did not return either STATX_MNT_ID or STATX_MNT_ID_UNIQUE.");
+41 -4
View File
@@ -937,12 +937,39 @@ static void cgroup_delegate_xattr_apply(Unit *u) {
}
static void cgroup_survive_xattr_apply(Unit *u) {
int r;
assert(u);
if (u->survive_final_kill_signal)
unit_set_xattr_graceful(u, "user.survive_final_kill_signal", "1", 1);
else
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
if (!crt)
return;
if (u->survive_final_kill_signal) {
r = cg_set_xattr(
crt->cgroup_path,
"user.survive_final_kill_signal",
"1",
1,
/* flags= */ 0);
/* user xattr support was added in kernel v5.7 */
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
r = cg_set_xattr(
crt->cgroup_path,
"trusted.survive_final_kill_signal",
"1",
1,
/* flags= */ 0);
if (r < 0)
log_unit_debug_errno(u,
r,
"Failed to set 'survive_final_kill_signal' xattr on control "
"group %s, ignoring: %m",
empty_to_root(crt->cgroup_path));
} else {
unit_remove_xattr_graceful(u, "user.survive_final_kill_signal");
unit_remove_xattr_graceful(u, "trusted.survive_final_kill_signal");
}
}
static void cgroup_xattr_apply(Unit *u) {
@@ -3189,6 +3216,13 @@ static int unit_check_cgroup_events(Unit *u) {
"cgroup.events",
STRV_MAKE("populated", "frozen"),
values);
if (r == -ENXIO)
/* ANCIENT-MOD: the "frozen" key exists only since kernel 5.2 (cgroup v2 freezer) */
r = cg_get_keyed_attribute(
crt->cgroup_path,
"cgroup.events",
STRV_MAKE("populated"),
values);
if (r < 0)
return r;
@@ -3203,7 +3237,7 @@ static int unit_check_cgroup_events(Unit *u) {
/* Disregard freezer state changes due to operations not initiated by us.
* See: https://github.com/systemd/systemd/pull/13512/files#r416469963 and
* https://github.com/systemd/systemd/pull/13512#issuecomment-573007207 */
if (IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_FREEZING_BY_PARENT, FREEZER_THAWING))
if (values[1] && IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_FREEZING_BY_PARENT, FREEZER_THAWING))
unit_freezer_complete(u, streq(values[1], "0") ? FREEZER_RUNNING : FREEZER_FROZEN);
free_many_charp(values, ELEMENTSOF(values));
@@ -4122,6 +4156,9 @@ int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
assert(action >= 0);
assert(action < _FREEZER_ACTION_MAX);
if (!cg_freezer_supported())
return 0;
unit_next_freezer_state(u, action, &next, &objective);
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
+3 -2
View File
@@ -1052,8 +1052,9 @@ static int setup_credentials_internal(
}
mfd = fsmount_credentials_fs(&fs_fd);
if (ERRNO_IS_NEG_PRIVILEGE(mfd) && !dir_mounted) {
log_debug_errno(mfd, "Lacking privilege to mount credentials fs, falling back to plain directory.");
if ((ERRNO_IS_NEG_PRIVILEGE(mfd) || ERRNO_IS_NEG_NOT_SUPPORTED(mfd)) && !dir_mounted) {
/* ANCIENT-MOD: also fall back if the new mount API is unavailable (kernel < 5.2) */
log_debug_errno(mfd, "Lacking privilege or kernel support to mount credentials fs, falling back to plain directory.");
return setup_credentials_plain_dir(context, cred_dir);
}
if (mfd < 0)
+28 -4
View File
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <sys/file.h>
#include <sys/mount.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -1562,6 +1563,25 @@ static int mount_private_cgroup2fs(const MountEntry *m, const NamespaceParameter
return mount_private_apivfs("cgroup2", mount_entry_path(m), "/sys/fs/cgroup", /* opts= */ NULL, p->runtime_scope);
}
/* ANCIENT-MOD: before kernel 5.8 procfs options are per pid namespace (shared with the host /proc) and
* textual hidepid= / subset= do not exist, hence ignore ProtectProc=/ProcSubset= there. */
static bool procfs_per_instance_options_supported(void) {
static int cached = -1;
struct utsname uts;
if (cached >= 0)
return cached;
if (uname(&uts) < 0)
return (cached = true);
cached = strverscmp_improved(uts.release, "5.8") >= 0;
if (!cached)
log_debug("Kernel %s does not support per-instance procfs options, ignoring ProtectProc=/ProcSubset=.", uts.release);
return cached;
}
static int mount_procfs(const MountEntry *m, const NamespaceParameters *p) {
_cleanup_free_ char *opts = NULL;
int r;
@@ -1569,8 +1589,9 @@ static int mount_procfs(const MountEntry *m, const NamespaceParameters *p) {
assert(m);
assert(p);
if (p->protect_proc != PROTECT_PROC_DEFAULT ||
p->proc_subset != PROC_SUBSET_ALL) {
if ((p->protect_proc != PROTECT_PROC_DEFAULT ||
p->proc_subset != PROC_SUBSET_ALL) &&
procfs_per_instance_options_supported()) {
opts = strjoin("hidepid=",
p->protect_proc == PROTECT_PROC_DEFAULT ? "off" : protect_proc_to_string(p->protect_proc));
@@ -2663,7 +2684,9 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
* as well now. */
.propagation = MS_SLAVE,
});
if (_root_mount_fd < 0 && !ERRNO_IS_NEG_PRIVILEGE(_root_mount_fd) && _root_mount_fd != -EINVAL)
/* ANCIENT-MOD: also tolerate missing open_tree() (kernel < 5.2) */
if (_root_mount_fd < 0 && !ERRNO_IS_NEG_PRIVILEGE(_root_mount_fd) &&
!ERRNO_IS_NEG_NOT_SUPPORTED(_root_mount_fd) && _root_mount_fd != -EINVAL)
return log_debug_errno(_root_mount_fd, "Failed to clone specified directory: %m");
root_mount_fd = _root_mount_fd;
@@ -2866,7 +2889,8 @@ int setup_namespace(const NamespaceParameters *p, char **reterr_path) {
/* In case /proc is successfully mounted with pid tree subset only (ProcSubset=pid), the protective
mounts to non-pid /proc paths would fail. But the pid only option may have failed gracefully, so
let's try the mounts but it's not fatal if they don't succeed. */
bool ignore_protect_proc = p->ignore_protect_paths || p->proc_subset == PROC_SUBSET_PID;
bool ignore_protect_proc = p->ignore_protect_paths ||
(p->proc_subset == PROC_SUBSET_PID && procfs_per_instance_options_supported());
if (p->protect_kernel_tunables) {
r = append_static_mounts(&ml,
protect_kernel_tunables_proc_table,
+1 -1
View File
@@ -6654,7 +6654,7 @@ int unit_freezer_action(Unit *u, FreezerAction action) {
assert(u);
assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
if (!unit_can_freeze(u))
if (!cg_freezer_supported() || !unit_can_freeze(u))
return -EOPNOTSUPP;
if (u->job)
+5 -1
View File
@@ -8,7 +8,11 @@
/* Defined since glibc-2.36.
* Supported since kernel v5.3 (7615d9e1780e26e0178c93c55b73309a5dc093d7). */
int pidfd_open_shim(pid_t pid, unsigned flags);
#define pidfd_open pidfd_open_shim
int pidfd_open_checked(pid_t pid, unsigned flags);
#define pidfd_open pidfd_open_checked
/* ANCIENT-MOD: waitid(P_PIDFD) (kernel v5.4) with waitid(P_PID) fallback. */
int pidfd_waitid(int fd, pid_t pid, siginfo_t *info, int options);
/* Defined since glibc-2.36.
* Supported since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad). */
+49
View File
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <poll.h>
#include <sys/pidfd.h>
#include <sys/wait.h>
#include "libc-shim.h"
@@ -8,6 +10,53 @@ DEFINE_SYSCALL_SHIM(pidfd_open, int,
pid_t, pid,
unsigned, flags)
/* ANCIENT-MOD: vendor kernels < 5.4 (e.g. Android 4.19) may backport pidfd_open() without
* waitid(P_PIDFD). Pidfds are reported usable only if they can be signalled and polled (both needed
* by logind and sd-event); waits go through pidfd_waitid(), which falls back to waitid(P_PID). */
int pidfd_open_checked(pid_t pid, unsigned flags) {
static int usable = -1;
if (usable < 0) {
int fd = pidfd_open_shim(getpid(), 0);
if (fd < 0) {
if (errno == ENOSYS)
usable = 0;
return fd;
}
/* Without pidfd poll support the default poll mask reports a live process as readable */
struct pollfd pfd = { .fd = fd, .events = POLLIN };
usable = pidfd_send_signal_shim(fd, 0, NULL, 0) >= 0 && poll(&pfd, 1, 0) == 0;
close(fd);
}
if (!usable) {
errno = ENOSYS;
return -1;
}
return pidfd_open_shim(pid, flags);
}
int pidfd_waitid(int fd, pid_t pid, siginfo_t *info, int options) {
static int supported = -1;
if (supported < 0) {
int self = pidfd_open_shim(getpid(), 0);
if (self < 0)
return -1;
siginfo_t si = {};
supported = waitid(P_PIDFD, self, &si, WEXITED|WNOHANG) >= 0 || errno != EINVAL;
close(self);
}
if (supported)
return waitid(P_PIDFD, fd, info, options);
return waitid(P_PID, pid, info, options);
}
DEFINE_SYSCALL_SHIM(pidfd_send_signal, int,
int, fd,
int, sig,
+43 -11
View File
@@ -3,6 +3,7 @@
#include <linux/magic.h>
#include <malloc.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/timerfd.h>
#include <sys/wait.h>
#include <threads.h>
@@ -51,9 +52,20 @@ static bool EVENT_SOURCE_WATCH_PIDFD(const sd_event_source *s) {
/* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */
return s &&
s->type == SOURCE_CHILD &&
s->child.pidfd >= 0 &&
(s->child.options & ~WNOWAIT) == WEXITED;
}
/* ANCIENT-MOD: child sources without pidfd (kernel < 5.3) fall back to waitid(P_PID) */
static int child_waitid(sd_event_source *s, siginfo_t *si, int options) {
assert(s);
if (s->child.pidfd >= 0)
return pidfd_waitid(s->child.pidfd, s->child.pid, si, options);
return waitid(P_PID, s->child.pid, si, options);
}
static bool event_source_is_online(sd_event_source *s) {
assert(s);
return s->enabled != SD_EVENT_OFF && !s->ratelimited;
@@ -1099,10 +1111,12 @@ static sd_event_source* source_free(sd_event_source *s) {
if (s->child.process_owned) {
assert(s->child.pid > 0);
assert(s->child.pidfd >= 0);
if (!s->child.exited) {
if (s->child.pidfd >= 0)
r = RET_NERRNO(pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0));
else
r = RET_NERRNO(kill(s->child.pid, SIGKILL));
if (r < 0 && r != -ESRCH)
log_debug_errno(r, "Failed to kill process " PID_FMT ", ignoring: %m",
s->child.pid);
@@ -1112,7 +1126,7 @@ static sd_event_source* source_free(sd_event_source *s) {
siginfo_t si = {};
/* Reap the child if we can */
(void) waitid(P_PIDFD, s->child.pidfd, &si, WEXITED);
(void) child_waitid(s, &si, WEXITED);
}
}
@@ -1649,9 +1663,21 @@ _public_ int sd_event_add_child(
* PID, and make regular waitid() handling race-free. */
s->child.pidfd = pidfd_open(pid, 0);
if (s->child.pidfd < 0)
if (s->child.pidfd < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
/* Without pidfd we depend on SIGCHLD via signalfd, which only works if it is blocked */
r = signal_is_blocked(SIGCHLD);
if (r < 0)
return r;
if (r == 0) {
log_debug("pidfd_open() unavailable, blocking SIGCHLD to watch child processes.");
r = sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD);
if (r < 0)
return r;
}
} else
s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */
s->wakeup = WAKEUP_EVENT_SOURCE;
@@ -3257,7 +3283,6 @@ _public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, cons
assert_return(s->type == SOURCE_CHILD, -EDOM);
assert_return(!event_origin_changed(s->event), -ECHILD);
assert_return(SIGNAL_VALID(sig), -EINVAL);
assert(s->child.pidfd >= 0);
/* If we already have seen indication the process exited refuse sending a signal early. */
if (s->child.exited)
@@ -3269,14 +3294,20 @@ _public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, cons
if (si)
copy = *si;
if (s->child.pidfd >= 0)
return RET_NERRNO(pidfd_send_signal(s->child.pidfd, sig, si ? &copy : NULL, flags));
if (flags != 0)
return -EOPNOTSUPP;
if (si)
return RET_NERRNO(syscall(SYS_rt_sigqueueinfo, s->child.pid, sig, &copy));
return RET_NERRNO(kill(s->child.pid, sig));
}
_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) {
assert_return(s, -EINVAL);
assert_return(s->type == SOURCE_CHILD, -EDOM);
assert_return(!event_origin_changed(s->event), -ECHILD);
assert(s->child.pidfd >= 0);
return s->child.pidfd_owned;
}
@@ -3285,7 +3316,9 @@ _public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) {
assert_return(s, -EINVAL);
assert_return(s->type == SOURCE_CHILD, -EDOM);
assert_return(!event_origin_changed(s->event), -ECHILD);
assert(s->child.pidfd >= 0);
if (s->child.pidfd < 0)
return -EOPNOTSUPP;
s->child.pidfd_owned = own;
return 0;
@@ -3757,7 +3790,6 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
HASHMAP_FOREACH(s, e->child_sources) {
assert(s->type == SOURCE_CHILD);
assert(s->child.pidfd >= 0);
if (s->priority > threshold)
continue;
@@ -3777,7 +3809,7 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
continue;
zero(s->child.siginfo);
if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo,
if (child_waitid(s, &s->child.siginfo,
WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | (s->child.options & ~WNOWAIT)) < 0)
return negative_errno();
@@ -3791,7 +3823,7 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
* from the queue, since there's no benefit in leaving it queued. */
assert(s->child.options & (WSTOPPED|WCONTINUED));
(void) waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
(void) child_waitid(s, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
}
r = source_set_pending(s, true);
@@ -3828,7 +3860,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
* be set to pending, and we would have returned early above. */
zero(s->child.siginfo);
if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
if (pidfd_waitid(s->child.pidfd, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
return -errno;
if (s->child.siginfo.si_pid == 0)
@@ -4274,7 +4306,7 @@ static int source_dispatch(sd_event_source *s) {
/* Now, reap the PID for good (unless WNOWAIT was specified by the caller). */
if (zombie) {
(void) waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG|WEXITED|(s->child.options & WNOWAIT));
(void) child_waitid(s, &s->child.siginfo, WNOHANG|WEXITED|(s->child.options & WNOWAIT));
if (!FLAGS_SET(s->child.options, WNOWAIT))
s->child.waited = true;
}
+2 -1
View File
@@ -117,7 +117,8 @@ int rtnl_resolve_ifname_full(
r = sd_netlink_call(*rtnl, message, 0, &reply);
if (r >= 0)
return parse_newlink_message(reply, ret_name, ret_altnames);
if (r != -ENODEV)
/* The kernels older than 76c9ac0ee878f6693d398d3a95ccaf85e1f597a6 (v5.5) return -EINVAL. */
if (!IN_SET(r, -ENODEV, -EINVAL))
return r;
}
+1 -1
View File
@@ -858,7 +858,7 @@ static int create_session_message(
if (!avoid_pidfd) {
pidfd = pidfd_open(getpid_cached(), 0);
if (pidfd < 0)
if (pidfd < 0 && !ERRNO_IS_NOT_SUPPORTED(errno)) /* ANCIENT-MOD: kernel < 5.3 */
return -errno;
}
+40 -3
View File
@@ -2448,6 +2448,38 @@ static int link_update_driver(Link *link, sd_netlink_message *message) {
return 1; /* needs reconfigure */
}
static int link_update_permanent_hardware_address_from_ethtool(Link *link, sd_netlink_message *message) {
int r;
assert(link);
assert(link->manager);
assert(message);
if (link->ethtool_permanent_hw_addr_read)
return 0;
/* When udevd is running, read the permanent hardware address after the interface is
* initialized by udevd. Otherwise, ethtool may not work correctly. See issue #22538.
* When udevd is not running, read the value when the interface is detected. */
if (udev_available() && !link->dev)
return 0;
/* If the interface does not have a hardware address, then it will not have a permanent address either. */
r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, NULL);
if (r == -ENODATA)
return 0;
if (r < 0)
return log_link_debug_errno(link, r, "Failed to read IFLA_ADDRESS attribute: %m");
link->ethtool_permanent_hw_addr_read = true;
r = ethtool_get_permanent_hw_addr(&link->manager->ethtool_fd, link->ifname, &link->permanent_hw_addr);
if (r < 0)
log_link_debug_errno(link, r, "Permanent hardware address not found, continuing without: %m");
return 0;
}
static int link_update_permanent_hardware_address(Link *link, sd_netlink_message *message) {
int r;
@@ -2459,11 +2491,16 @@ static int link_update_permanent_hardware_address(Link *link, sd_netlink_message
return 0;
r = netlink_message_read_hw_addr(message, IFLA_PERM_ADDRESS, &link->permanent_hw_addr);
if (r == -ENODATA)
return 0;
if (r < 0)
if (r < 0) {
if (r != -ENODATA)
return log_link_debug_errno(link, r, "Failed to read IFLA_PERM_ADDRESS attribute: %m");
/* Fallback to ethtool for kernels older than v5.6 (f74877a5457d34d604dba6dbbb13c4c05bac8b93). */
r = link_update_permanent_hardware_address_from_ethtool(link, message);
if (r < 0)
return r;
}
if (link->permanent_hw_addr.length > 0)
log_link_debug(link, "Saved permanent hardware address: %s", HW_ADDR_TO_STR(&link->permanent_hw_addr));
+6 -1
View File
@@ -52,6 +52,7 @@
#include "networkd-wwan-bus.h"
#include "ordered-set.h"
#include "qdisc.h"
#include "selinux-util.h"
#include "set.h"
#include "stat-util.h"
#include "string-util.h"
@@ -1149,8 +1150,12 @@ int manager_enumerate(Manager *m) {
if (r < 0)
return log_error_errno(r, "Could not enumerate neighbors: %m");
/* ANCIENT-MOD: NextHop support is added in kernel v5.3 (65ee00a9409f751188a8cdc0988167858eb4a536),
* and older kernels return -EOPNOTSUPP, or -EINVAL if SELinux is enabled. */
r = manager_enumerate_nexthop(m);
if (r < 0)
if (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing()))
log_debug_errno(r, "Could not enumerate nexthops, ignoring: %m");
else if (r < 0)
return log_error_errno(r, "Could not enumerate nexthops: %m");
r = manager_enumerate_routes(m);
+12
View File
@@ -1066,6 +1066,7 @@ static int fw_nftables_add_local_dnat_internal(
sd_netlink_message *messages[3] = {};
CLEANUP_ELEMENTS(messages, sd_netlink_message_unref_array_clear);
static bool ipv6_supported = true;
uint32_t data[5], key[2], dlen;
size_t msgcnt = 0;
int r;
@@ -1074,6 +1075,9 @@ static int fw_nftables_add_local_dnat_internal(
assert(add || !previous_remote);
assert(IN_SET(af, AF_INET, AF_INET6));
if (!ipv6_supported && af == AF_INET6)
return -EOPNOTSUPP;
if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
return -EPROTONOSUPPORT;
@@ -1127,6 +1131,14 @@ static int fw_nftables_add_local_dnat_internal(
assert(msgcnt < ELEMENTSOF(messages));
r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS);
if (r == -EOVERFLOW && af == AF_INET6) {
/* ANCIENT-MOD: The current implementation of DNAT in systemd requires kernel's
* fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 (v5.8), and the older kernel returns
* -EOVERFLOW. Let's treat the error as -EOPNOTSUPP. */
log_debug_errno(r, "The current implementation of IPv6 DNAT in systemd requires kernel 5.8 or newer, ignoring: %m");
ipv6_supported = false;
return -EOPNOTSUPP;
}
if (r < 0)
return r;
+3
View File
@@ -64,6 +64,9 @@ static bool is_in_survivor_cgroup(const PidRef *pid) {
}
r = cg_get_xattr_bool(cgroup_path, "user.survive_final_kill_signal");
/* user xattr support was added to kernel v5.7, try with the trusted namespace as a fallback */
if (ERRNO_IS_NEG_XATTR_ABSENT(r))
r = cg_get_xattr_bool(cgroup_path, "trusted.survive_final_kill_signal");
if (r < 0 && !ERRNO_IS_NEG_XATTR_ABSENT(r))
log_debug_errno(r,
"Failed to get survive_final_kill_signal xattr of %s, ignoring: %m",
+16
View File
@@ -5,6 +5,7 @@
#endif
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <sys/file.h>
#include <sys/ioctl.h>
@@ -200,6 +201,21 @@ static int loop_configure_fallback(int fd, const struct loop_config *c) {
random_u64_range(UINT64_C(240) * USEC_PER_MSEC * n_attempts/64));
}
/* Work around a kernel bug, where changing offset/size of the loopback device doesn't correctly
* invalidate the buffer cache. For details see:
*
* https://android.googlesource.com/platform/system/apex/+/bef74542fbbb4cd629793f4efee8e0053b360570
*
* This was fixed in kernel 5.0, see:
*
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5db470e229e22b7eda6e23b5566e532c96fb5bc3
*
* We'll run the work-around here in the legacy LOOP_SET_STATUS64 codepath. In the LOOP_CONFIGURE
* codepath above it should not be necessary. */
if (c->info.lo_offset != 0 || c->info.lo_sizelimit != 0)
if (ioctl(fd, BLKFLSBUF, 0) < 0)
log_debug_errno(errno, "Failed to issue BLKFLSBUF ioctl, ignoring: %m");
/* If a block size is requested then try to configure it. If that doesn't work, ignore errors, but
* afterwards, let's validate what is in effect, and if it doesn't match what we want, fail */
if (c->block_size != 0) {
+22 -13
View File
@@ -43,26 +43,35 @@ typedef struct MountPoint {
} MountPoint;
static int cgroupfs_mount_options(int priority, const char *type, char **ret) {
_cleanup_free_ char *opts = NULL;
int r;
assert(type);
assert(streq(type, "cgroup2"));
assert(ret);
/* memory_hugetlb_accounting mount option is since kernel v6.7 (8cba9576df601c384abd334a503c3f6e1e29eefb). */
/* ANCIENT-MOD: memory_recursiveprot is probed (kernel >= 5.7) instead of being always passed.
* memory_hugetlb_accounting mount option is since kernel v6.7 (8cba9576df601c384abd334a503c3f6e1e29eefb). */
r = mount_option_supported("cgroup2", "memory_hugetlb_accounting", /* value= */ NULL);
if (r <= 0) {
if (r < 0)
log_full_errno(priority, r, "Failed to determine whether cgroupfs supports 'memory_hugetlb_accounting' mount option, assuming not: %m");
else
log_debug("'memory_hugetlb_accounting' not supported by cgroupfs, not using mount option.");
*ret = NULL;
return 0;
FOREACH_STRING(o, "memory_recursiveprot", "memory_hugetlb_accounting") {
r = mount_option_supported("cgroup2", o, /* value= */ NULL);
if (r == -EAGAIN)
/* No fsopen(), i.e. kernel < 5.2, hence none of these options exist either */
log_debug("Cannot probe cgroupfs mount option '%s', kernel too old, not using it.", o);
else if (r < 0 && streq(o, "memory_recursiveprot")) {
log_full_errno(priority, r, "Failed to determine whether cgroupfs supports '%s' mount option, assuming it does: %m", o);
if (!strextend_with_separator(&opts, ",", o))
return log_oom_full(priority);
} else if (r < 0)
log_full_errno(priority, r, "Failed to determine whether cgroupfs supports '%s' mount option, assuming not: %m", o);
else if (r == 0)
log_debug("'%s' not supported by cgroupfs, not using mount option.", o);
else if (!strextend_with_separator(&opts, ",", o))
return log_oom_full(priority);
}
return strdup_to(ret, "memory_hugetlb_accounting");
*ret = TAKE_PTR(opts);
return 0;
}
int mount_cgroupfs(const char *path) {
@@ -82,7 +91,7 @@ int mount_cgroupfs(const char *path) {
return r;
/* These options shall be kept in sync with those in mount_table below. */
if (!strprepend_with_separator(&opts, ",", "nsdelegate,memory_recursiveprot"))
if (!strprepend_with_separator(&opts, ",", "nsdelegate"))
return log_oom();
return mount_nofollow_verbose(LOG_ERR, "cgroup2", path, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
@@ -200,7 +209,7 @@ static const MountPoint mount_table[] = {
.what = "cgroup2",
.where = "/sys/fs/cgroup",
.type = "cgroup2",
.options = "nsdelegate,memory_recursiveprot",
.options = "nsdelegate",
.options_fn = cgroupfs_mount_options,
.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
.mode = MNT_FATAL|MNT_IN_CONTAINER|MNT_CHECK_WRITABLE,
+8 -2
View File
@@ -343,13 +343,19 @@ TEST(close_all_fds) {
_exit(EXIT_SUCCESS);
}
r = ASSERT_OK(pidref_safe_fork("(caf-nomalloc)", flags, NULL));
ASSERT_OK(r = pidref_safe_fork("(caf-nomalloc)", flags, NULL));
if (r == 0) {
test_close_all_fds_inner(close_all_fds_without_malloc);
_exit(EXIT_SUCCESS);
}
r = ASSERT_OK(pidref_safe_fork("(caf-frugal)", flags, NULL));
ASSERT_OK(r = pidref_safe_fork("(caf-proc)", flags, NULL));
if (r == 0) {
test_close_all_fds_inner(close_all_fds_by_proc);
_exit(EXIT_SUCCESS);
}
ASSERT_OK(r = pidref_safe_fork("(caf-frugal)", flags, NULL));
if (r == 0) {
test_close_all_fds_inner(close_all_fds_frugal);
_exit(EXIT_SUCCESS);
+1 -1
View File
@@ -672,7 +672,7 @@ static void test_nested_partition_table_one(const char *nested_table) {
ASSERT_TRUE(dissected->partitions[PARTITION_ROOT].found);
node = ASSERT_NOT_NULL(dissected->partitions[PARTITION_ROOT].node);
/* Carve a nested partition table into that partition, mimicking the pmOS/android case (663f0bf5cb)
/* Carve a nested partition table into that partition, mimicking the Alpine/Nura case (663f0bf5cb)
* where a partition carries a partition table the kernel won't scan, as partition devices don't
* support partition scanning. We write and read it back through the same partition node, so the
* buffer cache stays coherent. */
@@ -2,7 +2,7 @@
[Unit]
Description=Test DynamicUser with static User= whose uid and gid are different
# On Ubuntu or Debian, user games has uid==5 and gid==60.
# On Alpine/postmarketOS, the user 'games' in the 'games' and 'users' groups.
# On Alpine/Nura, the user 'games' in the 'games' and 'users' groups.
[Service]
Type=oneshot
+1 -1
View File
@@ -50,7 +50,7 @@ testcase_basic() {
systemd-run -p PrivatePIDs=yes --remain-after-exit --unit TEST-07-PID1-private-pid sleep infinity
# Wait for ExecMainPID to be correctly populated as there might be a race between spawning service
# and actual exec child process
# Note, Alpine/postmarketOS build coreutils with --enable-single-binary=symlinks. In that case, coreutils
# Note, Alpine/Nura build coreutils with --enable-single-binary=symlinks. In that case, coreutils
# calls prctl(PR_SET_NAME, argv[0]), hence the comm will be the path to the symlink. If the sleep file is
# a dedicated binary (like most other distributions do), the comm will be the filename, i.e. "sleep". So,
# here we need to cut the directory part.
+1 -1
View File
@@ -410,7 +410,7 @@ testcase_check_default_inaccessible_paths() {
"/proc/timer_list"
)
# /proc/kcore may not exist on some kernels, e.g. Alpine/postmarketOS.
# /proc/kcore may not exist on some kernels, e.g. Alpine/Nura.
if [[ -e /proc/kcore ]]; then
inaccessible_paths+=(
"/proc/kcore"
+1 -1
View File
@@ -11,7 +11,7 @@ set -o pipefail
. /etc/os-release
if [[ "${ID_LIKE:-}" == alpine ]]; then
# Alpine/postmarketOS builds libdevmapper and so on without systemd support, and seems to not wait for
# Alpine/Nura builds libdevmapper and so on without systemd support, and seems to not wait for
# uevents for dm-X devices being processed by systemd-udevd. That causes a significant issue in
# dissect-image.c especially when multiple dm-X devices are activated/deactivated in parallel.
exit 0
+1 -1
View File
@@ -3191,7 +3191,7 @@ EOF
assert_eq "$(findmnt "${btrfs_mntpoint_plain}" -o SOURCE -n)" "${loop}p1"
dm_btrfs_encrypted="$(findmnt "${btrfs_mntpoint_encrypted}" -o SOURCE -n)"
if [[ "$dm_btrfs_encrypted" != "/dev/mapper/btrfs-replace-encrypted" ]]; then
# When libdevmapper is built without UDEV_SYNC_SUPPORT (e.g. on Alpine/postmarketOS),
# When libdevmapper is built without UDEV_SYNC_SUPPORT (e.g. on Alpine/Nura),
# it creates a device node under /dev/mapper/ instead of relying on udev to create a symlink.
# In this case, verify that both device nodes refer to the same underlying device.
assert_eq "$(stat -c %Hr:%Lr "$dm_btrfs_encrypted")" "$(stat -c %Hr:%Lr /dev/mapper/btrfs-replace-encrypted)"
+1 -1
View File
@@ -659,7 +659,7 @@ testcase_lvm_basic() {
. /etc/os-release
if [[ "$ID" == "ubuntu" || "${ID_LIKE:-}" == "alpine" ]]; then
echo "LVM on Ubuntu/alpine/postmarketos is broken, skipping the test" | tee --append /skipped
echo "LVM on Ubuntu/Alpine/Nura is broken, skipping the test" | tee --append /skipped
exit 77
fi
+1 -1
View File
@@ -129,7 +129,7 @@ for a in crc32c crc32 xxhash64 sha1 sha256; do
modprobe -q "crypto-$a" || :
# Some algorithms are not supported on certain platforms (e.g. crc32 is
# missing on Alpine/postmarketOS). Skip them at runtime to avoid spurious
# missing on Alpine/Nura). Skip them at runtime to avoid spurious
# failures.
if ! grep -q -E "^name\s+: $a\$" /proc/crypto; then
echo "Algorithm '$a' is not supported on this system, skipping."
+1 -1
View File
@@ -1129,7 +1129,7 @@ testcase_11_nft() {
. /etc/os-release
if [[ "${ID_LIKE:-}" == alpine ]]; then
# FIXME: For some reasons, the following tests will fail on alpine/postmarketos.
# FIXME: For some reasons, the following tests will fail on Alpine/Nura.
return 0
fi
+1 -1
View File
@@ -8,7 +8,7 @@ set -o pipefail
. /etc/os-release
if [[ "${ID_LIKE:-}" == alpine ]]; then
# FIXME: For some reasons (maybe this test requires nss module??), the test fails on alpine/postmarketos.
# FIXME: For some reasons (maybe this test requires nss module??), the test fails on Alpine/Nura.
exit 77
fi