systemd-257-24
Resolves: RHEL-155454, RHEL-155805, RHEL-155396, RHEL-158303, RHEL-158354, RHEL-143728, RHEL-168098, RHEL-143028
This commit is contained in:
parent
363d20f6ec
commit
b7ebf97389
@ -0,0 +1,89 @@
|
||||
From 3061980e575f36129fe1880118ae757e6069eaa0 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Fri, 17 Oct 2025 14:00:23 +0100
|
||||
Subject: [PATCH] ci: re-enable bpf-framework option for build and unit test
|
||||
jobs
|
||||
|
||||
Use the same trickery we do in the package build and search for
|
||||
the actual bpftool binary. For the CI job any one we find is
|
||||
good enough.
|
||||
When we switch all jobs to 26.04 we can drop all of this.
|
||||
|
||||
This reverts commit cc814110af7a453db898ea2990a0281616d5ceff.
|
||||
|
||||
(cherry picked from commit 3b11139c0db9dd0a37b0493a8d2ad5f531a92344)
|
||||
|
||||
Related: RHEL-155454
|
||||
---
|
||||
.github/workflows/build_test.sh | 12 ++++++++++++
|
||||
.github/workflows/unit_tests.sh | 13 +++++++++++++
|
||||
2 files changed, 25 insertions(+)
|
||||
|
||||
diff --git a/.github/workflows/build_test.sh b/.github/workflows/build_test.sh
|
||||
index 113af704a8..462203be9a 100755
|
||||
--- a/.github/workflows/build_test.sh
|
||||
+++ b/.github/workflows/build_test.sh
|
||||
@@ -47,6 +47,7 @@ PACKAGES=(
|
||||
libxkbcommon-dev
|
||||
libxtables-dev
|
||||
libzstd-dev
|
||||
+ linux-tools-generic
|
||||
mold
|
||||
mount
|
||||
net-tools
|
||||
@@ -131,6 +132,17 @@ sudo apt-get -y install "${PACKAGES[@]}"
|
||||
pip3 install --user -r .github/workflows/requirements.txt --require-hashes --break-system-packages
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
+# TODO: drop after we switch to ubuntu 26.04
|
||||
+bpftool_dir=$(dirname "$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)")
|
||||
+if [ -n "$bpftool_dir" ]; then
|
||||
+ export PATH="$bpftool_dir:$PATH"
|
||||
+fi
|
||||
+
|
||||
+if [[ -n "$CUSTOM_PYTHON" ]]; then
|
||||
+ # If CUSTOM_PYTHON is set we need to pull jinja2 from pip, as a local interpreter is used
|
||||
+ pip3 install --user --break-system-packages jinja2
|
||||
+fi
|
||||
+
|
||||
$CC --version
|
||||
meson --version
|
||||
ninja --version
|
||||
diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh
|
||||
index 168bcc55c3..3acaf75417 100755
|
||||
--- a/.github/workflows/unit_tests.sh
|
||||
+++ b/.github/workflows/unit_tests.sh
|
||||
@@ -18,6 +18,7 @@ ADDITIONAL_DEPS=(
|
||||
libtss2-dev
|
||||
libxkbcommon-dev
|
||||
libzstd-dev
|
||||
+ linux-tools-generic
|
||||
python3-libevdev
|
||||
python3-pefile
|
||||
python3-pyelftools
|
||||
@@ -70,6 +71,12 @@ for phase in "${PHASES[@]}"; do
|
||||
capsh --drop=all -- -c "stat $PWD/meson.build"
|
||||
;;
|
||||
RUN|RUN_GCC|RUN_CLANG|RUN_CLANG_RELEASE)
|
||||
+ # TODO: drop after we switch to ubuntu 26.04
|
||||
+ bpftool_dir=$(dirname "$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)")
|
||||
+ if [ -n "$bpftool_dir" ]; then
|
||||
+ export PATH="$bpftool_dir:$PATH"
|
||||
+ fi
|
||||
+
|
||||
if [[ "$phase" =~ ^RUN_CLANG ]]; then
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
@@ -94,6 +101,12 @@ for phase in "${PHASES[@]}"; do
|
||||
TZ=GMT+12 meson test -C build --print-errorlogs
|
||||
;;
|
||||
RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN_NO_DEPS)
|
||||
+ # TODO: drop after we switch to ubuntu 26.04
|
||||
+ bpftool_dir=$(dirname "$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)")
|
||||
+ if [ -n "$bpftool_dir" ]; then
|
||||
+ export PATH="$bpftool_dir:$PATH"
|
||||
+ fi
|
||||
+
|
||||
MESON_ARGS=(--optimization=1)
|
||||
|
||||
if [[ "$phase" =~ ^RUN_CLANG_ASAN_UBSAN ]]; then
|
||||
32
0611-ci-add-bpftool-workaround-to-codeql-job-too.patch
Normal file
32
0611-ci-add-bpftool-workaround-to-codeql-job-too.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 5886ebf6256fb0b1873828fa46d918877c18e474 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Fri, 17 Oct 2025 15:39:09 +0100
|
||||
Subject: [PATCH] ci: add bpftool workaround to codeql job too
|
||||
|
||||
(cherry picked from commit e9fd2bbfffc5c2c7cd1ea0a288d5435fc15e387f)
|
||||
|
||||
Related: RHEL-155454
|
||||
---
|
||||
.github/workflows/codeql.yml | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
|
||||
index 51034783ca..443221fa11 100644
|
||||
--- a/.github/workflows/codeql.yml
|
||||
+++ b/.github/workflows/codeql.yml
|
||||
@@ -44,7 +44,14 @@ jobs:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql-config.yml
|
||||
|
||||
- - run: sudo -E .github/workflows/unit_tests.sh SETUP
|
||||
+ - run: |
|
||||
+ sudo -E .github/workflows/unit_tests.sh SETUP
|
||||
+ # TODO: drop after we switch to ubuntu 26.04
|
||||
+ bpftool_binary=$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)
|
||||
+ if [ -n "$bpftool_binary" ]; then
|
||||
+ sudo rm -f /usr/bin/bpftool
|
||||
+ sudo ln -s "$bpftool_binary" /usr/bin/
|
||||
+ fi
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88
|
||||
27
0612-ci-fix-workaround-about-bpftool-for-codeql.patch
Normal file
27
0612-ci-fix-workaround-about-bpftool-for-codeql.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 9455ccb53a8cf50d9b7026e297f8afd8847a57e2 Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Sat, 18 Oct 2025 10:39:13 +0900
|
||||
Subject: [PATCH] ci: fix workaround about bpftool for codeql
|
||||
|
||||
Follow-up for e9fd2bbfffc5c2c7cd1ea0a288d5435fc15e387f.
|
||||
|
||||
(cherry picked from commit a6836cfa0bdf1bb1fcf05686c5af3f2b5ad97f6b)
|
||||
|
||||
Related: RHEL-155454
|
||||
---
|
||||
.github/workflows/codeql.yml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
|
||||
index 443221fa11..cfe54d59ac 100644
|
||||
--- a/.github/workflows/codeql.yml
|
||||
+++ b/.github/workflows/codeql.yml
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
# TODO: drop after we switch to ubuntu 26.04
|
||||
bpftool_binary=$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)
|
||||
if [ -n "$bpftool_binary" ]; then
|
||||
- sudo rm -f /usr/bin/bpftool
|
||||
+ sudo rm -f /usr/{bin,sbin}/bpftool
|
||||
sudo ln -s "$bpftool_binary" /usr/bin/
|
||||
fi
|
||||
|
||||
31
0613-ci-add-bpftool-workaround-to-coverity-too.patch
Normal file
31
0613-ci-add-bpftool-workaround-to-coverity-too.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From 2842f1200bcb79f211309270a0afab4ab7a89b20 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Sat, 18 Oct 2025 14:23:59 +0100
|
||||
Subject: [PATCH] ci: add bpftool workaround to coverity too
|
||||
|
||||
(cherry picked from commit d29f181cf02100c146fc8691a5515a708d06ddbf)
|
||||
|
||||
Related: RHEL-155454
|
||||
---
|
||||
.github/workflows/coverity.yml | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
|
||||
index 66204069c4..80d25d380a 100644
|
||||
--- a/.github/workflows/coverity.yml
|
||||
+++ b/.github/workflows/coverity.yml
|
||||
@@ -25,6 +25,13 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
# Reuse the setup phase of the unit test script to avoid code duplication
|
||||
- name: Install build dependencies
|
||||
- run: sudo -E .github/workflows/unit_tests.sh SETUP
|
||||
+ run: |
|
||||
+ sudo -E .github/workflows/unit_tests.sh SETUP
|
||||
+ # TODO: drop after we switch to ubuntu 26.04
|
||||
+ bpftool_binary=$(find /usr/lib/linux-tools/ /usr/lib/linux-tools-* -name 'bpftool' -perm /u=x 2>/dev/null | sort -r | head -n1)
|
||||
+ if [ -n "$bpftool_binary" ]; then
|
||||
+ sudo rm -f /usr/{bin,sbin}/bpftool
|
||||
+ sudo ln -s "$bpftool_binary" /usr/bin/
|
||||
+ fi
|
||||
- name: Build & upload the results
|
||||
run: tools/coverity.sh
|
||||
@ -0,0 +1,36 @@
|
||||
From 3e597926e21dfbaf2b4a38aa64a4da954815f2b7 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Macku <jamacku@redhat.com>
|
||||
Date: Mon, 30 Mar 2026 14:48:42 +0200
|
||||
Subject: [PATCH] Revert "man: mention RHEL documentation in systemctl's man
|
||||
page"
|
||||
|
||||
This reverts commit fdebd2be914ce55ec4244c99adc93fc7f046c08f.
|
||||
|
||||
rhel-only: doc
|
||||
|
||||
Resolves: RHEL-155805
|
||||
---
|
||||
man/systemctl.xml | 10 ----------
|
||||
1 file changed, 10 deletions(-)
|
||||
|
||||
diff --git a/man/systemctl.xml b/man/systemctl.xml
|
||||
index 322505e615..fe15bd3722 100644
|
||||
--- a/man/systemctl.xml
|
||||
+++ b/man/systemctl.xml
|
||||
@@ -2978,16 +2978,6 @@ EOF
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
- <refsect1>
|
||||
- <title>Examples</title>
|
||||
- <para>
|
||||
- For examples how to use systemctl in comparison with old service and chkconfig commands please see:
|
||||
- <ulink url="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/10/html/using_systemd_unit_files_to_customize_and_optimize_your_system/managing-systemd#managing-system-services-with-systemctl">
|
||||
- Managing System Services
|
||||
- </ulink>
|
||||
- </para>
|
||||
- </refsect1>
|
||||
-
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
162
0615-path-util-add-flavour-of-path_startswith-that-leaves.patch
Normal file
162
0615-path-util-add-flavour-of-path_startswith-that-leaves.patch
Normal file
@ -0,0 +1,162 @@
|
||||
From 655ca1b4d224079a6ce87f705fb0c33ebe69726f Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Mon, 19 May 2025 12:58:52 +0200
|
||||
Subject: [PATCH] path-util: add flavour of path_startswith() that leaves a
|
||||
leading slash in place
|
||||
|
||||
(cherry picked from commit ee19edbb9f3455db3f750089082f3e5a925e3a0c)
|
||||
|
||||
Related: RHEL-155396
|
||||
---
|
||||
src/basic/fs-util.c | 2 +-
|
||||
src/basic/mkdir.c | 2 +-
|
||||
src/basic/path-util.c | 39 ++++++++++++++++++++++++++++-----------
|
||||
src/basic/path-util.h | 10 ++++++++--
|
||||
src/test/test-path-util.c | 16 ++++++++++++++++
|
||||
5 files changed, 54 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
|
||||
index 4ede324c34..21a670c9e8 100644
|
||||
--- a/src/basic/fs-util.c
|
||||
+++ b/src/basic/fs-util.c
|
||||
@@ -66,7 +66,7 @@ int rmdir_parents(const char *path, const char *stop) {
|
||||
assert(*slash == '/');
|
||||
*slash = '\0';
|
||||
|
||||
- if (path_startswith_full(stop, p, /* accept_dot_dot= */ false))
|
||||
+ if (path_startswith_full(stop, p, /* flags= */ 0))
|
||||
return 0;
|
||||
|
||||
if (rmdir(p) < 0 && errno != ENOENT)
|
||||
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
|
||||
index 3e1545a58b..6fc2a79944 100644
|
||||
--- a/src/basic/mkdir.c
|
||||
+++ b/src/basic/mkdir.c
|
||||
@@ -149,7 +149,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui
|
||||
assert(_mkdirat != mkdirat);
|
||||
|
||||
if (prefix) {
|
||||
- p = path_startswith_full(path, prefix, /* accept_dot_dot= */ false);
|
||||
+ p = path_startswith_full(path, prefix, /* flags= */ 0);
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
|
||||
index 78ba10ed80..a4709e1b7d 100644
|
||||
--- a/src/basic/path-util.c
|
||||
+++ b/src/basic/path-util.c
|
||||
@@ -405,8 +405,8 @@ char* path_simplify_full(char *path, PathSimplifyFlags flags) {
|
||||
return path;
|
||||
}
|
||||
|
||||
-char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
|
||||
- assert(path);
|
||||
+char* path_startswith_full(const char *original_path, const char *prefix, PathStartWithFlags flags) {
|
||||
+ assert(original_path);
|
||||
assert(prefix);
|
||||
|
||||
/* Returns a pointer to the start of the first component after the parts matched by
|
||||
@@ -419,28 +419,45 @@ char* path_startswith_full(const char *path, const char *prefix, bool accept_dot
|
||||
* Returns NULL otherwise.
|
||||
*/
|
||||
|
||||
+ const char *path = original_path;
|
||||
+
|
||||
if ((path[0] == '/') != (prefix[0] == '/'))
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
const char *p, *q;
|
||||
- int r, k;
|
||||
+ int m, n;
|
||||
|
||||
- r = path_find_first_component(&path, accept_dot_dot, &p);
|
||||
- if (r < 0)
|
||||
+ m = path_find_first_component(&path, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &p);
|
||||
+ if (m < 0)
|
||||
return NULL;
|
||||
|
||||
- k = path_find_first_component(&prefix, accept_dot_dot, &q);
|
||||
- if (k < 0)
|
||||
+ n = path_find_first_component(&prefix, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &q);
|
||||
+ if (n < 0)
|
||||
return NULL;
|
||||
|
||||
- if (k == 0)
|
||||
- return (char*) (p ?: path);
|
||||
+ if (n == 0) {
|
||||
+ if (!p)
|
||||
+ p = path;
|
||||
+
|
||||
+ if (FLAGS_SET(flags, PATH_STARTSWITH_RETURN_LEADING_SLASH)) {
|
||||
+
|
||||
+ if (p <= original_path)
|
||||
+ return NULL;
|
||||
+
|
||||
+ p--;
|
||||
+
|
||||
+ if (*p != '/')
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ return (char*) p;
|
||||
+ }
|
||||
|
||||
- if (r != k)
|
||||
+ if (m != n)
|
||||
return NULL;
|
||||
|
||||
- if (!strneq(p, q, r))
|
||||
+ if (!strneq(p, q, m))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
|
||||
index dff5a3a549..d1e9f4b785 100644
|
||||
--- a/src/basic/path-util.h
|
||||
+++ b/src/basic/path-util.h
|
||||
@@ -52,9 +52,15 @@ int safe_getcwd(char **ret);
|
||||
int path_make_absolute_cwd(const char *p, char **ret);
|
||||
int path_make_relative(const char *from, const char *to, char **ret);
|
||||
int path_make_relative_parent(const char *from_child, const char *to, char **ret);
|
||||
-char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
|
||||
+
|
||||
+typedef enum PathStartWithFlags {
|
||||
+ PATH_STARTSWITH_ACCEPT_DOT_DOT = 1U << 0,
|
||||
+ PATH_STARTSWITH_RETURN_LEADING_SLASH = 1U << 1,
|
||||
+} PathStartWithFlags;
|
||||
+
|
||||
+char* path_startswith_full(const char *path, const char *prefix, PathStartWithFlags flags) _pure_;
|
||||
static inline char* path_startswith(const char *path, const char *prefix) {
|
||||
- return path_startswith_full(path, prefix, true);
|
||||
+ return path_startswith_full(path, prefix, PATH_STARTSWITH_ACCEPT_DOT_DOT);
|
||||
}
|
||||
|
||||
int path_compare(const char *a, const char *b) _pure_;
|
||||
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
|
||||
index e02bd8c857..8aa477bd69 100644
|
||||
--- a/src/test/test-path-util.c
|
||||
+++ b/src/test/test-path-util.c
|
||||
@@ -756,6 +756,22 @@ TEST(path_startswith) {
|
||||
test_path_startswith_one("/foo/bar/barfoo/", "/fo", NULL, NULL);
|
||||
}
|
||||
|
||||
+static void test_path_startswith_return_leading_slash_one(const char *path, const char *prefix, const char *expected) {
|
||||
+ const char *p;
|
||||
+
|
||||
+ log_debug("/* %s(%s, %s) */", __func__, path, prefix);
|
||||
+
|
||||
+ p = path_startswith_full(path, prefix, PATH_STARTSWITH_RETURN_LEADING_SLASH);
|
||||
+ ASSERT_STREQ(p, expected);
|
||||
+}
|
||||
+
|
||||
+TEST(path_startswith_return_leading_slash) {
|
||||
+ test_path_startswith_return_leading_slash_one("/foo/bar", "/", "/foo/bar");
|
||||
+ test_path_startswith_return_leading_slash_one("/foo/bar", "/foo", "/bar");
|
||||
+ test_path_startswith_return_leading_slash_one("/foo/bar", "/foo/bar", NULL);
|
||||
+ test_path_startswith_return_leading_slash_one("/foo/bar/", "/foo/bar", "/");
|
||||
+}
|
||||
+
|
||||
static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
const char *t;
|
||||
@ -0,0 +1,45 @@
|
||||
From 6ac39e6caa209898323dda2d907b594322ba3894 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 22 May 2025 18:35:25 +0200
|
||||
Subject: [PATCH] cgroup: port some code over to path_startswith_full()
|
||||
|
||||
(cherry picked from commit 482107724f64cb8dd24db3e65b6ea3151a330301)
|
||||
|
||||
Related: RHEL-155396
|
||||
---
|
||||
src/basic/cgroup-util.c | 10 ++--------
|
||||
1 file changed, 2 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
|
||||
index 309dccb45a..b8a17badea 100644
|
||||
--- a/src/basic/cgroup-util.c
|
||||
+++ b/src/basic/cgroup-util.c
|
||||
@@ -1013,13 +1013,12 @@ int cg_get_root_path(char **ret_path) {
|
||||
}
|
||||
|
||||
int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted) {
|
||||
- _cleanup_free_ char *rt = NULL;
|
||||
- char *p;
|
||||
int r;
|
||||
|
||||
assert(cgroup);
|
||||
assert(ret_shifted);
|
||||
|
||||
+ _cleanup_free_ char *rt = NULL;
|
||||
if (!root) {
|
||||
/* If the root was specified let's use that, otherwise
|
||||
* let's determine it from PID 1 */
|
||||
@@ -1031,12 +1030,7 @@ int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted
|
||||
root = rt;
|
||||
}
|
||||
|
||||
- p = path_startswith(cgroup, root);
|
||||
- if (p && p > cgroup)
|
||||
- *ret_shifted = p - 1;
|
||||
- else
|
||||
- *ret_shifted = cgroup;
|
||||
-
|
||||
+ *ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH) ?: cgroup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
From 889e708da11d9185abb56d5aa42bb1df747217b5 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Fri, 23 May 2025 06:45:40 +0200
|
||||
Subject: [PATCH] path-util: invert PATH_STARTSWITH_ACCEPT_DOT_DOT flag
|
||||
|
||||
As requested: https://github.com/systemd/systemd/pull/37572#pullrequestreview-2861928094
|
||||
|
||||
(cherry picked from commit ceed11e465f1c8efff1931412a85924d9de7c08d)
|
||||
|
||||
Related: RHEL-155396
|
||||
---
|
||||
src/basic/cgroup-util.c | 2 +-
|
||||
src/basic/fs-util.c | 2 +-
|
||||
src/basic/mkdir.c | 2 +-
|
||||
src/basic/path-util.c | 4 ++--
|
||||
src/basic/path-util.h | 4 ++--
|
||||
5 files changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
|
||||
index b8a17badea..925b753c39 100644
|
||||
--- a/src/basic/cgroup-util.c
|
||||
+++ b/src/basic/cgroup-util.c
|
||||
@@ -1030,7 +1030,7 @@ int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted
|
||||
root = rt;
|
||||
}
|
||||
|
||||
- *ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH) ?: cgroup;
|
||||
+ *ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT) ?: cgroup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
|
||||
index 21a670c9e8..69e76653ab 100644
|
||||
--- a/src/basic/fs-util.c
|
||||
+++ b/src/basic/fs-util.c
|
||||
@@ -66,7 +66,7 @@ int rmdir_parents(const char *path, const char *stop) {
|
||||
assert(*slash == '/');
|
||||
*slash = '\0';
|
||||
|
||||
- if (path_startswith_full(stop, p, /* flags= */ 0))
|
||||
+ if (path_startswith_full(stop, p, PATH_STARTSWITH_REFUSE_DOT_DOT))
|
||||
return 0;
|
||||
|
||||
if (rmdir(p) < 0 && errno != ENOENT)
|
||||
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
|
||||
index 6fc2a79944..f1e5f2dc8d 100644
|
||||
--- a/src/basic/mkdir.c
|
||||
+++ b/src/basic/mkdir.c
|
||||
@@ -149,7 +149,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui
|
||||
assert(_mkdirat != mkdirat);
|
||||
|
||||
if (prefix) {
|
||||
- p = path_startswith_full(path, prefix, /* flags= */ 0);
|
||||
+ p = path_startswith_full(path, prefix, PATH_STARTSWITH_REFUSE_DOT_DOT);
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
|
||||
index a4709e1b7d..fda6066bc6 100644
|
||||
--- a/src/basic/path-util.c
|
||||
+++ b/src/basic/path-util.c
|
||||
@@ -428,11 +428,11 @@ char* path_startswith_full(const char *original_path, const char *prefix, PathSt
|
||||
const char *p, *q;
|
||||
int m, n;
|
||||
|
||||
- m = path_find_first_component(&path, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &p);
|
||||
+ m = path_find_first_component(&path, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &p);
|
||||
if (m < 0)
|
||||
return NULL;
|
||||
|
||||
- n = path_find_first_component(&prefix, FLAGS_SET(flags, PATH_STARTSWITH_ACCEPT_DOT_DOT), &q);
|
||||
+ n = path_find_first_component(&prefix, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &q);
|
||||
if (n < 0)
|
||||
return NULL;
|
||||
|
||||
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
|
||||
index d1e9f4b785..429d7ac507 100644
|
||||
--- a/src/basic/path-util.h
|
||||
+++ b/src/basic/path-util.h
|
||||
@@ -54,13 +54,13 @@ int path_make_relative(const char *from, const char *to, char **ret);
|
||||
int path_make_relative_parent(const char *from_child, const char *to, char **ret);
|
||||
|
||||
typedef enum PathStartWithFlags {
|
||||
- PATH_STARTSWITH_ACCEPT_DOT_DOT = 1U << 0,
|
||||
+ PATH_STARTSWITH_REFUSE_DOT_DOT = 1U << 0,
|
||||
PATH_STARTSWITH_RETURN_LEADING_SLASH = 1U << 1,
|
||||
} PathStartWithFlags;
|
||||
|
||||
char* path_startswith_full(const char *path, const char *prefix, PathStartWithFlags flags) _pure_;
|
||||
static inline char* path_startswith(const char *path, const char *prefix) {
|
||||
- return path_startswith_full(path, prefix, PATH_STARTSWITH_ACCEPT_DOT_DOT);
|
||||
+ return path_startswith_full(path, prefix, 0);
|
||||
}
|
||||
|
||||
int path_compare(const char *a, const char *b) _pure_;
|
||||
@ -0,0 +1,28 @@
|
||||
From 9108a63c9d99242b6a5c96046b1494d3101afa2a Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Thu, 26 Feb 2026 11:07:39 +0100
|
||||
Subject: [PATCH] sd-json: fix off-by-one issue when updating parent for array
|
||||
elements
|
||||
|
||||
Follow-up for 8525bb369a09f488ec77f94e1557ecc2343eb4ab
|
||||
|
||||
(cherry picked from commit 4e6e3b8707c84018051ae1885af20e06b2a5209e)
|
||||
|
||||
Related: RHEL-155396
|
||||
---
|
||||
src/libsystemd/sd-json/sd-json.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c
|
||||
index 64b59e0f3f..97897122b8 100644
|
||||
--- a/src/libsystemd/sd-json/sd-json.c
|
||||
+++ b/src/libsystemd/sd-json/sd-json.c
|
||||
@@ -2243,7 +2243,7 @@ _public_ int sd_json_variant_append_array(sd_json_variant **v, sd_json_variant *
|
||||
|
||||
if (old != *v)
|
||||
/* Readjust the parent pointers to the new address */
|
||||
- for (size_t i = 1; i < size; i++)
|
||||
+ for (size_t i = 0; i < size; i++)
|
||||
(*v)[1 + i].parent = *v;
|
||||
|
||||
return json_variant_array_put_element(*v, element);
|
||||
96
0619-core-cgroup-avoid-one-unnecessary-strjoina.patch
Normal file
96
0619-core-cgroup-avoid-one-unnecessary-strjoina.patch
Normal file
@ -0,0 +1,96 @@
|
||||
From 3af048c981a816e0dca65597532456fb7630a417 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Thu, 26 Feb 2026 11:06:00 +0100
|
||||
Subject: [PATCH] core/cgroup: avoid one unnecessary strjoina()
|
||||
|
||||
(cherry picked from commit 42aee39107fbdd7db1ccd402a2151822b2805e9f)
|
||||
|
||||
Related: RHEL-155396
|
||||
---
|
||||
src/core/cgroup.c | 28 +++++++++++++---------------
|
||||
1 file changed, 13 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
|
||||
index 22a29666b6..88ba883f77 100644
|
||||
--- a/src/core/cgroup.c
|
||||
+++ b/src/core/cgroup.c
|
||||
@@ -2961,12 +2961,13 @@ static int unit_update_cgroup(
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suffix_path) {
|
||||
+static int unit_attach_pid_to_cgroup_via_bus(Unit *u, const char *cgroup_path, pid_t pid) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
- char *pp;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
+ assert(cgroup_path);
|
||||
+ assert(pid_is_valid(pid));
|
||||
|
||||
if (MANAGER_IS_SYSTEM(u->manager))
|
||||
return -EINVAL;
|
||||
@@ -2974,18 +2975,13 @@ static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suf
|
||||
if (!u->manager->system_bus)
|
||||
return -EIO;
|
||||
|
||||
- CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
||||
- if (!crt || !crt->cgroup_path)
|
||||
- return -EOWNERDEAD;
|
||||
-
|
||||
/* Determine this unit's cgroup path relative to our cgroup root */
|
||||
- pp = path_startswith(crt->cgroup_path, u->manager->cgroup_root);
|
||||
+ const char *pp = path_startswith_full(cgroup_path,
|
||||
+ u->manager->cgroup_root,
|
||||
+ PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT);
|
||||
if (!pp)
|
||||
return -EINVAL;
|
||||
|
||||
- pp = strjoina("/", pp, suffix_path);
|
||||
- path_simplify(pp);
|
||||
-
|
||||
r = bus_call_method(u->manager->system_bus,
|
||||
bus_systemd_mgr,
|
||||
"AttachProcessesToUnit",
|
||||
@@ -3026,8 +3022,10 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
|
||||
CGroupRuntime *crt = ASSERT_PTR(unit_get_cgroup_runtime(u));
|
||||
|
||||
if (isempty(suffix_path))
|
||||
- p = crt->cgroup_path;
|
||||
+ p = empty_to_root(crt->cgroup_path);
|
||||
else {
|
||||
+ assert(path_is_absolute(suffix_path));
|
||||
+
|
||||
joined = path_join(crt->cgroup_path, suffix_path);
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
@@ -3045,7 +3043,7 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
|
||||
* before we use it */
|
||||
r = pidref_verify(pid);
|
||||
if (r < 0) {
|
||||
- log_unit_info_errno(u, r, "PID " PID_FMT " vanished before we could move it to target cgroup '%s', skipping: %m", pid->pid, empty_to_root(p));
|
||||
+ log_unit_info_errno(u, r, "PID " PID_FMT " vanished before we could move it to target cgroup '%s', skipping: %m", pid->pid, p);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3056,7 +3054,7 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
|
||||
|
||||
log_unit_full_errno(u, again ? LOG_DEBUG : LOG_INFO, r,
|
||||
"Couldn't move process "PID_FMT" to%s requested cgroup '%s': %m",
|
||||
- pid->pid, again ? " directly" : "", empty_to_root(p));
|
||||
+ pid->pid, again ? " directly" : "", p);
|
||||
|
||||
if (again) {
|
||||
int z;
|
||||
@@ -3066,9 +3064,9 @@ int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) {
|
||||
* Since it's more privileged it might be able to move the process across the
|
||||
* leaves of a subtree whose top node is not owned by us. */
|
||||
|
||||
- z = unit_attach_pid_to_cgroup_via_bus(u, pid->pid, suffix_path);
|
||||
+ z = unit_attach_pid_to_cgroup_via_bus(u, p, pid->pid);
|
||||
if (z < 0)
|
||||
- log_unit_info_errno(u, z, "Couldn't move process "PID_FMT" to requested cgroup '%s' (directly or via the system bus): %m", pid->pid, empty_to_root(p));
|
||||
+ log_unit_info_errno(u, z, "Couldn't move process "PID_FMT" to requested cgroup '%s' (directly or via the system bus): %m", pid->pid, p);
|
||||
else {
|
||||
if (ret >= 0)
|
||||
ret++; /* Count successful additions */
|
||||
29
0620-core-validate-input-cgroup-path-more-prudently.patch
Normal file
29
0620-core-validate-input-cgroup-path-more-prudently.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From e1c092e585f4cada10dbd79d0c31bfb9156edea0 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Thu, 26 Feb 2026 11:06:34 +0100
|
||||
Subject: [PATCH] core: validate input cgroup path more prudently
|
||||
|
||||
(cherry picked from commit efa6ba2ab625aaa160ac435a09e6482fc63bdbe8)
|
||||
|
||||
Resolves: RHEL-155396
|
||||
---
|
||||
src/core/dbus-manager.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
|
||||
index 8e39d67a00..d516f30c96 100644
|
||||
--- a/src/core/dbus-manager.c
|
||||
+++ b/src/core/dbus-manager.c
|
||||
@@ -622,6 +622,12 @@ static int method_get_unit_by_control_group(sd_bus_message *message, void *userd
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
+ if (!path_is_absolute(cgroup))
|
||||
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not absolute: %s", cgroup);
|
||||
+
|
||||
+ if (!path_is_normalized(cgroup))
|
||||
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not normalized: %s", cgroup);
|
||||
+
|
||||
u = manager_get_unit_by_cgroup(m, cgroup);
|
||||
if (!u)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
|
||||
@ -0,0 +1,55 @@
|
||||
From b29c80a11df03e849e4f2a33e8332776c4b0f637 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Wed, 11 Mar 2026 12:15:26 +0000
|
||||
Subject: [PATCH] nspawn: apply BindUser/Ephemeral from settings file only if
|
||||
trusted
|
||||
|
||||
Originally reported on yeswehack.com as:
|
||||
YWH-PGM9780-116
|
||||
|
||||
Follow-up for 2f8930449079403b26c9164b8eeac78d5af2c8df
|
||||
Follow-up for a2f577fca0be79b23f61f033229b64884e7d840a
|
||||
|
||||
(cherry picked from commit 61bceb1bff4b1f9c126b18dc971ca3e6d8c71c40)
|
||||
|
||||
Resolves: RHEL-158303
|
||||
---
|
||||
src/nspawn/nspawn.c | 18 ++++++++++++++----
|
||||
1 file changed, 14 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
|
||||
index 724639df5c..acf579c007 100644
|
||||
--- a/src/nspawn/nspawn.c
|
||||
+++ b/src/nspawn/nspawn.c
|
||||
@@ -4739,8 +4739,13 @@ static int merge_settings(Settings *settings, const char *path) {
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_EPHEMERAL) == 0 &&
|
||||
- settings->ephemeral >= 0)
|
||||
- arg_ephemeral = settings->ephemeral;
|
||||
+ settings->ephemeral >= 0) {
|
||||
+
|
||||
+ if (!arg_settings_trusted)
|
||||
+ log_warning("Ignoring ephemeral setting, file %s is not trusted.", path);
|
||||
+ else
|
||||
+ arg_ephemeral = settings->ephemeral;
|
||||
+ }
|
||||
|
||||
if ((arg_settings_mask & SETTING_DIRECTORY) == 0 &&
|
||||
settings->root) {
|
||||
@@ -4908,8 +4913,13 @@ static int merge_settings(Settings *settings, const char *path) {
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_BIND_USER) == 0 &&
|
||||
- !strv_isempty(settings->bind_user))
|
||||
- strv_free_and_replace(arg_bind_user, settings->bind_user);
|
||||
+ !strv_isempty(settings->bind_user)) {
|
||||
+
|
||||
+ if (!arg_settings_trusted)
|
||||
+ log_warning("Ignoring bind user setting, file %s is not trusted.", path);
|
||||
+ else
|
||||
+ strv_free_and_replace(arg_bind_user, settings->bind_user);
|
||||
+ }
|
||||
|
||||
if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0 &&
|
||||
settings->notify_ready >= 0)
|
||||
32
0622-nspawn-normalize-pivot_root-paths.patch
Normal file
32
0622-nspawn-normalize-pivot_root-paths.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 5f8d0355128c2aaa59ffc56916d1939d6022e6db Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Wed, 11 Mar 2026 13:27:14 +0000
|
||||
Subject: [PATCH] nspawn: normalize pivot_root paths
|
||||
|
||||
Originally reported on yeswehack.com as:
|
||||
YWH-PGM9780-116
|
||||
|
||||
Follow-up for b53ede699cdc5233041a22591f18863fb3fe2672
|
||||
|
||||
(cherry picked from commit 7b85f5498a958e5bb660c703b8f4a71cceed3373)
|
||||
|
||||
Resolves: RHEL-158303
|
||||
---
|
||||
src/nspawn/nspawn-mount.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
|
||||
index ddbdba6fb6..c233cdf600 100644
|
||||
--- a/src/nspawn/nspawn-mount.c
|
||||
+++ b/src/nspawn/nspawn-mount.c
|
||||
@@ -1309,7 +1309,9 @@ int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s
|
||||
|
||||
if (!path_is_absolute(root_new))
|
||||
return -EINVAL;
|
||||
- if (root_old && !path_is_absolute(root_old))
|
||||
+ if (!path_is_normalized(root_new))
|
||||
+ return -EINVAL;
|
||||
+ if (root_old && (!path_is_absolute(root_old) || !path_is_normalized(root_old)))
|
||||
return -EINVAL;
|
||||
|
||||
free_and_replace(*pivot_root_new, root_new);
|
||||
124
0623-udev-check-for-invalid-chars-in-various-fields-recei.patch
Normal file
124
0623-udev-check-for-invalid-chars-in-various-fields-recei.patch
Normal file
@ -0,0 +1,124 @@
|
||||
From 193648df27a08e5564c09f82115ee0c282c9fe85 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Fri, 6 Mar 2026 19:32:35 +0000
|
||||
Subject: [PATCH] udev: check for invalid chars in various fields received from
|
||||
the kernel
|
||||
|
||||
(cherry picked from commit 16325b35fa6ecb25f66534a562583ce3b96d52f3)
|
||||
|
||||
Resolves: RHEL-158354
|
||||
---
|
||||
src/udev/dmi_memory_id/dmi_memory_id.c | 3 ++-
|
||||
src/udev/scsi_id/scsi_id.c | 5 +++--
|
||||
src/udev/udev-builtin-net_id.c | 9 +++++++++
|
||||
src/udev/v4l_id/v4l_id.c | 5 ++++-
|
||||
4 files changed, 18 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/udev/dmi_memory_id/dmi_memory_id.c b/src/udev/dmi_memory_id/dmi_memory_id.c
|
||||
index e62222a307..d8370bbe3f 100644
|
||||
--- a/src/udev/dmi_memory_id/dmi_memory_id.c
|
||||
+++ b/src/udev/dmi_memory_id/dmi_memory_id.c
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "string-util.h"
|
||||
#include "udev-util.h"
|
||||
#include "unaligned.h"
|
||||
+#include "utf8.h"
|
||||
|
||||
#define SUPPORTED_SMBIOS_VER 0x030300
|
||||
|
||||
@@ -185,7 +186,7 @@ static void dmi_memory_device_string(
|
||||
|
||||
str = strdupa_safe(dmi_string(h, s));
|
||||
str = strstrip(str);
|
||||
- if (!isempty(str))
|
||||
+ if (!isempty(str) && utf8_is_valid(str) && !string_has_cc(str, /* ok= */ NULL))
|
||||
printf("MEMORY_DEVICE_%u_%s=%s\n", slot_num, attr_suffix, str);
|
||||
}
|
||||
|
||||
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
|
||||
index b63a46a730..650bf7824f 100644
|
||||
--- a/src/udev/scsi_id/scsi_id.c
|
||||
+++ b/src/udev/scsi_id/scsi_id.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "strv.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "udev-util.h"
|
||||
+#include "utf8.h"
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "device", required_argument, NULL, 'd' },
|
||||
@@ -450,8 +451,8 @@ static int scsi_id(char *maj_min_dev) {
|
||||
}
|
||||
if (dev_scsi.tgpt_group[0] != '\0')
|
||||
printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group);
|
||||
- if (dev_scsi.unit_serial_number[0] != '\0')
|
||||
- printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number);
|
||||
+ if (dev_scsi.unit_serial_number[0] != '\0' && utf8_is_valid(dev_scsi.unit_serial_number) && !string_has_cc(dev_scsi.unit_serial_number, /* ok= */ NULL))
|
||||
+ printf("ID_SCSI_SERIAL=%s\n", serial_str);
|
||||
goto out;
|
||||
}
|
||||
|
||||
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
|
||||
index 96e792bcde..0d3c62f4b5 100644
|
||||
--- a/src/udev/udev-builtin-net_id.c
|
||||
+++ b/src/udev/udev-builtin-net_id.c
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "strv.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "udev-builtin.h"
|
||||
+#include "utf8.h"
|
||||
|
||||
#define ONBOARD_14BIT_INDEX_MAX ((1U << 14) - 1)
|
||||
#define ONBOARD_16BIT_INDEX_MAX ((1U << 16) - 1)
|
||||
@@ -236,6 +237,9 @@ static int get_port_specifier(sd_device *dev, bool fallback_to_dev_id, char **re
|
||||
}
|
||||
}
|
||||
|
||||
+ if (!utf8_is_valid(phys_port_name) || string_has_cc(phys_port_name, /* ok= */ NULL))
|
||||
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid phys_port_name");
|
||||
+
|
||||
/* Otherwise, use phys_port_name as is. */
|
||||
buf = strjoin("n", phys_port_name);
|
||||
if (!buf)
|
||||
@@ -340,6 +344,9 @@ static int names_pci_onboard_label(UdevEvent *event, sd_device *pci_dev, const c
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(pci_dev, r, "Failed to get PCI onboard label: %m");
|
||||
|
||||
+ if (!utf8_is_valid(label) || string_has_cc(label, /* ok= */ NULL))
|
||||
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid label");
|
||||
+
|
||||
char str[ALTIFNAMSIZ];
|
||||
if (snprintf_ok(str, sizeof str, "%s%s",
|
||||
naming_scheme_has(NAMING_LABEL_NOPREFIX) ? "" : prefix,
|
||||
@@ -1257,6 +1264,8 @@ static int names_netdevsim(UdevEvent *event, const char *prefix) {
|
||||
if (isempty(phys_port_name))
|
||||
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"The 'phys_port_name' attribute is empty.");
|
||||
+ if (!utf8_is_valid(phys_port_name) || string_has_cc(phys_port_name, /* ok= */ NULL))
|
||||
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid phys_port_name");
|
||||
|
||||
char str[ALTIFNAMSIZ];
|
||||
if (snprintf_ok(str, sizeof str, "%si%un%s", prefix, addr, phys_port_name))
|
||||
diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c
|
||||
index 5c540659f3..8e29f8898e 100644
|
||||
--- a/src/udev/v4l_id/v4l_id.c
|
||||
+++ b/src/udev/v4l_id/v4l_id.c
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "build.h"
|
||||
#include "fd-util.h"
|
||||
#include "main-func.h"
|
||||
+#include "string-util.h"
|
||||
+#include "utf8.h"
|
||||
|
||||
static const char *arg_device = NULL;
|
||||
|
||||
@@ -72,7 +74,8 @@ static int run(int argc, char *argv[]) {
|
||||
int capabilities;
|
||||
|
||||
printf("ID_V4L_VERSION=2\n");
|
||||
- printf("ID_V4L_PRODUCT=%s\n", v2cap.card);
|
||||
+ if (utf8_is_valid((char *)v2cap.card) && !string_has_cc((char *)v2cap.card, /* ok= */ NULL))
|
||||
+ printf("ID_V4L_PRODUCT=%s\n", v2cap.card);
|
||||
printf("ID_V4L_CAPABILITIES=:");
|
||||
|
||||
if (v2cap.capabilities & V4L2_CAP_DEVICE_CAPS)
|
||||
@ -0,0 +1,45 @@
|
||||
From 611f421f23f2e1a560eb76bb8d922c8a942a9da5 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Fri, 6 Mar 2026 19:42:16 +0000
|
||||
Subject: [PATCH] udev: ensure there is space for trailing NUL before calling
|
||||
sprintf
|
||||
|
||||
sprintf will write 5 characters, as it adds a trailing NUL byte.
|
||||
|
||||
Reported on yeswehack.com as:
|
||||
YWH-PGM9780-62
|
||||
|
||||
Follow-up for 8cfcf9980a3
|
||||
|
||||
(cherry picked from commit 69e4ba69d689748d1d515c5a8d063073df3c5821)
|
||||
|
||||
Related: RHEL-158354
|
||||
---
|
||||
src/shared/device-nodes.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/shared/device-nodes.c b/src/shared/device-nodes.c
|
||||
index d08c40fe2c..20206ee7b4 100644
|
||||
--- a/src/shared/device-nodes.c
|
||||
+++ b/src/shared/device-nodes.c
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "device-nodes.h"
|
||||
#include "path-util.h"
|
||||
+#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
@@ -39,10 +40,10 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) {
|
||||
|
||||
} else if (str[i] == '\\' || !allow_listed_char_for_devnode(str[i], NULL)) {
|
||||
|
||||
- if (len-j < 4)
|
||||
+ if (len-j < 5)
|
||||
return -EINVAL;
|
||||
|
||||
- sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
|
||||
+ assert_se(snprintf_ok(&str_enc[j], 5, "\\x%02x", (unsigned char) str[i]));
|
||||
j += 4;
|
||||
|
||||
} else {
|
||||
32
0625-udev-ensure-tag-parsing-stays-within-bounds.patch
Normal file
32
0625-udev-ensure-tag-parsing-stays-within-bounds.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 6a324492fc5710816ef376d2e012b1661f50b291 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Fri, 6 Mar 2026 20:25:05 +0000
|
||||
Subject: [PATCH] udev: ensure tag parsing stays within bounds
|
||||
|
||||
This cannot actually happen, but add a safety check nonetheless.
|
||||
|
||||
Reported on yeswehack.com as:
|
||||
YWH-PGM9780-43
|
||||
|
||||
Follow-up for d7867b31836173d1a943ecb1cab6484536126411
|
||||
|
||||
(cherry picked from commit 45a200cd751fae382f4145760cf84fd181db1319)
|
||||
|
||||
Related: RHEL-158354
|
||||
---
|
||||
src/udev/udev-builtin-path_id.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
|
||||
index d6ea471482..545757dc09 100644
|
||||
--- a/src/udev/udev-builtin-path_id.c
|
||||
+++ b/src/udev/udev-builtin-path_id.c
|
||||
@@ -667,7 +667,7 @@ static void add_id_tag(UdevEvent *event, const char *path) {
|
||||
size_t i = 0;
|
||||
|
||||
/* compose valid udev tag name */
|
||||
- for (const char *p = path; *p; p++) {
|
||||
+ for (const char *p = path; *p && i < sizeof(tag) - 1; p++) {
|
||||
if (ascii_isdigit(*p) ||
|
||||
ascii_isalpha(*p) ||
|
||||
*p == '-') {
|
||||
32
0626-udev-fix-review-mixup.patch
Normal file
32
0626-udev-fix-review-mixup.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 51ee6986c85c060fbbd644d94553edc6854ee5d6 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Fri, 13 Mar 2026 11:10:47 +0000
|
||||
Subject: [PATCH] udev: fix review mixup
|
||||
|
||||
The previous version in the PR changed variable and sanitized it
|
||||
in place. The second version switched to skip if CCs are in the
|
||||
string instead, but didn't move back to the original variable.
|
||||
Because it's an existing variable, no CI caught it.
|
||||
|
||||
Follow-up for 16325b35fa6ecb25f66534a562583ce3b96d52f3
|
||||
|
||||
(cherry picked from commit 54f880b02ecf7362e630ffc885d1466df6ee6820)
|
||||
|
||||
Resolves: RHEL-158354
|
||||
---
|
||||
src/udev/scsi_id/scsi_id.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
|
||||
index 650bf7824f..854f8ffa05 100644
|
||||
--- a/src/udev/scsi_id/scsi_id.c
|
||||
+++ b/src/udev/scsi_id/scsi_id.c
|
||||
@@ -452,7 +452,7 @@ static int scsi_id(char *maj_min_dev) {
|
||||
if (dev_scsi.tgpt_group[0] != '\0')
|
||||
printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group);
|
||||
if (dev_scsi.unit_serial_number[0] != '\0' && utf8_is_valid(dev_scsi.unit_serial_number) && !string_has_cc(dev_scsi.unit_serial_number, /* ok= */ NULL))
|
||||
- printf("ID_SCSI_SERIAL=%s\n", serial_str);
|
||||
+ printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
From 2ce69dc53f7c6076dcbdf60ef0211f0b8ea3f876 Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Fri, 10 Apr 2026 19:04:04 +0100
|
||||
Subject: [PATCH] udev/scsi-id: check for invalid chars in various fields
|
||||
received from the kernel
|
||||
|
||||
Follow-up for 16325b35fa6ecb25f66534a562583ce3b96d52f3
|
||||
|
||||
(cherry picked from commit 5f700d148c44063c0f0dbb9fc136866339cd3fa7)
|
||||
|
||||
Related: RHEL-158354
|
||||
---
|
||||
src/udev/scsi_id/scsi_id.c | 12 ++++++++----
|
||||
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
|
||||
index 854f8ffa05..bc350fed47 100644
|
||||
--- a/src/udev/scsi_id/scsi_id.c
|
||||
+++ b/src/udev/scsi_id/scsi_id.c
|
||||
@@ -398,6 +398,10 @@ static int set_inq_values(struct scsi_id_device *dev_scsi, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static bool scsi_string_is_valid(const char *s) {
|
||||
+ return !isempty(s) && utf8_is_valid(s) && !string_has_cc(s, /* ok= */ NULL);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* scsi_id: try to get an id, if one is found, printf it to stdout.
|
||||
* returns a value passed to exit() - 0 if printed an id, else 1.
|
||||
@@ -441,17 +445,17 @@ static int scsi_id(char *maj_min_dev) {
|
||||
udev_replace_chars(serial_str, NULL);
|
||||
printf("ID_SERIAL_SHORT=%s\n", serial_str);
|
||||
}
|
||||
- if (dev_scsi.wwn[0] != '\0') {
|
||||
+ if (scsi_string_is_valid(dev_scsi.wwn)) {
|
||||
printf("ID_WWN=0x%s\n", dev_scsi.wwn);
|
||||
- if (dev_scsi.wwn_vendor_extension[0] != '\0') {
|
||||
+ if (scsi_string_is_valid(dev_scsi.wwn_vendor_extension)) {
|
||||
printf("ID_WWN_VENDOR_EXTENSION=0x%s\n", dev_scsi.wwn_vendor_extension);
|
||||
printf("ID_WWN_WITH_EXTENSION=0x%s%s\n", dev_scsi.wwn, dev_scsi.wwn_vendor_extension);
|
||||
} else
|
||||
printf("ID_WWN_WITH_EXTENSION=0x%s\n", dev_scsi.wwn);
|
||||
}
|
||||
- if (dev_scsi.tgpt_group[0] != '\0')
|
||||
+ if (scsi_string_is_valid(dev_scsi.tgpt_group))
|
||||
printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group);
|
||||
- if (dev_scsi.unit_serial_number[0] != '\0' && utf8_is_valid(dev_scsi.unit_serial_number) && !string_has_cc(dev_scsi.unit_serial_number, /* ok= */ NULL))
|
||||
+ if (scsi_string_is_valid(dev_scsi.unit_serial_number))
|
||||
printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number);
|
||||
goto out;
|
||||
}
|
||||
88
0628-udev-builtin-net-id-print-cescaped-bad-attributes.patch
Normal file
88
0628-udev-builtin-net-id-print-cescaped-bad-attributes.patch
Normal file
@ -0,0 +1,88 @@
|
||||
From de3d4ab2348dc313a08fa3b667acf42a34d19bb0 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@amutable.com>
|
||||
Date: Wed, 11 Mar 2026 11:27:48 +0100
|
||||
Subject: [PATCH] udev-builtin-net-id: print cescaped bad attributes
|
||||
|
||||
Follow-up for 16325b35fa6ecb25f66534a562583ce3b96d52f3. Let's
|
||||
log those bad value to make it easier to figure out why things
|
||||
are not working if we reject an attribute.
|
||||
|
||||
(cherry picked from commit 7c4047957ef58744ecfad6d277f7c45d430f6d70)
|
||||
|
||||
Related: RHEL-158354
|
||||
---
|
||||
src/udev/udev-builtin-net_id.c | 19 ++++++++++++-------
|
||||
1 file changed, 12 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
|
||||
index 0d3c62f4b5..fd39a90c87 100644
|
||||
--- a/src/udev/udev-builtin-net_id.c
|
||||
+++ b/src/udev/udev-builtin-net_id.c
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "dirent-util.h"
|
||||
+#include "escape.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@@ -45,6 +46,12 @@
|
||||
#define ONBOARD_14BIT_INDEX_MAX ((1U << 14) - 1)
|
||||
#define ONBOARD_16BIT_INDEX_MAX ((1U << 16) - 1)
|
||||
|
||||
+static int log_invalid_device_attr(sd_device *dev, const char *attr, const char *value) {
|
||||
+ _cleanup_free_ char *escaped = cescape(value);
|
||||
+ return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL),
|
||||
+ "Invalid %s value '%s'.", attr, strnull(escaped));
|
||||
+}
|
||||
+
|
||||
/* skip intermediate virtio devices */
|
||||
static sd_device *device_skip_virtio(sd_device *dev) {
|
||||
/* there can only ever be one virtio bus per parent device, so we can
|
||||
@@ -238,7 +245,7 @@ static int get_port_specifier(sd_device *dev, bool fallback_to_dev_id, char **re
|
||||
}
|
||||
|
||||
if (!utf8_is_valid(phys_port_name) || string_has_cc(phys_port_name, /* ok= */ NULL))
|
||||
- return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid phys_port_name");
|
||||
+ return log_invalid_device_attr(dev, "phys_port_name", phys_port_name);
|
||||
|
||||
/* Otherwise, use phys_port_name as is. */
|
||||
buf = strjoin("n", phys_port_name);
|
||||
@@ -345,7 +352,7 @@ static int names_pci_onboard_label(UdevEvent *event, sd_device *pci_dev, const c
|
||||
return log_device_debug_errno(pci_dev, r, "Failed to get PCI onboard label: %m");
|
||||
|
||||
if (!utf8_is_valid(label) || string_has_cc(label, /* ok= */ NULL))
|
||||
- return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid label");
|
||||
+ return log_invalid_device_attr(dev, "label", label);
|
||||
|
||||
char str[ALTIFNAMSIZ];
|
||||
if (snprintf_ok(str, sizeof str, "%s%s",
|
||||
@@ -751,8 +758,7 @@ static int names_vio(UdevEvent *event, const char *prefix) {
|
||||
"VIO bus ID and slot ID have invalid length: %s", s);
|
||||
|
||||
if (!in_charset(s, HEXDIGITS))
|
||||
- return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL),
|
||||
- "VIO bus ID and slot ID contain invalid characters: %s", s);
|
||||
+ return log_invalid_device_attr(dev, "VIO bus ID and slot ID", s);
|
||||
|
||||
/* Parse only slot ID (the last 4 hexdigits). */
|
||||
r = safe_atou_full(s + 4, 16, &slotid);
|
||||
@@ -808,8 +814,7 @@ static int names_platform(UdevEvent *event, const char *prefix) {
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!in_charset(vendor, validchars))
|
||||
- return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ENOENT),
|
||||
- "Platform vendor contains invalid characters: %s", vendor);
|
||||
+ return log_invalid_device_attr(dev, "platform vendor", vendor);
|
||||
|
||||
ascii_strlower(vendor);
|
||||
|
||||
@@ -1265,7 +1270,7 @@ static int names_netdevsim(UdevEvent *event, const char *prefix) {
|
||||
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"The 'phys_port_name' attribute is empty.");
|
||||
if (!utf8_is_valid(phys_port_name) || string_has_cc(phys_port_name, /* ok= */ NULL))
|
||||
- return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid phys_port_name");
|
||||
+ return log_invalid_device_attr(dev, "phys_port_name", phys_port_name);
|
||||
|
||||
char str[ALTIFNAMSIZ];
|
||||
if (snprintf_ok(str, sizeof str, "%si%un%s", prefix, addr, phys_port_name))
|
||||
@ -0,0 +1,34 @@
|
||||
From e1498685abfebf42a64a5545be6c925d1adefa66 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Sekletar <msekleta@redhat.com>
|
||||
Date: Fri, 9 Jan 2026 17:18:41 +0100
|
||||
Subject: [PATCH] core: only activate transaction that contain useful jobs
|
||||
|
||||
If no real jobs were added to the transaction, do not activate it.
|
||||
The JOB_NOP anchor does not perform any useful work and activating
|
||||
such transaction only wastes resources.
|
||||
|
||||
Fixes #9751
|
||||
|
||||
(cherry picked from commit bcbf80c43d107ad233edc990a60bdc40f517085a)
|
||||
|
||||
Resolves: RHEL-143728
|
||||
---
|
||||
src/core/manager.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/src/core/manager.c b/src/core/manager.c
|
||||
index f7f901521b..22efab33df 100644
|
||||
--- a/src/core/manager.c
|
||||
+++ b/src/core/manager.c
|
||||
@@ -2297,6 +2297,11 @@ int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error
|
||||
tr->anchor_job,
|
||||
mode == JOB_IGNORE_DEPENDENCIES ? TRANSACTION_IGNORE_ORDER : 0);
|
||||
|
||||
+ /* Only activate the transaction if it contains jobs other than NOP anchor.
|
||||
+ * Short-circuiting here avoids unnecessary processing, such as emitting D-Bus signals. */
|
||||
+ if (hashmap_size(tr->jobs) <= 1)
|
||||
+ return 0;
|
||||
+
|
||||
r = transaction_activate(tr, m, mode, NULL, e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
27
0630-journald-extend-STDOUT_STREAMS_MAX-to-64k.patch
Normal file
27
0630-journald-extend-STDOUT_STREAMS_MAX-to-64k.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 4a438fbccf6b533d4546e2e9b37919684a9a2d90 Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Sun, 1 Dec 2024 14:46:40 +0900
|
||||
Subject: [PATCH] journald: extend STDOUT_STREAMS_MAX to 64k
|
||||
|
||||
Closes #35390.
|
||||
|
||||
(cherry picked from commit c576ba7182f54f352c03f0768c9178b173fb8bcb)
|
||||
|
||||
Resolves: RHEL-168098
|
||||
---
|
||||
src/journal/journald-stream.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
|
||||
index b019eda0d2..f039a33ad2 100644
|
||||
--- a/src/journal/journald-stream.c
|
||||
+++ b/src/journal/journald-stream.c
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "unit-name.h"
|
||||
#include "user-util.h"
|
||||
|
||||
-#define STDOUT_STREAMS_MAX 4096
|
||||
+#define STDOUT_STREAMS_MAX (64*1024)
|
||||
|
||||
/* During the "setup" protocol phase of the stream logic let's define a different maximum line length than
|
||||
* during the actual operational phase. We want to allow users to specify very short line lengths after all,
|
||||
76
0631-string-util-introduce-strprepend-helper.patch
Normal file
76
0631-string-util-introduce-strprepend-helper.patch
Normal file
@ -0,0 +1,76 @@
|
||||
From 4b773b91307715d016c84542037cbfbc16dbdcfa Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Mon, 10 Feb 2025 19:03:08 +0100
|
||||
Subject: [PATCH] string-util: introduce strprepend() helper
|
||||
|
||||
(cherry picked from commit b40694f5fc21317af617f37bb03304c84ca993c8)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/basic/string-util.c | 14 ++++++++++++++
|
||||
src/basic/string-util.h | 2 ++
|
||||
src/test/test-string-util.c | 13 +++++++++++++
|
||||
3 files changed, 29 insertions(+)
|
||||
|
||||
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
|
||||
index 7122d5145e..6d490e7444 100644
|
||||
--- a/src/basic/string-util.c
|
||||
+++ b/src/basic/string-util.c
|
||||
@@ -46,6 +46,20 @@ char* first_word(const char *s, const char *word) {
|
||||
return (char*) nw;
|
||||
}
|
||||
|
||||
+char* strprepend(char **x, const char *s) {
|
||||
+ assert(x);
|
||||
+
|
||||
+ if (isempty(s) && *x)
|
||||
+ return *x;
|
||||
+
|
||||
+ char *p = strjoin(strempty(s), *x);
|
||||
+ if (!p)
|
||||
+ return NULL;
|
||||
+
|
||||
+ free_and_replace(*x, p);
|
||||
+ return *x;
|
||||
+}
|
||||
+
|
||||
char* strnappend(const char *s, const char *suffix, size_t b) {
|
||||
size_t a;
|
||||
char *r;
|
||||
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
|
||||
index a1592b6e6d..7ce26b30f9 100644
|
||||
--- a/src/basic/string-util.h
|
||||
+++ b/src/basic/string-util.h
|
||||
@@ -106,6 +106,8 @@ static inline const char* empty_or_dash_to_null(const char *p) {
|
||||
|
||||
char* first_word(const char *s, const char *word) _pure_;
|
||||
|
||||
+char* strprepend(char **x, const char *s);
|
||||
+
|
||||
char* strnappend(const char *s, const char *suffix, size_t length);
|
||||
|
||||
char* strjoin_real(const char *x, ...) _sentinel_;
|
||||
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
|
||||
index b692af6cc0..0474f3a162 100644
|
||||
--- a/src/test/test-string-util.c
|
||||
+++ b/src/test/test-string-util.c
|
||||
@@ -1335,6 +1335,19 @@ TEST(strextendn) {
|
||||
x = mfree(x);
|
||||
}
|
||||
|
||||
+TEST(strprepend) {
|
||||
+ _cleanup_free_ char *x = NULL;
|
||||
+
|
||||
+ ASSERT_STREQ(strprepend(&x, NULL), "");
|
||||
+ x = mfree(x);
|
||||
+
|
||||
+ ASSERT_STREQ(strprepend(&x, ""), "");
|
||||
+
|
||||
+ ASSERT_STREQ(strprepend(&x, "xxx"), "xxx");
|
||||
+ ASSERT_STREQ(strprepend(&x, "bar"), "barxxx");
|
||||
+ ASSERT_STREQ(strprepend(&x, "foo"), "foobarxxx");
|
||||
+}
|
||||
+
|
||||
TEST(strlevenshtein) {
|
||||
assert_se(strlevenshtein(NULL, NULL) == 0);
|
||||
assert_se(strlevenshtein("", "") == 0);
|
||||
139
0632-missing-add-quotactl_fd-wrapper.patch
Normal file
139
0632-missing-add-quotactl_fd-wrapper.patch
Normal file
@ -0,0 +1,139 @@
|
||||
From 125c2b786edaed0c11ef923e10cf0448909abf63 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Fri, 10 Jan 2025 11:33:03 +0100
|
||||
Subject: [PATCH] missing: add quotactl_fd() wrapper
|
||||
|
||||
(cherry picked from commit 7adafb0832a709f4fcf1210602224cb049d02857)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
meson.build | 1 +
|
||||
src/basic/missing_syscall.h | 16 ++++++++
|
||||
src/basic/missing_syscall_def.h | 68 +++++++++++++++++++++++++++++++++
|
||||
src/basic/missing_syscalls.py | 1 +
|
||||
4 files changed, 86 insertions(+)
|
||||
|
||||
diff --git a/meson.build b/meson.build
|
||||
index fa39da2d38..8b9818a202 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -675,6 +675,7 @@ foreach ident : [
|
||||
['fsmount', '''#include <sys/mount.h>'''],
|
||||
['getdents64', '''#include <dirent.h>'''],
|
||||
['pidfd_spawn', '''#include <spawn.h>'''],
|
||||
+ ['quotactl_fd', '''#include <sys/quota.h>'''],
|
||||
]
|
||||
|
||||
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
|
||||
diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h
|
||||
index e2cd8b4e35..8ac4c5288a 100644
|
||||
--- a/src/basic/missing_syscall.h
|
||||
+++ b/src/basic/missing_syscall.h
|
||||
@@ -695,3 +695,19 @@ int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags,
|
||||
* at build time) and just define it. Once the kernel drops ia64 support, we can drop this too. */
|
||||
#define HAVE_CLONE 1
|
||||
#endif
|
||||
+
|
||||
+/* ======================================================================= */
|
||||
+
|
||||
+#if !HAVE_QUOTACTL_FD
|
||||
+
|
||||
+static inline int missing_quotactl_fd(int fd, int cmd, int id, void *addr) {
|
||||
+#if defined __NR_quotactl_fd
|
||||
+ return syscall(__NR_quotactl_fd, fd, cmd, id, addr);
|
||||
+#else
|
||||
+ errno = ENOSYS;
|
||||
+ return -1;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+# define quotactl_fd missing_quotactl_fd
|
||||
+#endif
|
||||
diff --git a/src/basic/missing_syscall_def.h b/src/basic/missing_syscall_def.h
|
||||
index f679422a2e..cd22058cdd 100644
|
||||
--- a/src/basic/missing_syscall_def.h
|
||||
+++ b/src/basic/missing_syscall_def.h
|
||||
@@ -1197,3 +1197,71 @@ assert_cc(__NR_statx == systemd_NR_statx);
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
+
|
||||
+#ifndef __IGNORE_quotactl_fd
|
||||
+# if defined(__aarch64__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__alpha__)
|
||||
+# define systemd_NR_quotactl_fd 553
|
||||
+# elif defined(__arc__) || defined(__tilegx__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__arm__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__i386__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__ia64__)
|
||||
+# define systemd_NR_quotactl_fd 1467
|
||||
+# elif defined(__loongarch_lp64)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__m68k__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(_MIPS_SIM)
|
||||
+# if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
+# define systemd_NR_quotactl_fd 4443
|
||||
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
+# define systemd_NR_quotactl_fd 6443
|
||||
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
+# define systemd_NR_quotactl_fd 5443
|
||||
+# else
|
||||
+# error "Unknown MIPS ABI"
|
||||
+# endif
|
||||
+# elif defined(__hppa__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__powerpc__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__riscv)
|
||||
+# if __riscv_xlen == 32
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif __riscv_xlen == 64
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# else
|
||||
+# error "Unknown RISC-V ABI"
|
||||
+# endif
|
||||
+# elif defined(__s390__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__sparc__)
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# elif defined(__x86_64__)
|
||||
+# if defined(__ILP32__)
|
||||
+# define systemd_NR_quotactl_fd (443 | /* __X32_SYSCALL_BIT */ 0x40000000)
|
||||
+# else
|
||||
+# define systemd_NR_quotactl_fd 443
|
||||
+# endif
|
||||
+# elif !defined(missing_arch_template)
|
||||
+# warning "quotactl_fd() syscall number is unknown for your architecture"
|
||||
+# endif
|
||||
+
|
||||
+/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
+# if defined __NR_quotactl_fd && __NR_quotactl_fd >= 0
|
||||
+# if defined systemd_NR_quotactl_fd
|
||||
+assert_cc(__NR_quotactl_fd == systemd_NR_quotactl_fd);
|
||||
+# endif
|
||||
+# else
|
||||
+# if defined __NR_quotactl_fd
|
||||
+# undef __NR_quotactl_fd
|
||||
+# endif
|
||||
+# if defined systemd_NR_quotactl_fd && systemd_NR_quotactl_fd >= 0
|
||||
+# define __NR_quotactl_fd systemd_NR_quotactl_fd
|
||||
+# endif
|
||||
+# endif
|
||||
+#endif
|
||||
diff --git a/src/basic/missing_syscalls.py b/src/basic/missing_syscalls.py
|
||||
index 3749e89c4e..a15fed0358 100644
|
||||
--- a/src/basic/missing_syscalls.py
|
||||
+++ b/src/basic/missing_syscalls.py
|
||||
@@ -20,6 +20,7 @@ SYSCALLS = [
|
||||
'pidfd_open',
|
||||
'pidfd_send_signal',
|
||||
'pkey_mprotect',
|
||||
+ 'quotactl_fd',
|
||||
'renameat2',
|
||||
'setns',
|
||||
'statx',
|
||||
413
0633-homed-always-use-quotactl_fd-if-its-available.patch
Normal file
413
0633-homed-always-use-quotactl_fd-if-its-available.patch
Normal file
@ -0,0 +1,413 @@
|
||||
From 58fc6c67b9723180f1c54e8b72e7f341e77a7591 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Mon, 31 Mar 2025 11:47:17 +0200
|
||||
Subject: [PATCH] homed: always use quotactl_fd() if its available
|
||||
|
||||
Let's always prefer quotactl_fd() when it's available and use quotactl()
|
||||
only as as a fallback on old kernels.
|
||||
|
||||
This way we can operate on the fds we typically already have open, or if
|
||||
needed we can open a new one, and use for multiple fs operation.
|
||||
|
||||
In the long run we should really focus on operating exclusively by fd
|
||||
instead of by path, by device nor or otherwise. This gets us a step
|
||||
closer to that.
|
||||
|
||||
(cherry picked from commit 5daca30b0f28ffdcfdd1e6b9df9691b89d1b6b0f)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/home/homed-home.c | 16 +++++++---
|
||||
src/home/homed-manager.c | 12 ++++---
|
||||
src/home/homework-directory.c | 6 ++--
|
||||
src/home/homework-fscrypt.c | 2 +-
|
||||
src/home/homework-quota.c | 57 +++++++++++++++++++++++-----------
|
||||
src/home/homework-quota.h | 6 ++--
|
||||
src/shared/quota-util.c | 34 +++++++++-----------
|
||||
src/shared/quota-util.h | 3 +-
|
||||
units/systemd-homed.service.in | 2 +-
|
||||
9 files changed, 80 insertions(+), 58 deletions(-)
|
||||
|
||||
diff --git a/src/home/homed-home.c b/src/home/homed-home.c
|
||||
index 44e3274c42..84b2a4935e 100644
|
||||
--- a/src/home/homed-home.c
|
||||
+++ b/src/home/homed-home.c
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "memfd-util.h"
|
||||
#include "missing_magic.h"
|
||||
#include "missing_mman.h"
|
||||
-#include "missing_syscall.h"
|
||||
#include "mkdir.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
@@ -2414,6 +2413,7 @@ static int home_get_disk_status_directory(
|
||||
uint64_t disk_size = UINT64_MAX, disk_usage = UINT64_MAX, disk_free = UINT64_MAX,
|
||||
disk_ceiling = UINT64_MAX, disk_floor = UINT64_MAX;
|
||||
mode_t access_mode = MODE_INVALID;
|
||||
+ _cleanup_close_ int fd = -EBADF;
|
||||
statfs_f_type_t fstype = 0;
|
||||
struct statfs sfs;
|
||||
struct dqblk req;
|
||||
@@ -2435,7 +2435,13 @@ static int home_get_disk_status_directory(
|
||||
if (!path)
|
||||
goto finish;
|
||||
|
||||
- if (statfs(path, &sfs) < 0)
|
||||
+ fd = open(path, O_CLOEXEC|O_RDONLY);
|
||||
+ if (fd < 0) {
|
||||
+ log_debug_errno(errno, "Failed to open '%s', ignoring: %m", path);
|
||||
+ goto finish;
|
||||
+ }
|
||||
+
|
||||
+ if (fstatfs(fd, &sfs) < 0)
|
||||
log_debug_errno(errno, "Failed to statfs() %s, ignoring: %m", path);
|
||||
else {
|
||||
disk_free = sfs.f_bsize * sfs.f_bavail;
|
||||
@@ -2449,13 +2455,13 @@ static int home_get_disk_status_directory(
|
||||
|
||||
if (IN_SET(h->record->storage, USER_CLASSIC, USER_DIRECTORY, USER_SUBVOLUME)) {
|
||||
|
||||
- r = btrfs_is_subvol(path);
|
||||
+ r = btrfs_is_subvol_fd(fd);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to determine whether %s is a btrfs subvolume: %m", path);
|
||||
else if (r > 0) {
|
||||
BtrfsQuotaInfo qi;
|
||||
|
||||
- r = btrfs_subvol_get_subtree_quota(path, 0, &qi);
|
||||
+ r = btrfs_subvol_get_subtree_quota_fd(fd, /* subvol_id= */ 0, &qi);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to query btrfs subtree quota, ignoring: %m");
|
||||
else {
|
||||
@@ -2488,7 +2494,7 @@ static int home_get_disk_status_directory(
|
||||
}
|
||||
|
||||
if (IN_SET(h->record->storage, USER_CLASSIC, USER_DIRECTORY, USER_FSCRYPT)) {
|
||||
- r = quotactl_path(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), path, h->uid, &req);
|
||||
+ r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, USRQUOTA), h->uid, &req);
|
||||
if (r < 0) {
|
||||
if (ERRNO_IS_NOT_SUPPORTED(r)) {
|
||||
log_debug_errno(r, "No UID quota support on %s.", path);
|
||||
diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c
|
||||
index 6b9e4fcf11..8d0e8514bf 100644
|
||||
--- a/src/home/homed-manager.c
|
||||
+++ b/src/home/homed-manager.c
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "user-record.h"
|
||||
#include "user-util.h"
|
||||
#include "varlink-io.systemd.UserDatabase.h"
|
||||
+#include "varlink-io.systemd.service.h"
|
||||
#include "varlink-util.h"
|
||||
|
||||
/* Where to look for private/public keys that are used to sign the user records. We are not using
|
||||
@@ -513,14 +514,15 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) {
|
||||
struct dqblk req;
|
||||
struct stat st;
|
||||
|
||||
- if (stat(where, &st) < 0) {
|
||||
+ _cleanup_close_ int fd = open(where, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||
+ if (fd < 0) {
|
||||
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
|
||||
- "Failed to stat %s, ignoring: %m", where);
|
||||
+ "Failed to open '%s', ignoring: %m", where);
|
||||
continue;
|
||||
}
|
||||
|
||||
- if (major(st.st_dev) == 0) {
|
||||
- log_debug("Directory %s is not on a real block device, not checking quota for UID use.", where);
|
||||
+ if (fstat(fd, &st) < 0) {
|
||||
+ log_error_errno(errno, "Failed to stat '%s', ignoring: %m", where);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -539,7 +541,7 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) {
|
||||
|
||||
previous_devno = st.st_dev;
|
||||
|
||||
- r = quotactl_devnum(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), st.st_dev, uid, &req);
|
||||
+ r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, USRQUOTA), uid, &req);
|
||||
if (r < 0) {
|
||||
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||
log_debug_errno(r, "No UID quota support on %s, ignoring.", where);
|
||||
diff --git a/src/home/homework-directory.c b/src/home/homework-directory.c
|
||||
index ff88367e43..37bdba30a3 100644
|
||||
--- a/src/home/homework-directory.c
|
||||
+++ b/src/home/homework-directory.c
|
||||
@@ -153,7 +153,7 @@ int home_create_directory_or_subvolume(UserRecord *h, HomeSetup *setup, UserReco
|
||||
/* Actually configure the quota. We also ignore errors here, but we do log
|
||||
* about them loudly, to keep things discoverable even though we don't
|
||||
* consider lacking quota support in kernel fatal. */
|
||||
- (void) home_update_quota_btrfs(h, d);
|
||||
+ (void) home_update_quota_btrfs(h, /* fd= */ -EBADF, d);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -169,7 +169,7 @@ int home_create_directory_or_subvolume(UserRecord *h, HomeSetup *setup, UserReco
|
||||
if (mkdir(d, 0700) < 0)
|
||||
return log_error_errno(errno, "Failed to create temporary home directory %s: %m", d);
|
||||
|
||||
- (void) home_update_quota_classic(h, d);
|
||||
+ (void) home_update_quota_classic(h, /* fd= */ -EBADF, d);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -285,7 +285,7 @@ int home_resize_directory(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
- r = home_update_quota_auto(h, NULL);
|
||||
+ r = home_update_quota_auto(h, setup->root_fd, /* path= */ NULL);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
return -ESOCKTNOSUPPORT; /* make recognizable */
|
||||
if (r < 0)
|
||||
diff --git a/src/home/homework-fscrypt.c b/src/home/homework-fscrypt.c
|
||||
index 3a9d4ea891..6e22fbd57c 100644
|
||||
--- a/src/home/homework-fscrypt.c
|
||||
+++ b/src/home/homework-fscrypt.c
|
||||
@@ -629,7 +629,7 @@ int home_create_fscrypt(
|
||||
nr++;
|
||||
}
|
||||
|
||||
- (void) home_update_quota_classic(h, temporary);
|
||||
+ (void) home_update_quota_classic(h, setup->root_fd, temporary);
|
||||
|
||||
r = home_shift_uid(setup->root_fd, HOME_RUNTIME_WORK_DIR, h->uid, h->uid, &mount_fd);
|
||||
if (r > 0)
|
||||
diff --git a/src/home/homework-quota.c b/src/home/homework-quota.c
|
||||
index c9516829d8..363be87104 100644
|
||||
--- a/src/home/homework-quota.c
|
||||
+++ b/src/home/homework-quota.c
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "blockdev-util.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "errno-util.h"
|
||||
+#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "homework-quota.h"
|
||||
#include "missing_magic.h"
|
||||
@@ -11,23 +12,32 @@
|
||||
#include "stat-util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
-int home_update_quota_btrfs(UserRecord *h, const char *path) {
|
||||
+int home_update_quota_btrfs(UserRecord *h, int fd, const char *path) {
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
assert(path);
|
||||
|
||||
+ _cleanup_close_ int _fd = -EBADF;
|
||||
+ if (fd < 0) {
|
||||
+ _fd = open(path, O_CLOEXEC|O_RDONLY);
|
||||
+ if (_fd < 0)
|
||||
+ return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||
+
|
||||
+ fd = _fd;
|
||||
+ }
|
||||
+
|
||||
if (h->disk_size == UINT64_MAX)
|
||||
return 0;
|
||||
|
||||
/* If the user wants quota, enable it */
|
||||
- r = btrfs_quota_enable(path, true);
|
||||
+ r = btrfs_quota_enable_fd(fd, true);
|
||||
if (r == -ENOTTY)
|
||||
return log_error_errno(r, "No btrfs quota support on subvolume %s.", path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable btrfs quota support on %s.", path);
|
||||
|
||||
- r = btrfs_qgroup_set_limit(path, 0, h->disk_size);
|
||||
+ r = btrfs_qgroup_set_limit_fd(fd, 0, h->disk_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set disk quota on subvolume %s: %m", path);
|
||||
|
||||
@@ -36,25 +46,27 @@ int home_update_quota_btrfs(UserRecord *h, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int home_update_quota_classic(UserRecord *h, const char *path) {
|
||||
+int home_update_quota_classic(UserRecord *h, int fd, const char *path) {
|
||||
struct dqblk req;
|
||||
- dev_t devno;
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
assert(uid_is_valid(h->uid));
|
||||
assert(path);
|
||||
|
||||
+ _cleanup_close_ int _fd = -EBADF;
|
||||
+ if (fd < 0) {
|
||||
+ _fd = open(path, O_CLOEXEC|O_RDONLY);
|
||||
+ if (_fd < 0)
|
||||
+ return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||
+
|
||||
+ fd = _fd;
|
||||
+ }
|
||||
+
|
||||
if (h->disk_size == UINT64_MAX)
|
||||
return 0;
|
||||
|
||||
- r = get_block_device(path, &devno);
|
||||
- if (r < 0)
|
||||
- return log_error_errno(r, "Failed to determine block device of %s: %m", path);
|
||||
- if (devno == 0)
|
||||
- return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system %s not backed by a block device.", path);
|
||||
-
|
||||
- r = quotactl_devnum(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), devno, h->uid, &req);
|
||||
+ r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, USRQUOTA), h->uid, &req);
|
||||
if (r == -ESRCH)
|
||||
zero(req);
|
||||
else if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
@@ -70,7 +82,7 @@ int home_update_quota_classic(UserRecord *h, const char *path) {
|
||||
req.dqb_valid = QIF_BLIMITS;
|
||||
req.dqb_bsoftlimit = req.dqb_bhardlimit = h->disk_size / QIF_DQBLKSIZE;
|
||||
|
||||
- r = quotactl_devnum(QCMD_FIXED(Q_SETQUOTA, USRQUOTA), devno, h->uid, &req);
|
||||
+ r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_SETQUOTA, USRQUOTA), h->uid, &req);
|
||||
if (r == -ESRCH)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "UID quota not available on %s.", path);
|
||||
if (r < 0)
|
||||
@@ -81,7 +93,7 @@ int home_update_quota_classic(UserRecord *h, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int home_update_quota_auto(UserRecord *h, const char *path) {
|
||||
+int home_update_quota_auto(UserRecord *h, int fd, const char *path) {
|
||||
struct statfs sfs;
|
||||
int r;
|
||||
|
||||
@@ -96,22 +108,31 @@ int home_update_quota_auto(UserRecord *h, const char *path) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Home record lacks image path.");
|
||||
}
|
||||
|
||||
- if (statfs(path, &sfs) < 0)
|
||||
+ _cleanup_close_ int _fd = -EBADF;
|
||||
+ if (fd < 0) {
|
||||
+ _fd = open(path, O_CLOEXEC|O_RDONLY);
|
||||
+ if (_fd < 0)
|
||||
+ return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||
+
|
||||
+ fd = _fd;
|
||||
+ }
|
||||
+
|
||||
+ if (fstatfs(fd, &sfs) < 0)
|
||||
return log_error_errno(errno, "Failed to statfs() file system: %m");
|
||||
|
||||
if (is_fs_type(&sfs, XFS_SUPER_MAGIC) ||
|
||||
is_fs_type(&sfs, EXT4_SUPER_MAGIC))
|
||||
- return home_update_quota_classic(h, path);
|
||||
+ return home_update_quota_classic(h, fd, path);
|
||||
|
||||
if (is_fs_type(&sfs, BTRFS_SUPER_MAGIC)) {
|
||||
|
||||
- r = btrfs_is_subvol(path);
|
||||
+ r = btrfs_is_subvol_fd(fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to test if %s is a subvolume: %m", path);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Directory %s is not a subvolume, cannot apply quota.", path);
|
||||
|
||||
- return home_update_quota_btrfs(h, path);
|
||||
+ return home_update_quota_btrfs(h, fd, path);
|
||||
}
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Type of directory %s not known, cannot apply quota.", path);
|
||||
diff --git a/src/home/homework-quota.h b/src/home/homework-quota.h
|
||||
index a21c9ba8b1..a03510c75e 100644
|
||||
--- a/src/home/homework-quota.h
|
||||
+++ b/src/home/homework-quota.h
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
#include "user-record.h"
|
||||
|
||||
-int home_update_quota_btrfs(UserRecord *h, const char *path);
|
||||
-int home_update_quota_classic(UserRecord *h, const char *path);
|
||||
-int home_update_quota_auto(UserRecord *h, const char *path);
|
||||
+int home_update_quota_btrfs(UserRecord *h, int fd, const char *path);
|
||||
+int home_update_quota_classic(UserRecord *h, int fd, const char *path);
|
||||
+int home_update_quota_auto(UserRecord *h, int fd, const char *path);
|
||||
diff --git a/src/shared/quota-util.c b/src/shared/quota-util.c
|
||||
index 4d014f847c..a698129adf 100644
|
||||
--- a/src/shared/quota-util.c
|
||||
+++ b/src/shared/quota-util.c
|
||||
@@ -1,42 +1,36 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
+#include <stdint.h>
|
||||
#include <sys/quota.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "device-util.h"
|
||||
+#include "errno-util.h"
|
||||
+#include "missing_syscall.h"
|
||||
#include "quota-util.h"
|
||||
|
||||
-int quotactl_devnum(int cmd, dev_t devnum, int id, void *addr) {
|
||||
- _cleanup_free_ char *devnode = NULL;
|
||||
+int quotactl_fd_with_fallback(int fd, int cmd, int id, void *addr) {
|
||||
int r;
|
||||
|
||||
- /* Like quotactl() but takes a dev_t instead of a path to a device node, and fixes caddr_t → void*,
|
||||
- * like we should, today */
|
||||
+ /* Emulates quotactl_fd() on older kernels that lack it. (i.e. kernels < 5.14) */
|
||||
|
||||
- r = devname_from_devnum(S_IFBLK, devnum, &devnode);
|
||||
- if (r < 0)
|
||||
+ r = RET_NERRNO(quotactl_fd(fd, cmd, id, addr));
|
||||
+ if (!ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
return r;
|
||||
|
||||
- if (quotactl(cmd, devnode, id, addr) < 0)
|
||||
- return -errno;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-int quotactl_path(int cmd, const char *path, int id, void *addr) {
|
||||
dev_t devno;
|
||||
- int r;
|
||||
-
|
||||
- /* Like quotactl() but takes a path to some fs object, and changes the backing file system. I.e. the
|
||||
- * argument shouldn't be a block device but a regular file system object */
|
||||
-
|
||||
- r = get_block_device(path, &devno);
|
||||
+ r = get_block_device_fd(fd, &devno);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (devno == 0) /* Doesn't have a block device */
|
||||
return -ENODEV;
|
||||
|
||||
- return quotactl_devnum(cmd, devno, id, addr);
|
||||
+ _cleanup_free_ char *devnode = NULL;
|
||||
+ r = devname_from_devnum(S_IFBLK, devno, &devnode);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ return RET_NERRNO(quotactl(cmd, devnode, id, addr));
|
||||
}
|
||||
diff --git a/src/shared/quota-util.h b/src/shared/quota-util.h
|
||||
index 14a390ebe4..ad97eede01 100644
|
||||
--- a/src/shared/quota-util.h
|
||||
+++ b/src/shared/quota-util.h
|
||||
@@ -15,5 +15,4 @@ static inline int QCMD_FIXED(uint32_t cmd, uint32_t type) {
|
||||
return (int) QCMD(cmd, type);
|
||||
}
|
||||
|
||||
-int quotactl_devnum(int cmd, dev_t devnum, int id, void *addr);
|
||||
-int quotactl_path(int cmd, const char *path, int id, void *addr);
|
||||
+int quotactl_fd_with_fallback(int fd, int cmd, int id, void *addr);
|
||||
diff --git a/units/systemd-homed.service.in b/units/systemd-homed.service.in
|
||||
index b54e5d30b2..5687fc0ed4 100644
|
||||
--- a/units/systemd-homed.service.in
|
||||
+++ b/units/systemd-homed.service.in
|
||||
@@ -33,7 +33,7 @@ StateDirectory=systemd/home
|
||||
CacheDirectory=systemd/home
|
||||
SystemCallArchitectures=native
|
||||
SystemCallErrorNumber=EPERM
|
||||
-SystemCallFilter=@system-service @mount quotactl
|
||||
+SystemCallFilter=@system-service @mount quotactl quotactl_fd
|
||||
TimeoutStopSec=3min
|
||||
{{SERVICE_WATCHDOG}}
|
||||
|
||||
400
0634-pid1-add-GracefulOptions-setting-to-.mount-units.patch
Normal file
400
0634-pid1-add-GracefulOptions-setting-to-.mount-units.patch
Normal file
@ -0,0 +1,400 @@
|
||||
From d40f49bc7e9454abdc0fc32936294cd046846c59 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 14 Jan 2025 16:49:52 +0100
|
||||
Subject: [PATCH] pid1: add GracefulOptions= setting to .mount units
|
||||
|
||||
This new setting can be used to specify mount options that shall only be
|
||||
added to the mount option string if the kernel supports them.
|
||||
|
||||
This shall be used for adding "usrquota" to tmp.mount without breaking compat,
|
||||
but is generally be useful.
|
||||
|
||||
[dtardon: I put the test into TEST-87-AUX-UTILS-VM, because that's where
|
||||
3f9539a97f3b4747ff22a530bac39dec24ac58af, which we have already
|
||||
backported, would have moved it.]
|
||||
|
||||
(cherry picked from commit 09fbff57fcde47782a73f23b3d5cfdcd0e8f699b)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
man/org.freedesktop.systemd1.xml | 7 ++++
|
||||
man/systemd.mount.xml | 16 +++++++++
|
||||
src/core/dbus-mount.c | 25 +++++++++++++
|
||||
src/core/load-fragment-gperf.gperf.in | 1 +
|
||||
src/core/load-fragment.c | 45 ++++++++++++++++++++++++
|
||||
src/core/load-fragment.h | 1 +
|
||||
src/core/mount.c | 44 +++++++++++++++++++++++
|
||||
src/core/mount.h | 2 ++
|
||||
src/shared/bus-unit-util.c | 19 +++++-----
|
||||
test/units/TEST-87-AUX-UTILS-VM.mount.sh | 7 ++++
|
||||
10 files changed, 159 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
|
||||
index 0c7c52d563..71d2a11d29 100644
|
||||
--- a/man/org.freedesktop.systemd1.xml
|
||||
+++ b/man/org.freedesktop.systemd1.xml
|
||||
@@ -7004,6 +7004,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
readonly s Result = '...';
|
||||
readonly u UID = ...;
|
||||
readonly u GID = ...;
|
||||
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
+ readonly as GracefulOptions = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
|
||||
readonly a(sasbttttuii) ExecMount = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
|
||||
@@ -7604,6 +7606,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<!--property GID is not documented!-->
|
||||
|
||||
+ <!--property GracefulOptions is not documented!-->
|
||||
+
|
||||
<!--property ExecUnmount is not documented!-->
|
||||
|
||||
<!--property ExecRemount is not documented!-->
|
||||
@@ -8150,6 +8154,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="GID"/>
|
||||
|
||||
+ <variablelist class="dbus-property" generated="True" extra-ref="GracefulOptions"/>
|
||||
+
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecMount"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecUnmount"/>
|
||||
@@ -12380,6 +12386,7 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<varname>ManagedOOMMemoryPressureDurationUSec</varname>,
|
||||
<varname>ProtectControlGroupsEx</varname>, and
|
||||
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
||||
+ <para><varname>GracefulOptions</varname> were added in version 258.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Swap Unit Objects</title>
|
||||
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
|
||||
index 20e724d540..9b394f6079 100644
|
||||
--- a/man/systemd.mount.xml
|
||||
+++ b/man/systemd.mount.xml
|
||||
@@ -650,6 +650,22 @@
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><varname>GracefulOptions=</varname></term>
|
||||
+
|
||||
+ <listitem><para>Additional mount options that shall be appended to <varname>Options=</varname> if
|
||||
+ supported by the kernel. This may be used to configure mount options that are optional and only
|
||||
+ enabled on kernels that support them. Note that this is supported only for native kernel mount
|
||||
+ options (i.e. explicitly not for mount options implemented in userspace, such as those processed by
|
||||
+ <command>/usr/bin/mount</command> itself, by FUSE or by mount helpers such as
|
||||
+ <command>mount.nfs</command>).</para>
|
||||
+
|
||||
+ <para>May be specified multiple times. If specified multiple times, all listed, supported mount
|
||||
+ options are combined. If an empty string is assigned, the list is reset.</para>
|
||||
+
|
||||
+ <xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
+ </varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<xi:include href="systemd.service.xml" xpointer="shared-unit-options" />
|
||||
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
|
||||
index d59aa06a11..855300d025 100644
|
||||
--- a/src/core/dbus-mount.c
|
||||
+++ b/src/core/dbus-mount.c
|
||||
@@ -75,6 +75,7 @@ const sd_bus_vtable bus_mount_vtable[] = {
|
||||
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
+ SD_BUS_PROPERTY("GracefulOptions", "as", NULL, offsetof(Mount, graceful_options), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
BUS_EXEC_COMMAND_VTABLE("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
@@ -150,6 +151,30 @@ static int bus_mount_set_transient_property(
|
||||
if (streq(name, "ReadWriteOnly"))
|
||||
return bus_set_transient_bool(u, name, &m->read_write_only, message, flags, error);
|
||||
|
||||
+ if (streq(name, "GracefulOptions")) {
|
||||
+ _cleanup_strv_free_ char **add = NULL;
|
||||
+ r = sd_bus_message_read_strv(message, &add);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
+
|
||||
+ if (strv_isempty(add)) {
|
||||
+ m->graceful_options = strv_free(m->graceful_options);
|
||||
+ unit_write_settingf(u, flags, name, "GracefulOptions=");
|
||||
+ } else {
|
||||
+ r = strv_extend_strv(&m->graceful_options, add, /* filter_duplicates= */ false);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ STRV_FOREACH(a, add)
|
||||
+ unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "GracefulOptions=%s", *a);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
|
||||
index d7564b3767..5b67d7b554 100644
|
||||
--- a/src/core/load-fragment-gperf.gperf.in
|
||||
+++ b/src/core/load-fragment-gperf.gperf.in
|
||||
@@ -546,6 +546,7 @@ Mount.SloppyOptions, config_parse_bool,
|
||||
Mount.LazyUnmount, config_parse_bool, 0, offsetof(Mount, lazy_unmount)
|
||||
Mount.ForceUnmount, config_parse_bool, 0, offsetof(Mount, force_unmount)
|
||||
Mount.ReadWriteOnly, config_parse_bool, 0, offsetof(Mount, read_write_only)
|
||||
+Mount.GracefulOptions, config_parse_mount_graceful_options, 0, offsetof(Mount, graceful_options)
|
||||
{{ EXEC_CONTEXT_CONFIG_ITEMS('Mount') }}
|
||||
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Mount') }}
|
||||
{{ KILL_CONTEXT_CONFIG_ITEMS('Mount') }}
|
||||
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
||||
index 90f054ec9e..9007846e64 100644
|
||||
--- a/src/core/load-fragment.c
|
||||
+++ b/src/core/load-fragment.c
|
||||
@@ -6121,6 +6121,51 @@ int config_parse_mount_node(
|
||||
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, path, data, userdata);
|
||||
}
|
||||
|
||||
+int config_parse_mount_graceful_options(
|
||||
+ const char *unit,
|
||||
+ const char *filename,
|
||||
+ unsigned line,
|
||||
+ const char *section,
|
||||
+ unsigned section_line,
|
||||
+ const char *lvalue,
|
||||
+ int ltype,
|
||||
+ const char *rvalue,
|
||||
+ void *data,
|
||||
+ void *userdata) {
|
||||
+
|
||||
+ const Unit *u = ASSERT_PTR(userdata);
|
||||
+ char ***sv = ASSERT_PTR(data);
|
||||
+ int r;
|
||||
+
|
||||
+ assert(filename);
|
||||
+ assert(lvalue);
|
||||
+ assert(rvalue);
|
||||
+
|
||||
+ if (isempty(rvalue)) {
|
||||
+ *sv = strv_free(*sv);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ _cleanup_free_ char *resolved = NULL;
|
||||
+ r = unit_full_printf(u, rvalue, &resolved);
|
||||
+ if (r < 0) {
|
||||
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ _cleanup_strv_free_ char **strv = NULL;
|
||||
+
|
||||
+ r = strv_split_full(&strv, resolved, ",", EXTRACT_RETAIN_ESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
|
||||
+ if (r < 0)
|
||||
+ return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
+
|
||||
+ r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates = */ false);
|
||||
+ if (r < 0)
|
||||
+ return log_oom();
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static int merge_by_names(Unit *u, Set *names, const char *id) {
|
||||
char *k;
|
||||
int r;
|
||||
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
|
||||
index 8ac962a94b..673088a42d 100644
|
||||
--- a/src/core/load-fragment.h
|
||||
+++ b/src/core/load-fragment.h
|
||||
@@ -164,6 +164,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_open_file);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_memory_pressure_watch);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_nft_set);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_mount_node);
|
||||
+CONFIG_PARSER_PROTOTYPE(config_parse_mount_graceful_options);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index e5d02965be..136c3f1453 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -231,6 +231,8 @@ static void mount_done(Unit *u) {
|
||||
mount_unwatch_control_pid(m);
|
||||
|
||||
m->timer_event_source = sd_event_source_disable_unref(m->timer_event_source);
|
||||
+
|
||||
+ m->graceful_options = strv_free(m->graceful_options);
|
||||
}
|
||||
|
||||
static int update_parameters_proc_self_mountinfo(
|
||||
@@ -1061,6 +1063,44 @@ fail:
|
||||
mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES, /* flush_result = */ false);
|
||||
}
|
||||
|
||||
+static int mount_append_graceful_options(Mount *m, const MountParameters *p, char **opts) {
|
||||
+ int r;
|
||||
+
|
||||
+ assert(m);
|
||||
+ assert(p);
|
||||
+ assert(opts);
|
||||
+
|
||||
+ if (strv_isempty(m->graceful_options))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!p->fstype) {
|
||||
+ log_unit_warning(UNIT(m), "GracefulOptions= used but file system type not known, suppressing all graceful options.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ STRV_FOREACH(o, m->graceful_options) {
|
||||
+ _cleanup_free_ char *k = NULL, *v = NULL;
|
||||
+
|
||||
+ r = split_pair(*o, "=", &k, &v);
|
||||
+ if (r < 0 && r != -EINVAL) /* EINVAL → not a key/value pair */
|
||||
+ return r;
|
||||
+
|
||||
+ r = mount_option_supported(p->fstype, k ?: *o, v);
|
||||
+ if (r < 0)
|
||||
+ log_unit_warning_errno(UNIT(m), r, "GracefulOptions=%s specified, but cannot determine availability, suppressing.", *o);
|
||||
+ else if (r == 0)
|
||||
+ log_unit_info(UNIT(m), "GracefulOptions=%s specified, but option is not available, suppressing.", *o);
|
||||
+ else {
|
||||
+ log_unit_debug(UNIT(m), "GracefulOptions=%s specified and supported, appending to mount option string.", *o);
|
||||
+
|
||||
+ if (!strextend_with_separator(opts, ",", *o))
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParameters *p) {
|
||||
int r;
|
||||
|
||||
@@ -1095,6 +1135,10 @@ static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParamete
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
+ r = mount_append_graceful_options(m, p, &opts);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
if (!isempty(opts)) {
|
||||
r = exec_command_append(c, "-o", opts, NULL);
|
||||
if (r < 0)
|
||||
diff --git a/src/core/mount.h b/src/core/mount.h
|
||||
index 9a8b6bb4c0..28cc7785d8 100644
|
||||
--- a/src/core/mount.h
|
||||
+++ b/src/core/mount.h
|
||||
@@ -88,6 +88,8 @@ struct Mount {
|
||||
sd_event_source *timer_event_source;
|
||||
|
||||
unsigned n_retry_umount;
|
||||
+
|
||||
+ char **graceful_options;
|
||||
};
|
||||
|
||||
extern const UnitVTable mount_vtable;
|
||||
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
|
||||
index 06bfb90c8f..8667d10077 100644
|
||||
--- a/src/shared/bus-unit-util.c
|
||||
+++ b/src/shared/bus-unit-util.c
|
||||
@@ -147,7 +147,7 @@ static int bus_append_string(sd_bus_message *m, const char *field, const char *e
|
||||
return 1;
|
||||
}
|
||||
|
||||
-static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
|
||||
+static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) {
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
@@ -170,7 +170,7 @@ static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq,
|
||||
for (p = eq;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
- r = extract_first_word(&p, &word, NULL, flags);
|
||||
+ r = extract_first_word(&p, &word, separator, flags);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == -ENOMEM)
|
||||
@@ -607,12 +607,12 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
|
||||
return bus_append_cg_blkio_weight_parse(m, field, eq);
|
||||
|
||||
if (streq(field, "DisableControllers"))
|
||||
- return bus_append_strv(m, "DisableControllers", eq, EXTRACT_UNQUOTE);
|
||||
+ return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
|
||||
|
||||
if (streq(field, "Delegate")) {
|
||||
r = parse_boolean(eq);
|
||||
if (r < 0)
|
||||
- return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_UNQUOTE);
|
||||
+ return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
|
||||
|
||||
r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
|
||||
if (r < 0)
|
||||
@@ -1110,7 +1110,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
"ConfigurationDirectory",
|
||||
"SupplementaryGroups",
|
||||
"SystemCallArchitectures"))
|
||||
- return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
|
||||
+ return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
|
||||
|
||||
if (STR_IN_SET(field, "SyslogLevel",
|
||||
"LogLevelMax"))
|
||||
@@ -1169,7 +1169,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
if (STR_IN_SET(field, "Environment",
|
||||
"UnsetEnvironment",
|
||||
"PassEnvironment"))
|
||||
- return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
|
||||
+ return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
|
||||
|
||||
if (streq(field, "EnvironmentFile")) {
|
||||
if (isempty(eq))
|
||||
@@ -2309,6 +2309,9 @@ static int bus_append_mount_property(sd_bus_message *m, const char *field, const
|
||||
"ReadwriteOnly"))
|
||||
return bus_append_parse_boolean(m, field, eq);
|
||||
|
||||
+ if (streq(field, "GracefulOptions"))
|
||||
+ return bus_append_strv(m, field, eq, /* separator= */ ",", 0);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2591,7 +2594,7 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
|
||||
return bus_append_string(m, field, eq);
|
||||
|
||||
if (streq(field, "Symlinks"))
|
||||
- return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
|
||||
+ return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
|
||||
|
||||
if (streq(field, "SocketProtocol"))
|
||||
return bus_append_parse_ip_protocol(m, field, eq);
|
||||
@@ -2725,7 +2728,7 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const
|
||||
"RequiresMountsFor",
|
||||
"WantsMountsFor",
|
||||
"Markers"))
|
||||
- return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
|
||||
+ return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
|
||||
|
||||
t = condition_type_from_string(field);
|
||||
if (t >= 0)
|
||||
diff --git a/test/units/TEST-87-AUX-UTILS-VM.mount.sh b/test/units/TEST-87-AUX-UTILS-VM.mount.sh
|
||||
index 3075d0fe2e..c1bfbdc1a2 100755
|
||||
--- a/test/units/TEST-87-AUX-UTILS-VM.mount.sh
|
||||
+++ b/test/units/TEST-87-AUX-UTILS-VM.mount.sh
|
||||
@@ -180,3 +180,10 @@ systemctl status "$WORK_DIR/mnt"
|
||||
touch "$WORK_DIR/mnt/hello"
|
||||
[[ "$(stat -c "%U:%G" "$WORK_DIR/mnt/hello")" == "testuser:testuser" ]]
|
||||
systemd-umount LABEL=owner-vfat
|
||||
+
|
||||
+# Mkae sure that graceful mount options work
|
||||
+GRACEFULTEST="/tmp/graceful/$RANDOM"
|
||||
+systemd-mount --tmpfs -p GracefulOptions=idefinitelydontexist,nr_inodes=4711,idonexisteither "$GRACEFULTEST"
|
||||
+findmnt -n -o options "$GRACEFULTEST"
|
||||
+findmnt -n -o options "$GRACEFULTEST" | grep -q nr_inodes=4711
|
||||
+umount "$GRACEFULTEST"
|
||||
75
0635-pid1-enable-usrquota-support-on-dev-shm.patch
Normal file
75
0635-pid1-enable-usrquota-support-on-dev-shm.patch
Normal file
@ -0,0 +1,75 @@
|
||||
From 75f712d4fb8d5b05f28eda98e9ae44512ba6d7f8 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 14 Jan 2025 16:51:49 +0100
|
||||
Subject: [PATCH] pid1: enable usrquota support on /dev/shm
|
||||
|
||||
(cherry picked from commit 8f5131fb9e7979022521d685e69b6419f0884677)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/shared/mount-setup.c | 33 +++++++++++++++++++++++++--------
|
||||
1 file changed, 25 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c
|
||||
index 73be3b5dce..db8c2b61d2 100644
|
||||
--- a/src/shared/mount-setup.c
|
||||
+++ b/src/shared/mount-setup.c
|
||||
@@ -34,11 +34,12 @@
|
||||
#include "virt.h"
|
||||
|
||||
typedef enum MountMode {
|
||||
- MNT_NONE = 0,
|
||||
- MNT_FATAL = 1 << 0,
|
||||
- MNT_IN_CONTAINER = 1 << 1,
|
||||
- MNT_CHECK_WRITABLE = 1 << 2,
|
||||
- MNT_FOLLOW_SYMLINK = 1 << 3,
|
||||
+ MNT_NONE = 0,
|
||||
+ MNT_FATAL = 1 << 0,
|
||||
+ MNT_IN_CONTAINER = 1 << 1,
|
||||
+ MNT_CHECK_WRITABLE = 1 << 2,
|
||||
+ MNT_FOLLOW_SYMLINK = 1 << 3,
|
||||
+ MNT_USRQUOTA_GRACEFUL = 1 << 4,
|
||||
} MountMode;
|
||||
|
||||
typedef struct MountPoint {
|
||||
@@ -92,7 +93,7 @@ static const MountPoint mount_table[] = {
|
||||
mac_smack_use, MNT_FATAL },
|
||||
#endif
|
||||
{ "tmpfs", "/dev/shm", "tmpfs", "mode=01777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
|
||||
+ NULL, MNT_FATAL|MNT_IN_CONTAINER|MNT_USRQUOTA_GRACEFUL },
|
||||
{ "devpts", "/dev/pts", "devpts", "mode=" STRINGIFY(TTY_MODE) ",gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
|
||||
NULL, MNT_IN_CONTAINER },
|
||||
#if ENABLE_SMACK
|
||||
@@ -189,13 +190,29 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
else
|
||||
(void) mkdir_p(p->where, 0755);
|
||||
|
||||
+ _cleanup_free_ char *extend_options = NULL;
|
||||
+ const char *o = p->options;
|
||||
+ if (FLAGS_SET(p->mode, MNT_USRQUOTA_GRACEFUL)) {
|
||||
+ r = mount_option_supported(p->type, "usrquota", /* value= */ NULL);
|
||||
+ if (r < 0)
|
||||
+ log_warning_errno(r, "Unable to determine whether %s supports 'usrquota' mount option, assuming not: %m", p->type);
|
||||
+ else if (r == 0)
|
||||
+ log_info("Not enabling 'usrquota' on '%s' as kernel lacks support for it.", p->where);
|
||||
+ else {
|
||||
+ if (!strextend_with_separator(&extend_options, ",", p->options ?: POINTER_MAX, "usrquota"))
|
||||
+ return log_oom();
|
||||
+
|
||||
+ o = extend_options;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
log_debug("Mounting %s to %s of type %s with options %s.",
|
||||
p->what,
|
||||
p->where,
|
||||
p->type,
|
||||
- strna(p->options));
|
||||
+ strna(o));
|
||||
|
||||
- r = mount_verbose_full(priority, p->what, p->where, p->type, p->flags, p->options, FLAGS_SET(p->mode, MNT_FOLLOW_SYMLINK));
|
||||
+ r = mount_verbose_full(priority, p->what, p->where, p->type, p->flags, o, FLAGS_SET(p->mode, MNT_FOLLOW_SYMLINK));
|
||||
if (r < 0)
|
||||
return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
|
||||
|
||||
24
0636-units-enable-usrquota-support-on-tmp.patch
Normal file
24
0636-units-enable-usrquota-support-on-tmp.patch
Normal file
@ -0,0 +1,24 @@
|
||||
From bc192261e4801ad27a8610fea4e10010d705bfc0 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 14 Jan 2025 16:52:04 +0100
|
||||
Subject: [PATCH] units: enable usrquota support on /tmp/
|
||||
|
||||
(cherry picked from commit c9f805674ace3e2d611596b871c2d12190457d87)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
units/tmp.mount | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/units/tmp.mount b/units/tmp.mount
|
||||
index d7beaa8d14..d347af56d3 100644
|
||||
--- a/units/tmp.mount
|
||||
+++ b/units/tmp.mount
|
||||
@@ -23,6 +23,7 @@ What=tmpfs
|
||||
Where=/tmp
|
||||
Type=tmpfs
|
||||
Options=mode=1777,strictatime,nosuid,nodev,size=50%%,nr_inodes=1m
|
||||
+GracefulOptions=usrquota
|
||||
|
||||
# Make 'systemctl enable tmp.mount' work:
|
||||
[Install]
|
||||
71
0637-nspawn-enable-usrquota-support-on-tmp-and-dev-shm.patch
Normal file
71
0637-nspawn-enable-usrquota-support-on-tmp-and-dev-shm.patch
Normal file
@ -0,0 +1,71 @@
|
||||
From b9cfb8c02ec36304e0a3ba730363a6dd747dd26a Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Tue, 14 Jan 2025 16:51:27 +0100
|
||||
Subject: [PATCH] nspawn: enable usrquota support on /tmp/ and /dev/shm/
|
||||
|
||||
(cherry picked from commit 611ae598889471830b2f1d7251c271b79884b1c4)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/nspawn/nspawn-mount.c | 21 +++++++++++++++++++--
|
||||
src/nspawn/nspawn-mount.h | 1 +
|
||||
2 files changed, 20 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
|
||||
index c233cdf600..6bd506f960 100644
|
||||
--- a/src/nspawn/nspawn-mount.c
|
||||
+++ b/src/nspawn/nspawn-mount.c
|
||||
@@ -592,7 +592,7 @@ int mount_all(const char *dest,
|
||||
|
||||
/* Then we list outer child mounts (i.e. mounts applied *before* entering user namespacing when we are privileged) */
|
||||
{ "tmpfs", "/tmp", "tmpfs", "mode=01777" NESTED_TMPFS_LIMITS, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||
- MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP|MOUNT_MKDIR },
|
||||
+ MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP|MOUNT_MKDIR|MOUNT_USRQUOTA_GRACEFUL },
|
||||
{ "tmpfs", "/sys", "tmpfs", "mode=0555" TMPFS_LIMITS_SYS, MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS|MOUNT_MKDIR|MOUNT_PRIVILEGED },
|
||||
{ "sysfs", "/sys", "sysfs", NULL, SYS_DEFAULT_MOUNT_FLAGS,
|
||||
@@ -602,7 +602,7 @@ int mount_all(const char *dest,
|
||||
{ "tmpfs", "/dev", "tmpfs", "mode=0755" TMPFS_LIMITS_PRIVATE_DEV, MS_NOSUID|MS_STRICTATIME,
|
||||
MOUNT_FATAL|MOUNT_MKDIR },
|
||||
{ "tmpfs", "/dev/shm", "tmpfs", "mode=01777" NESTED_TMPFS_LIMITS, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||
- MOUNT_FATAL|MOUNT_MKDIR },
|
||||
+ MOUNT_FATAL|MOUNT_MKDIR|MOUNT_USRQUOTA_GRACEFUL },
|
||||
{ "tmpfs", "/run", "tmpfs", "mode=0755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||
MOUNT_FATAL|MOUNT_MKDIR },
|
||||
{ "/run/host", "/run/host", NULL, NULL, MS_BIND,
|
||||
@@ -710,6 +710,23 @@ int mount_all(const char *dest,
|
||||
o = options;
|
||||
}
|
||||
|
||||
+ if (FLAGS_SET(m->mount_settings, MOUNT_USRQUOTA_GRACEFUL)) {
|
||||
+ r = mount_option_supported(m->type, /* key= */ "usrquota", /* value= */ NULL);
|
||||
+ if (r < 0)
|
||||
+ log_warning_errno(r, "Failed to determine if '%s' supports 'usrquota', assuming it doesn't: %m", m->type);
|
||||
+ else if (r == 0)
|
||||
+ log_info("Kernel doesn't support 'usrquota' on '%s', not including in mount options for '%s'.", m->type, m->where);
|
||||
+ else {
|
||||
+ _cleanup_free_ char *joined = NULL;
|
||||
+
|
||||
+ if (!strextend_with_separator(&joined, ",", o ?: POINTER_MAX, "usrquota"))
|
||||
+ return log_oom();
|
||||
+
|
||||
+ free_and_replace(options, joined);
|
||||
+ o = options;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (FLAGS_SET(m->mount_settings, MOUNT_PREFIX_ROOT)) {
|
||||
/* Optionally prefix the mount source with the root dir. This is useful in bind
|
||||
* mounts to be created within the container image before we transition into it. Note
|
||||
diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h
|
||||
index 5f66bc7328..529fa16658 100644
|
||||
--- a/src/nspawn/nspawn-mount.h
|
||||
+++ b/src/nspawn/nspawn-mount.h
|
||||
@@ -21,6 +21,7 @@ typedef enum MountSettingsMask {
|
||||
MOUNT_PREFIX_ROOT = 1 << 10,/* if set, prefix the source path with the container's root directory */
|
||||
MOUNT_FOLLOW_SYMLINKS = 1 << 11,/* if set, we'll follow symlinks for the mount target */
|
||||
MOUNT_PRIVILEGED = 1 << 12,/* if set, we'll only mount this in the outer child if we are running in privileged mode */
|
||||
+ MOUNT_USRQUOTA_GRACEFUL = 1 << 13,/* if set, append "usrquota" to mount options if kernel tmpfs supports that */
|
||||
} MountSettingsMask;
|
||||
|
||||
typedef enum CustomMountType {
|
||||
@ -0,0 +1,31 @@
|
||||
From 4a4f0b5dcb42533971116fd8f467f9866f50d58c Mon Sep 17 00:00:00 2001
|
||||
From: Luca Boccassi <luca.boccassi@gmail.com>
|
||||
Date: Mon, 20 Jan 2025 19:05:11 +0000
|
||||
Subject: [PATCH] nspawn: downgrade log message about usrquota to debug
|
||||
|
||||
This is shown every time nspawn is started, which is annoying
|
||||
and there's nothing a user can do about it, since it depends on
|
||||
an extremely new kernel. Downgrade to debug.
|
||||
|
||||
Follow-up for 611ae598889471830b2f1d7251c271b79884b1c4
|
||||
|
||||
(cherry picked from commit 8fa7863a93047d310ec6600f939590f07854b497)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/nspawn/nspawn-mount.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
|
||||
index 6bd506f960..cd5a634ec0 100644
|
||||
--- a/src/nspawn/nspawn-mount.c
|
||||
+++ b/src/nspawn/nspawn-mount.c
|
||||
@@ -715,7 +715,7 @@ int mount_all(const char *dest,
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to determine if '%s' supports 'usrquota', assuming it doesn't: %m", m->type);
|
||||
else if (r == 0)
|
||||
- log_info("Kernel doesn't support 'usrquota' on '%s', not including in mount options for '%s'.", m->type, m->where);
|
||||
+ log_debug("Kernel doesn't support 'usrquota' on '%s', not including in mount options for '%s'.", m->type, m->where);
|
||||
else {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
24
0639-mount-setup-drop-outdated-comment.patch
Normal file
24
0639-mount-setup-drop-outdated-comment.patch
Normal file
@ -0,0 +1,24 @@
|
||||
From 2cc61dd003b3798a2beb19160501961056f8ee96 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Sat, 8 Mar 2025 19:13:44 +0100
|
||||
Subject: [PATCH] mount-setup: drop outdated comment
|
||||
|
||||
(cherry picked from commit 80b7f60d2e7883cec3185172a85901d72fd5cdb3)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/shared/mount-setup.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c
|
||||
index db8c2b61d2..93e646d045 100644
|
||||
--- a/src/shared/mount-setup.c
|
||||
+++ b/src/shared/mount-setup.c
|
||||
@@ -179,7 +179,6 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
- /* Skip securityfs in a container */
|
||||
if (!FLAGS_SET(p->mode, MNT_IN_CONTAINER) && detect_container() > 0)
|
||||
return 0;
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
From d5642d888c6bc1b8014b727b6b1b4851a0829239 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Thu, 6 Mar 2025 13:14:13 +0100
|
||||
Subject: [PATCH] mount-setup: tune down log level if usrquota is not
|
||||
supported, apply usrquota when smack is in use too
|
||||
|
||||
Follow-up for 8f5131fb9e7979022521d685e69b6419f0884677
|
||||
|
||||
(cherry picked from commit b05c495eedaa73d4e911f9617a9afba04c95395b)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/shared/mount-setup.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c
|
||||
index 93e646d045..4c5151c7db 100644
|
||||
--- a/src/shared/mount-setup.c
|
||||
+++ b/src/shared/mount-setup.c
|
||||
@@ -90,7 +90,7 @@ static const MountPoint mount_table[] = {
|
||||
{ "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
||||
mac_smack_use, MNT_FATAL },
|
||||
{ "tmpfs", "/dev/shm", "tmpfs", "mode=01777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||
- mac_smack_use, MNT_FATAL },
|
||||
+ mac_smack_use, MNT_FATAL|MNT_USRQUOTA_GRACEFUL },
|
||||
#endif
|
||||
{ "tmpfs", "/dev/shm", "tmpfs", "mode=01777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||
NULL, MNT_FATAL|MNT_IN_CONTAINER|MNT_USRQUOTA_GRACEFUL },
|
||||
@@ -194,9 +194,9 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
if (FLAGS_SET(p->mode, MNT_USRQUOTA_GRACEFUL)) {
|
||||
r = mount_option_supported(p->type, "usrquota", /* value= */ NULL);
|
||||
if (r < 0)
|
||||
- log_warning_errno(r, "Unable to determine whether %s supports 'usrquota' mount option, assuming not: %m", p->type);
|
||||
+ log_full_errno(priority, r, "Unable to determine whether %s supports 'usrquota' mount option, assuming not: %m", p->type);
|
||||
else if (r == 0)
|
||||
- log_info("Not enabling 'usrquota' on '%s' as kernel lacks support for it.", p->where);
|
||||
+ log_debug("Not enabling 'usrquota' on '%s' as kernel lacks support for it.", p->where);
|
||||
else {
|
||||
if (!strextend_with_separator(&extend_options, ",", p->options ?: POINTER_MAX, "usrquota"))
|
||||
return log_oom();
|
||||
@ -0,0 +1,89 @@
|
||||
From 72d7385b4390e3c4def7e488aef31b84e1bb5f5d Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 23 Jan 2025 11:40:36 +0100
|
||||
Subject: [PATCH] devnum-util: add macros to safely convert dev_t to pointers
|
||||
and back
|
||||
|
||||
Sometimes it's nice being able to store dev_t as pointer values in
|
||||
hashmaps/tables, instead of having to allocate memory for them and using
|
||||
devt_hash_ops. After all dev_t is weird on Linux/glibc: glibc defines it
|
||||
as 64bit entity (which hence appears as something we cannot encode in a
|
||||
pointer value for compat with 32bit archs) but it actually is 32bit in
|
||||
the kernel apis. Hence we can safely cut off the upper 32bit, and still
|
||||
retain compat with all archs.
|
||||
|
||||
But let's hide this in new macros, and validate this is all correct via
|
||||
a test.
|
||||
|
||||
(cherry picked from commit d15811d7e5bb3fc3afc1c14e4d5bb3b18fddedc1)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/basic/devnum-util.h | 10 ++++++++--
|
||||
src/test/test-devnum-util.c | 17 +++++++++++++++++
|
||||
2 files changed, 25 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/basic/devnum-util.h b/src/basic/devnum-util.h
|
||||
index e109de9913..0efca56780 100644
|
||||
--- a/src/basic/devnum-util.h
|
||||
+++ b/src/basic/devnum-util.h
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
int parse_devnum(const char *s, dev_t *ret);
|
||||
|
||||
+#define DEVNUM_MAJOR_MAX ((UINT32_C(1) << 12) - 1U)
|
||||
+#define DEVNUM_MINOR_MAX ((UINT32_C(1) << 20) - 1U)
|
||||
+
|
||||
/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
|
||||
* specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
|
||||
* major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
|
||||
@@ -18,14 +21,14 @@ int parse_devnum(const char *s, dev_t *ret);
|
||||
#define DEVICE_MAJOR_VALID(x) \
|
||||
({ \
|
||||
typeof(x) _x = (x), _y = 0; \
|
||||
- _x >= _y && _x < (UINT32_C(1) << 12); \
|
||||
+ _x >= _y && _x <= DEVNUM_MAJOR_MAX; \
|
||||
\
|
||||
})
|
||||
|
||||
#define DEVICE_MINOR_VALID(x) \
|
||||
({ \
|
||||
typeof(x) _x = (x), _y = 0; \
|
||||
- _x >= _y && _x < (UINT32_C(1) << 20); \
|
||||
+ _x >= _y && _x <= DEVNUM_MINOR_MAX; \
|
||||
})
|
||||
|
||||
int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret);
|
||||
@@ -54,3 +57,6 @@ static inline char *format_devnum(dev_t d, char buf[static DEVNUM_STR_MAX]) {
|
||||
static inline bool devnum_is_zero(dev_t d) {
|
||||
return major(d) == 0 && minor(d) == 0;
|
||||
}
|
||||
+
|
||||
+#define DEVNUM_TO_PTR(u) ((void*) (uintptr_t) (u))
|
||||
+#define PTR_TO_DEVNUM(p) ((dev_t) ((uintptr_t) (p)))
|
||||
diff --git a/src/test/test-devnum-util.c b/src/test/test-devnum-util.c
|
||||
index ebef794001..782f15d86f 100644
|
||||
--- a/src/test/test-devnum-util.c
|
||||
+++ b/src/test/test-devnum-util.c
|
||||
@@ -121,4 +121,21 @@ TEST(devnum_format_str) {
|
||||
test_devnum_format_str_one(makedev(4095, 1048575), "4095:1048575");
|
||||
}
|
||||
|
||||
+TEST(devnum_to_ptr) {
|
||||
+ dev_t m = makedev(0, 0);
|
||||
+ ASSERT_EQ(major(m), 0U);
|
||||
+ ASSERT_EQ(minor(m), 0U);
|
||||
+ ASSERT_EQ(m, PTR_TO_DEVNUM(DEVNUM_TO_PTR(m)));
|
||||
+
|
||||
+ m = makedev(DEVNUM_MAJOR_MAX, DEVNUM_MINOR_MAX);
|
||||
+ ASSERT_EQ(major(m), DEVNUM_MAJOR_MAX);
|
||||
+ ASSERT_EQ(minor(m), DEVNUM_MINOR_MAX);
|
||||
+ ASSERT_EQ(m, PTR_TO_DEVNUM(DEVNUM_TO_PTR(m)));
|
||||
+
|
||||
+ m = makedev(5, 8);
|
||||
+ ASSERT_EQ(major(m), 5U);
|
||||
+ ASSERT_EQ(minor(m), 8U);
|
||||
+ ASSERT_EQ(m, PTR_TO_DEVNUM(DEVNUM_TO_PTR(m)));
|
||||
+}
|
||||
+
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
284
0642-user-record-add-fields-for-setting-limits-on-tmp-and.patch
Normal file
284
0642-user-record-add-fields-for-setting-limits-on-tmp-and.patch
Normal file
@ -0,0 +1,284 @@
|
||||
From 34ee2cbe4a0b8bdd1d48c31d6735f9d9b551e524 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Fri, 10 Jan 2025 11:33:59 +0100
|
||||
Subject: [PATCH] user-record: add fields for setting limits on /tmp/ and
|
||||
/dev/shm/
|
||||
|
||||
(cherry picked from commit 72b932aac0fbd818208d78ec01256bb946401881)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
docs/USER_RECORD.md | 35 ++++++++++++-----
|
||||
src/shared/user-record-show.c | 24 ++++++++++++
|
||||
src/shared/user-record.c | 71 +++++++++++++++++++++++++++++++++++
|
||||
src/shared/user-record.h | 17 +++++++++
|
||||
4 files changed, 138 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/docs/USER_RECORD.md b/docs/USER_RECORD.md
|
||||
index 90675dd532..689dd4e599 100644
|
||||
--- a/docs/USER_RECORD.md
|
||||
+++ b/docs/USER_RECORD.md
|
||||
@@ -626,6 +626,19 @@ is allowed to edit.
|
||||
`selfModifiablePrivileged` → Similar to `selfModifiableFields`, but it lists fields in
|
||||
the `privileged` section that the user is allowed to edit.
|
||||
|
||||
+`tmpLimit` → A numeric value encoding a disk quota limit in bytes enforced on
|
||||
+`/tmp/` on login, in case it is backed by volatile file system (such as
|
||||
+`tmpfs`).
|
||||
+
|
||||
+`tmpLimitScale` → Similar, but encodes a relative value, normalized to
|
||||
+`UINT32_MAX` as 100%. This value is applied relative to the file system
|
||||
+size. If both `tmpLimit` and `tmpLimitScale` are set, the lower of the two
|
||||
+should be enforced. If neither field is set the implementation might apply a
|
||||
+default limit.
|
||||
+
|
||||
+`devShmLimit`, `devShmLimitScale` → Similar to the previous two, but apply to
|
||||
+`/dev/shm/` rather than `/tmp/`.
|
||||
+
|
||||
`privileged` → An object, which contains the fields of the `privileged` section
|
||||
of the user record, see below.
|
||||
|
||||
@@ -777,22 +790,26 @@ These four are the only fields specific to this section. All other fields that
|
||||
may be used in this section are identical to the equally named ones in the
|
||||
`regular` section (i.e. at the top-level object). Specifically, these are:
|
||||
|
||||
-`blobDirectory`, `blobManifest`, `iconName`, `location`, `shell`, `umask`, `environment`, `timeZone`,
|
||||
-`preferredLanguage`, `additionalLanguages`, `niceLevel`, `resourceLimits`, `locked`, `notBeforeUSec`,
|
||||
-`notAfterUSec`, `storage`, `diskSize`, `diskSizeRelative`, `skeletonDirectory`,
|
||||
-`accessMode`, `tasksMax`, `memoryHigh`, `memoryMax`, `cpuWeight`, `ioWeight`,
|
||||
+`blobDirectory`, `blobManifest`, `iconName`, `location`, `shell`, `umask`,
|
||||
+`environment`, `timeZone`, `preferredLanguage`, `additionalLanguages`,
|
||||
+`niceLevel`, `resourceLimits`, `locked`, `notBeforeUSec`, `notAfterUSec`,
|
||||
+`storage`, `diskSize`, `diskSizeRelative`, `skeletonDirectory`, `accessMode`,
|
||||
+`tasksMax`, `memoryHigh`, `memoryMax`, `cpuWeight`, `ioWeight`,
|
||||
`mountNoDevices`, `mountNoSuid`, `mountNoExecute`, `cifsDomain`,
|
||||
`cifsUserName`, `cifsService`, `cifsExtraMountOptions`, `imagePath`, `uid`,
|
||||
`gid`, `memberOf`, `fileSystemType`, `partitionUuid`, `luksUuid`,
|
||||
`fileSystemUuid`, `luksDiscard`, `luksOfflineDiscard`, `luksCipher`,
|
||||
`luksCipherMode`, `luksVolumeKeySize`, `luksPbkdfHashAlgorithm`,
|
||||
-`luksPbkdfType`, `luksPbkdfForceIterations`, `luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`,
|
||||
-`luksPbkdfParallelThreads`, `luksSectorSize`, `autoResizeMode`, `rebalanceWeight`,
|
||||
-`rateLimitIntervalUSec`, `rateLimitBurst`, `enforcePasswordPolicy`,
|
||||
-`autoLogin`, `preferredSessionType`, `preferredSessionLauncher`, `stopDelayUSec`, `killProcesses`,
|
||||
+`luksPbkdfType`, `luksPbkdfForceIterations`, `luksPbkdfTimeCostUSec`,
|
||||
+`luksPbkdfMemoryCost`, `luksPbkdfParallelThreads`, `luksSectorSize`,
|
||||
+`autoResizeMode`, `rebalanceWeight`, `rateLimitIntervalUSec`, `rateLimitBurst`,
|
||||
+`enforcePasswordPolicy`, `autoLogin`, `preferredSessionType`,
|
||||
+`preferredSessionLauncher`, `stopDelayUSec`, `killProcesses`,
|
||||
`passwordChangeMinUSec`, `passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
|
||||
`passwordChangeInactiveUSec`, `passwordChangeNow`, `pkcs11TokenUri`,
|
||||
-`fido2HmacCredential`, `selfModifiableFields`, `selfModifiableBlobs`, `selfModifiablePrivileged`.
|
||||
+`fido2HmacCredential`, `selfModifiableFields`, `selfModifiableBlobs`,
|
||||
+`selfModifiablePrivileged`, `tmpLimit`, `tmpLimitScale`, `devShmLimit`,
|
||||
+`devShmLimitScale`.
|
||||
|
||||
## Fields in the `binding` section
|
||||
|
||||
diff --git a/src/shared/user-record-show.c b/src/shared/user-record-show.c
|
||||
index dab75d1f79..a6173aabb8 100644
|
||||
--- a/src/shared/user-record-show.c
|
||||
+++ b/src/shared/user-record-show.c
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "hashmap.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "path-util.h"
|
||||
+#include "percent-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
@@ -54,6 +55,26 @@ static void dump_self_modifiable(
|
||||
printf("%13s %s\n", i == value ? heading : "", *i);
|
||||
}
|
||||
|
||||
+static void show_tmpfs_limit(const char *tmpfs, const TmpfsLimit *limit, uint32_t scale) {
|
||||
+ assert(tmpfs);
|
||||
+ assert(limit);
|
||||
+
|
||||
+ if (!limit->is_set)
|
||||
+ return;
|
||||
+
|
||||
+ printf(" %s Limit:", tmpfs);
|
||||
+
|
||||
+ if (limit->limit != UINT64_MAX)
|
||||
+ printf(" %s", FORMAT_BYTES(limit->limit));
|
||||
+ if (limit->limit == UINT64_MAX || limit->limit_scale != UINT32_MAX) {
|
||||
+ if (limit->limit != UINT64_MAX)
|
||||
+ printf(" or");
|
||||
+
|
||||
+ printf(" %i%%", UINT32_SCALE_TO_PERCENT(scale));
|
||||
+ }
|
||||
+ printf("\n");
|
||||
+}
|
||||
+
|
||||
void user_record_show(UserRecord *hr, bool show_full_group_info) {
|
||||
_cleanup_strv_free_ char **langs = NULL;
|
||||
const char *hd, *ip, *shell;
|
||||
@@ -371,6 +392,9 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
|
||||
if (hr->io_weight != UINT64_MAX)
|
||||
printf(" IO Weight: %" PRIu64 "\n", hr->io_weight);
|
||||
|
||||
+ show_tmpfs_limit("TMP", &hr->tmp_limit, user_record_tmp_limit_scale(hr));
|
||||
+ show_tmpfs_limit("SHM", &hr->dev_shm_limit, user_record_dev_shm_limit_scale(hr));
|
||||
+
|
||||
if (hr->access_mode != MODE_INVALID)
|
||||
printf(" Access Mode: 0%03o\n", user_record_access_mode(hr));
|
||||
|
||||
diff --git a/src/shared/user-record.c b/src/shared/user-record.c
|
||||
index bfea52427a..6a1813c402 100644
|
||||
--- a/src/shared/user-record.c
|
||||
+++ b/src/shared/user-record.c
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "locale-util.h"
|
||||
#include "memory-util.h"
|
||||
#include "path-util.h"
|
||||
+#include "percent-util.h"
|
||||
#include "pkcs11-util.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "sha256.h"
|
||||
@@ -95,6 +96,8 @@ UserRecord* user_record_new(void) {
|
||||
.drop_caches = -1,
|
||||
.auto_resize_mode = _AUTO_RESIZE_MODE_INVALID,
|
||||
.rebalance_weight = REBALANCE_WEIGHT_UNSET,
|
||||
+ .tmp_limit = TMPFS_LIMIT_NULL,
|
||||
+ .dev_shm_limit = TMPFS_LIMIT_NULL,
|
||||
};
|
||||
|
||||
return h;
|
||||
@@ -982,6 +985,40 @@ static int dispatch_rebalance_weight(const char *name, sd_json_variant *variant,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int dispatch_tmpfs_limit(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ TmpfsLimit *limit = ASSERT_PTR(userdata);
|
||||
+ int r;
|
||||
+
|
||||
+ if (sd_json_variant_is_null(variant)) {
|
||||
+ *limit = TMPFS_LIMIT_NULL;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ r = sd_json_dispatch_uint64(name, variant, flags, &limit->limit);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ limit->is_set = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int dispatch_tmpfs_limit_scale(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ TmpfsLimit *limit = ASSERT_PTR(userdata);
|
||||
+ int r;
|
||||
+
|
||||
+ if (sd_json_variant_is_null(variant)) {
|
||||
+ *limit = TMPFS_LIMIT_NULL;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ r = sd_json_dispatch_uint32(name, variant, flags, &limit->limit_scale);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ limit->is_set = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int dispatch_privileged(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
|
||||
static const sd_json_dispatch_field privileged_dispatch_table[] = {
|
||||
@@ -1299,6 +1336,10 @@ static int dispatch_per_machine(const char *name, sd_json_variant *variant, sd_j
|
||||
{ "selfModifiableFields", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(UserRecord, self_modifiable_fields), SD_JSON_STRICT },
|
||||
{ "selfModifiableBlobs", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(UserRecord, self_modifiable_blobs), SD_JSON_STRICT },
|
||||
{ "selfModifiablePrivileged", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(UserRecord, self_modifiable_privileged), SD_JSON_STRICT },
|
||||
+ { "tmpLimit", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit, offsetof(UserRecord, tmp_limit), 0, },
|
||||
+ { "tmpLimitScale", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit_scale, offsetof(UserRecord, tmp_limit), 0, },
|
||||
+ { "devShmLimit", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit, offsetof(UserRecord, dev_shm_limit), 0, },
|
||||
+ { "devShmLimitScale", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit_scale, offsetof(UserRecord, dev_shm_limit), 0, },
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -1650,6 +1691,10 @@ int user_record_load(UserRecord *h, sd_json_variant *v, UserRecordLoadFlags load
|
||||
{ "selfModifiableFields", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(UserRecord, self_modifiable_fields), SD_JSON_STRICT },
|
||||
{ "selfModifiableBlobs", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(UserRecord, self_modifiable_blobs), SD_JSON_STRICT },
|
||||
{ "selfModifiablePrivileged", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(UserRecord, self_modifiable_privileged), SD_JSON_STRICT },
|
||||
+ { "tmpLimit", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit, offsetof(UserRecord, tmp_limit), 0, },
|
||||
+ { "tmpLimitScale", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit_scale, offsetof(UserRecord, tmp_limit), 0, },
|
||||
+ { "devShmLimit", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit, offsetof(UserRecord, dev_shm_limit), 0, },
|
||||
+ { "devShmLimitScale", _SD_JSON_VARIANT_TYPE_INVALID, dispatch_tmpfs_limit_scale, offsetof(UserRecord, dev_shm_limit), 0, },
|
||||
|
||||
{ "secret", SD_JSON_VARIANT_OBJECT, dispatch_secret, 0, 0 },
|
||||
{ "privileged", SD_JSON_VARIANT_OBJECT, dispatch_privileged, 0, 0 },
|
||||
@@ -2163,6 +2208,32 @@ int user_record_languages(UserRecord *h, char ***ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+uint32_t user_record_tmp_limit_scale(UserRecord *h) {
|
||||
+ assert(h);
|
||||
+
|
||||
+ if (h->tmp_limit.is_set)
|
||||
+ return h->tmp_limit.limit_scale;
|
||||
+
|
||||
+ /* By default grant regular users only 80% quota */
|
||||
+ if (user_record_disposition(h) == USER_REGULAR)
|
||||
+ return UINT32_SCALE_FROM_PERCENT(80);
|
||||
+
|
||||
+ return UINT32_MAX;
|
||||
+}
|
||||
+
|
||||
+uint32_t user_record_dev_shm_limit_scale(UserRecord *h) {
|
||||
+ assert(h);
|
||||
+
|
||||
+ if (h->dev_shm_limit.is_set)
|
||||
+ return h->dev_shm_limit.limit_scale;
|
||||
+
|
||||
+ /* By default grant regular users only 80% quota */
|
||||
+ if (user_record_disposition(h) == USER_REGULAR)
|
||||
+ return UINT32_SCALE_FROM_PERCENT(80);
|
||||
+
|
||||
+ return UINT32_MAX;
|
||||
+}
|
||||
+
|
||||
const char** user_record_self_modifiable_fields(UserRecord *h) {
|
||||
/* As a rule of thumb: a setting is safe if it cannot be used by a
|
||||
* user to give themselves some unfair advantage over other users on
|
||||
diff --git a/src/shared/user-record.h b/src/shared/user-record.h
|
||||
index a3d8f4eb07..8c709750ae 100644
|
||||
--- a/src/shared/user-record.h
|
||||
+++ b/src/shared/user-record.h
|
||||
@@ -232,6 +232,19 @@ typedef enum AutoResizeMode {
|
||||
#define REBALANCE_WEIGHT_MAX UINT64_C(10000)
|
||||
#define REBALANCE_WEIGHT_UNSET UINT64_MAX
|
||||
|
||||
+typedef struct TmpfsLimit {
|
||||
+ /* Absolute and relative tmpfs limits */
|
||||
+ uint64_t limit;
|
||||
+ uint32_t limit_scale;
|
||||
+ bool is_set;
|
||||
+} TmpfsLimit;
|
||||
+
|
||||
+#define TMPFS_LIMIT_NULL \
|
||||
+ (TmpfsLimit) { \
|
||||
+ .limit = UINT64_MAX, \
|
||||
+ .limit_scale = UINT32_MAX, \
|
||||
+ } \
|
||||
+
|
||||
typedef struct UserRecord {
|
||||
/* The following three fields are not part of the JSON record */
|
||||
unsigned n_ref;
|
||||
@@ -392,6 +405,8 @@ typedef struct UserRecord {
|
||||
char **self_modifiable_blobs;
|
||||
char **self_modifiable_privileged;
|
||||
|
||||
+ TmpfsLimit tmp_limit, dev_shm_limit;
|
||||
+
|
||||
sd_json_variant *json;
|
||||
} UserRecord;
|
||||
|
||||
@@ -439,6 +454,8 @@ uint64_t user_record_rebalance_weight(UserRecord *h);
|
||||
uint64_t user_record_capability_bounding_set(UserRecord *h);
|
||||
uint64_t user_record_capability_ambient_set(UserRecord *h);
|
||||
int user_record_languages(UserRecord *h, char ***ret);
|
||||
+uint32_t user_record_tmp_limit_scale(UserRecord *h);
|
||||
+uint32_t user_record_dev_shm_limit_scale(UserRecord *h);
|
||||
|
||||
const char **user_record_self_modifiable_fields(UserRecord *h);
|
||||
const char **user_record_self_modifiable_blobs(UserRecord *h);
|
||||
108
0643-user-runtime-dir-some-smaller-modernizations-refacto.patch
Normal file
108
0643-user-runtime-dir-some-smaller-modernizations-refacto.patch
Normal file
@ -0,0 +1,108 @@
|
||||
From 801e4945fff10fd4250202fed1101f7e236ddd41 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 23 Jan 2025 22:30:41 +0100
|
||||
Subject: [PATCH] user-runtime-dir: some smaller modernizations/refactorings
|
||||
|
||||
(cherry picked from commit 9ef12bc1d73aa1c2d65ff006550180624e688a5c)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/login/user-runtime-dir.c | 44 +++++++++++++++++++-----------------
|
||||
1 file changed, 23 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c
|
||||
index b242f83429..f39c1ad225 100644
|
||||
--- a/src/login/user-runtime-dir.c
|
||||
+++ b/src/login/user-runtime-dir.c
|
||||
@@ -92,39 +92,38 @@ static int user_mkdir_runtime_path(
|
||||
uid, gid, runtime_dir_size, runtime_dir_inodes,
|
||||
mac_smack_use() ? ",smackfsroot=*" : "");
|
||||
|
||||
+ _cleanup_free_ char *d = strdup(runtime_path);
|
||||
+ if (!d)
|
||||
+ return log_oom();
|
||||
+
|
||||
r = mkdir_label(runtime_path, 0700);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return log_error_errno(r, "Failed to create %s: %m", runtime_path);
|
||||
|
||||
+ _cleanup_(rmdir_and_freep) char *destroy = TAKE_PTR(d); /* auto-destroy */
|
||||
+
|
||||
r = mount_nofollow_verbose(LOG_DEBUG, "tmpfs", runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, options);
|
||||
if (r < 0) {
|
||||
- if (!ERRNO_IS_PRIVILEGE(r)) {
|
||||
- log_error_errno(r, "Failed to mount per-user tmpfs directory %s: %m", runtime_path);
|
||||
- goto fail;
|
||||
- }
|
||||
+ if (!ERRNO_IS_PRIVILEGE(r))
|
||||
+ return log_error_errno(r, "Failed to mount per-user tmpfs directory %s: %m", runtime_path);
|
||||
|
||||
log_debug_errno(r,
|
||||
"Failed to mount per-user tmpfs directory %s.\n"
|
||||
"Assuming containerized execution, ignoring: %m", runtime_path);
|
||||
|
||||
r = chmod_and_chown(runtime_path, 0700, uid, gid);
|
||||
- if (r < 0) {
|
||||
- log_error_errno(r, "Failed to change ownership and mode of \"%s\": %m", runtime_path);
|
||||
- goto fail;
|
||||
- }
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to change ownership and mode of \"%s\": %m", runtime_path);
|
||||
}
|
||||
|
||||
+ destroy = mfree(destroy); /* deactivate auto-destroy */
|
||||
+
|
||||
r = label_fix(runtime_path, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to fix label of \"%s\", ignoring: %m", runtime_path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
-
|
||||
-fail:
|
||||
- /* Try to clean up, but ignore errors */
|
||||
- (void) rmdir(runtime_path);
|
||||
- return r;
|
||||
}
|
||||
|
||||
static int user_remove_runtime_path(const char *runtime_path) {
|
||||
@@ -139,9 +138,9 @@ static int user_remove_runtime_path(const char *runtime_path) {
|
||||
|
||||
/* Ignore cases where the directory isn't mounted, as that's quite possible, if we lacked the permissions to
|
||||
* mount something */
|
||||
- r = umount2(runtime_path, MNT_DETACH);
|
||||
- if (r < 0 && !IN_SET(errno, EINVAL, ENOENT))
|
||||
- log_debug_errno(errno, "Failed to unmount user runtime directory %s, ignoring: %m", runtime_path);
|
||||
+ r = RET_NERRNO(umount2(runtime_path, MNT_DETACH));
|
||||
+ if (r < 0 && !IN_SET(r, -EINVAL, -ENOENT))
|
||||
+ log_debug_errno(r, "Failed to unmount user runtime directory %s, ignoring: %m", runtime_path);
|
||||
|
||||
r = rm_rf(runtime_path, REMOVE_ROOT);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
@@ -206,7 +205,10 @@ static int run(int argc, char *argv[]) {
|
||||
if (argc != 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"This program takes two arguments.");
|
||||
- if (!STR_IN_SET(argv[1], "start", "stop"))
|
||||
+
|
||||
+ const char *verb = argv[1], *user = argv[2];
|
||||
+
|
||||
+ if (!STR_IN_SET(verb, "start", "stop"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"First argument must be either \"start\" or \"stop\".");
|
||||
|
||||
@@ -216,10 +218,10 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
- if (streq(argv[1], "start"))
|
||||
- return do_mount(argv[2]);
|
||||
- if (streq(argv[1], "stop"))
|
||||
- return do_umount(argv[2]);
|
||||
+ if (streq(verb, "start"))
|
||||
+ return do_mount(user);
|
||||
+ if (streq(verb, "stop"))
|
||||
+ return do_umount(user);
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
304
0644-user-runtime-dir-enforce-tmp-and-dev-shm-quota.patch
Normal file
304
0644-user-runtime-dir-enforce-tmp-and-dev-shm-quota.patch
Normal file
@ -0,0 +1,304 @@
|
||||
From 4aad3334b4618edc47d4813bdbed9b3ca6b86aec Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Fri, 10 Jan 2025 11:34:18 +0100
|
||||
Subject: [PATCH] user-runtime-dir: enforce /tmp/ and /dev/shm/ quota
|
||||
|
||||
Enforce the quota on these two tmpfs at the same place where we mount
|
||||
the per-user $XDG_RUNTIME_DIR. Conceptually these are very similar
|
||||
concepts, and it makes sure to enforce the limits at the same place with
|
||||
the same lifecycle.
|
||||
|
||||
(cherry picked from commit b1c95fb2e9d11fc190017dec3d64f468f9d378bc)
|
||||
|
||||
Resolves: RHEL-143028
|
||||
---
|
||||
README | 2 +
|
||||
man/user@.service.xml | 13 +--
|
||||
src/login/user-runtime-dir.c | 191 ++++++++++++++++++++++++++++++-----
|
||||
3 files changed, 173 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/README b/README
|
||||
index b9a58389ad..7d38f17b5a 100644
|
||||
--- a/README
|
||||
+++ b/README
|
||||
@@ -41,6 +41,8 @@ REQUIREMENTS:
|
||||
≥ 5.3 for bounded loops in BPF program
|
||||
≥ 5.4 for pidfd and signed Verity images
|
||||
≥ 5.7 for CLONE_INTO_CGROUP, BPF links and the BPF LSM hook
|
||||
+ ≥ 5.14 for quotactl_fd()
|
||||
+ ≥ 6.6 for quota support on tmpfs
|
||||
|
||||
⛔ Kernel versions below 3.15 ("minimum baseline") are not supported at
|
||||
all, and are missing required functionality (e.g. CLOCK_BOOTTIME
|
||||
diff --git a/man/user@.service.xml b/man/user@.service.xml
|
||||
index e9cbda4833..f2e83c1b16 100644
|
||||
--- a/man/user@.service.xml
|
||||
+++ b/man/user@.service.xml
|
||||
@@ -42,12 +42,13 @@
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry> for a
|
||||
list of units that form the basis of the unit hierarchies of system and user units.</para>
|
||||
|
||||
- <para><filename>user@<replaceable>UID</replaceable>.service</filename> is accompanied by the
|
||||
- system unit <filename>user-runtime-dir@<replaceable>UID</replaceable>.service</filename>, which
|
||||
- creates the user's runtime directory
|
||||
- <filename>/run/user/<replaceable>UID</replaceable></filename>, and then removes it when this
|
||||
- unit is stopped. <filename>user-runtime-dir@<replaceable>UID</replaceable>.service</filename>
|
||||
- executes the <filename>systemd-user-runtime-dir</filename> binary to do the actual work.</para>
|
||||
+ <para><filename>user@<replaceable>UID</replaceable>.service</filename> is accompanied by the system unit
|
||||
+ <filename>user-runtime-dir@<replaceable>UID</replaceable>.service</filename>, which creates the user's
|
||||
+ runtime directory <filename>/run/user/<replaceable>UID</replaceable></filename> when started, and removes
|
||||
+ it when it is stopped. It also might apply runtime quota settings on <filename>/tmp/</filename> and/or
|
||||
+ <filename>/dev/shm/</filename> for the
|
||||
+ user. <filename>user-runtime-dir@<replaceable>UID</replaceable>.service</filename> executes the
|
||||
+ <filename>systemd-user-runtime-dir</filename> binary to do the actual work.</para>
|
||||
|
||||
<para>User processes may be started by the <filename>user@.service</filename> instance, in which
|
||||
case they will be part of that unit in the system hierarchy. They may also be started elsewhere,
|
||||
diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c
|
||||
index f39c1ad225..94117c95db 100644
|
||||
--- a/src/login/user-runtime-dir.c
|
||||
+++ b/src/login/user-runtime-dir.c
|
||||
@@ -8,15 +8,20 @@
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "dev-setup.h"
|
||||
+#include "devnum-util.h"
|
||||
+#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "label-util.h"
|
||||
#include "limits-util.h"
|
||||
#include "main-func.h"
|
||||
+#include "missing_magic.h"
|
||||
+#include "missing_syscall.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "mount-util.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "path-util.h"
|
||||
+#include "quota-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "selinux-util.h"
|
||||
#include "smack-util.h"
|
||||
@@ -24,6 +29,7 @@
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
+#include "userdb.h"
|
||||
|
||||
static int acquire_runtime_dir_properties(uint64_t *ret_size, uint64_t *ret_inodes) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
@@ -126,6 +132,26 @@ static int user_mkdir_runtime_path(
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int do_mount(UserRecord *ur) {
|
||||
+ int r;
|
||||
+
|
||||
+ assert(ur);
|
||||
+
|
||||
+ if (!uid_is_valid(ur->uid) || !gid_is_valid(ur->gid))
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(ENOMSG), "User '%s' lacks UID or GID, refusing.", ur->user_name);
|
||||
+
|
||||
+ uint64_t runtime_dir_size, runtime_dir_inodes;
|
||||
+ r = acquire_runtime_dir_properties(&runtime_dir_size, &runtime_dir_inodes);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ char runtime_path[STRLEN("/run/user/") + DECIMAL_STR_MAX(uid_t)];
|
||||
+ xsprintf(runtime_path, "/run/user/" UID_FMT, ur->uid);
|
||||
+
|
||||
+ log_debug("Will mount %s owned by "UID_FMT":"GID_FMT, runtime_path, ur->uid, ur->gid);
|
||||
+ return user_mkdir_runtime_path(runtime_path, ur->uid, ur->gid, runtime_dir_size, runtime_dir_inodes);
|
||||
+}
|
||||
+
|
||||
static int user_remove_runtime_path(const char *runtime_path) {
|
||||
int r;
|
||||
|
||||
@@ -149,31 +175,6 @@ static int user_remove_runtime_path(const char *runtime_path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int do_mount(const char *user) {
|
||||
- char runtime_path[STRLEN("/run/user/") + DECIMAL_STR_MAX(uid_t)];
|
||||
- uint64_t runtime_dir_size, runtime_dir_inodes;
|
||||
- uid_t uid;
|
||||
- gid_t gid;
|
||||
- int r;
|
||||
-
|
||||
- r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
- if (r < 0)
|
||||
- return log_error_errno(r,
|
||||
- r == -ESRCH ? "No such user \"%s\"" :
|
||||
- r == -ENOMSG ? "UID \"%s\" is invalid or has an invalid main group"
|
||||
- : "Failed to look up user \"%s\": %m",
|
||||
- user);
|
||||
-
|
||||
- r = acquire_runtime_dir_properties(&runtime_dir_size, &runtime_dir_inodes);
|
||||
- if (r < 0)
|
||||
- return r;
|
||||
-
|
||||
- xsprintf(runtime_path, "/run/user/" UID_FMT, uid);
|
||||
-
|
||||
- log_debug("Will mount %s owned by "UID_FMT":"GID_FMT, runtime_path, uid, gid);
|
||||
- return user_mkdir_runtime_path(runtime_path, uid, gid, runtime_dir_size, runtime_dir_inodes);
|
||||
-}
|
||||
-
|
||||
static int do_umount(const char *user) {
|
||||
char runtime_path[STRLEN("/run/user/") + DECIMAL_STR_MAX(uid_t)];
|
||||
uid_t uid;
|
||||
@@ -197,6 +198,126 @@ static int do_umount(const char *user) {
|
||||
return user_remove_runtime_path(runtime_path);
|
||||
}
|
||||
|
||||
+static int apply_tmpfs_quota(
|
||||
+ char **paths,
|
||||
+ uid_t uid,
|
||||
+ uint64_t limit,
|
||||
+ uint32_t scale) {
|
||||
+
|
||||
+ _cleanup_set_free_ Set *processed = NULL;
|
||||
+ int r;
|
||||
+
|
||||
+ assert(uid_is_valid(uid));
|
||||
+
|
||||
+ STRV_FOREACH(p, paths) {
|
||||
+ _cleanup_close_ int fd = open(*p, O_DIRECTORY|O_CLOEXEC);
|
||||
+ if (fd < 0) {
|
||||
+ log_warning_errno(errno, "Failed to open '%s' in order to set quota, ignoring: %m", *p);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ struct stat st;
|
||||
+ if (fstat(fd, &st) < 0) {
|
||||
+ log_warning_errno(errno, "Failed to stat '%s' in order to set quota, ignoring: %m", *p);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Cover for bind mounted or symlinked /var/tmp/ + /tmp/ */
|
||||
+ if (set_contains(processed, DEVNUM_TO_PTR(st.st_dev))) {
|
||||
+ log_debug("Not setting quota on '%s', since already processed.", *p);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Remember we already dealt with this fs, even if the subsequent operation fails, since
|
||||
+ * there's no point in appyling quota twice, regardless if it succeeds or not. */
|
||||
+ if (set_ensure_put(&processed, /* hash_ops= */ NULL, DEVNUM_TO_PTR(st.st_dev)) < 0)
|
||||
+ return log_oom();
|
||||
+
|
||||
+ struct statfs sfs;
|
||||
+ if (fstatfs(fd, &sfs) < 0) {
|
||||
+ log_warning_errno(errno, "Failed to statfs '%s' in order to set quota, ignoring: %m", *p);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (!is_fs_type(&sfs, TMPFS_MAGIC)) {
|
||||
+ log_debug("Not setting quota on '%s', since not tmpfs.", *p);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ struct dqblk req;
|
||||
+ r = RET_NERRNO(quotactl_fd(fd, QCMD_FIXED(Q_GETQUOTA, USRQUOTA), uid, &req));
|
||||
+ if (r == -ESRCH)
|
||||
+ zero(req);
|
||||
+ else if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
|
||||
+ log_debug_errno(r, "No UID quota support on %s, not setting quota: %m", *p);
|
||||
+ continue;
|
||||
+ } else if (ERRNO_IS_NEG_PRIVILEGE(r)) {
|
||||
+ log_debug_errno(r, "Lacking privileges to query UID quota on %s, not setting quota: %m", *p);
|
||||
+ continue;
|
||||
+ } else if (r < 0) {
|
||||
+ log_warning_errno(r, "Failed to query disk quota on %s for UID " UID_FMT ", ignoring: %m", *p, uid);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ uint64_t v =
|
||||
+ (scale == 0) ? 0 :
|
||||
+ (scale == UINT32_MAX) ? UINT64_MAX :
|
||||
+ (uint64_t) ((double) (sfs.f_blocks * sfs.f_frsize) / scale * UINT32_MAX);
|
||||
+
|
||||
+ v = MIN(v, limit);
|
||||
+ v /= QIF_DQBLKSIZE;
|
||||
+
|
||||
+ if (FLAGS_SET(req.dqb_valid, QIF_BLIMITS) && v == req.dqb_bhardlimit) {
|
||||
+ /* Shortcut things if everything is set up properly already */
|
||||
+ log_debug("Configured quota on '%s' already matches the intended setting, not updating quota.", *p);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ req.dqb_valid = QIF_BLIMITS;
|
||||
+ req.dqb_bsoftlimit = req.dqb_bhardlimit = v;
|
||||
+
|
||||
+ r = RET_NERRNO(quotactl_fd(fd, QCMD_FIXED(Q_SETQUOTA, USRQUOTA), uid, &req));
|
||||
+ if (r == -ESRCH) {
|
||||
+ log_debug_errno(r, "Not setting UID quota on %s since UID quota is not supported: %m", *p);
|
||||
+ continue;
|
||||
+ } else if (ERRNO_IS_NEG_PRIVILEGE(r)) {
|
||||
+ log_debug_errno(r, "Lacking privileges to set UID quota on %s, skipping: %m", *p);
|
||||
+ continue;
|
||||
+ } else if (r < 0) {
|
||||
+ log_warning_errno(r, "Failed to set disk quota on %s for UID " UID_FMT ", ignoring: %m", *p, uid);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ log_info("Successfully configured disk quota for UID " UID_FMT " on %s to %s", uid, *p, FORMAT_BYTES(v * QIF_DQBLKSIZE));
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int do_tmpfs_quota(UserRecord *ur) {
|
||||
+ int r;
|
||||
+
|
||||
+ assert(ur);
|
||||
+
|
||||
+ if (user_record_is_root(ur)) {
|
||||
+ log_debug("Not applying tmpfs quota to root user.");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (!uid_is_valid(ur->uid))
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(ENOMSG), "User '%s' lacks UID, refusing.", ur->user_name);
|
||||
+
|
||||
+ r = apply_tmpfs_quota(STRV_MAKE("/tmp", "/var/tmp"), ur->uid, ur->tmp_limit.limit, user_record_tmp_limit_scale(ur));
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ r = apply_tmpfs_quota(STRV_MAKE("/dev/shm"), ur->uid, ur->dev_shm_limit.limit, user_record_dev_shm_limit_scale(ur));
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int run(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
@@ -218,10 +339,26 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
- if (streq(verb, "start"))
|
||||
- return do_mount(user);
|
||||
+ if (streq(verb, "start")) {
|
||||
+ _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
|
||||
+ r = userdb_by_name(user, /* match= */ NULL, USERDB_PARSE_NUMERIC|USERDB_SUPPRESS_SHADOW, &ur);
|
||||
+ if (r == -ESRCH)
|
||||
+ return log_error_errno(r, "User '%s' does not exist: %m", user);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to resolve user '%s': %m", user);
|
||||
+
|
||||
+ /* We do two things here: mount the per-user XDG_RUNTIME_DIR, and set up tmpfs quota on /tmp/
|
||||
+ * and /dev/shm/. */
|
||||
+
|
||||
+ r = 0;
|
||||
+ RET_GATHER(r, do_mount(ur));
|
||||
+ RET_GATHER(r, do_tmpfs_quota(ur));
|
||||
+ return r;
|
||||
+ }
|
||||
+
|
||||
if (streq(verb, "stop"))
|
||||
return do_umount(user);
|
||||
+
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
129
0645-homectl-add-support-for-configuring-tmpfs-limits.patch
Normal file
129
0645-homectl-add-support-for-configuring-tmpfs-limits.patch
Normal file
@ -0,0 +1,129 @@
|
||||
From aa2f389a0844384dc0ecfda291ddb5e4f2afbc40 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Fri, 10 Jan 2025 15:31:44 +0100
|
||||
Subject: [PATCH] homectl: add support for configuring tmpfs limits
|
||||
|
||||
(cherry picked from commit 2b2aebf4dd695d52cf8b6cbd38ba57affdc5a6bb)
|
||||
|
||||
Resolves: RHEL-143028
|
||||
---
|
||||
man/homectl.xml | 16 +++++++++++++
|
||||
src/home/homectl.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 73 insertions(+)
|
||||
|
||||
diff --git a/man/homectl.xml b/man/homectl.xml
|
||||
index d08972c421..adad89c54a 100644
|
||||
--- a/man/homectl.xml
|
||||
+++ b/man/homectl.xml
|
||||
@@ -792,6 +792,22 @@
|
||||
<xi:include href="version-info.xml" xpointer="v245"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><option>--tmp-limit=<replaceable>BYTES</replaceable></option></term>
|
||||
+ <term><option>--tmp-limit=<replaceable>PERCENT</replaceable></option></term>
|
||||
+ <term><option>--dev-shm-limit=<replaceable>BYTES</replaceable></option></term>
|
||||
+ <term><option>--dev-shm-limit=<replaceable>PERCENT</replaceable></option></term>
|
||||
+
|
||||
+ <listitem><para>Controls the per-user quota on <filename>/tmp/</filename> and
|
||||
+ <filename>/dev/shm/</filename> that is applied when the user logs in. Takes either an absolute value
|
||||
+ in bytes (with the usual K, M, G, T suffixes to the base of 1024), or a percentage. In the latter
|
||||
+ case the limit is applied relative to the size of the respective file system. This limit is only
|
||||
+ applied if the relevant file system is <literal>tmpfs</literal> and has no effect otherwise. Note
|
||||
+ that if these options are not used, a default quota might still be enforced (typically 80%.)</para>
|
||||
+
|
||||
+ <xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<varlistentry>
|
||||
<term><option>--storage=<replaceable>STORAGE</replaceable></option></term>
|
||||
|
||||
diff --git a/src/home/homectl.c b/src/home/homectl.c
|
||||
index 6d5aec1602..c99663ffea 100644
|
||||
--- a/src/home/homectl.c
|
||||
+++ b/src/home/homectl.c
|
||||
@@ -2854,6 +2854,9 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" --memory-max=BYTES Set maximum memory limit\n"
|
||||
" --cpu-weight=WEIGHT Set CPU weight\n"
|
||||
" --io-weight=WEIGHT Set IO weight\n"
|
||||
+ " --tmp-limit=BYTES|PERCENT Set limit on /tmp/\n"
|
||||
+ " --dev-shm-limit=BYTES|PERCENT\n"
|
||||
+ " Set limit on /dev/shm/\n"
|
||||
"\n%4$sStorage User Record Properties:%5$s\n"
|
||||
" --storage=STORAGE Storage type to use (luks, fscrypt, directory,\n"
|
||||
" subvolume, cifs)\n"
|
||||
@@ -3002,6 +3005,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_PROMPT_NEW_USER,
|
||||
ARG_AVATAR,
|
||||
ARG_LOGIN_BACKGROUND,
|
||||
+ ARG_TMP_LIMIT,
|
||||
+ ARG_DEV_SHM_LIMIT,
|
||||
ARG_MATCH,
|
||||
};
|
||||
|
||||
@@ -3103,6 +3108,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "blob", required_argument, NULL, 'b' },
|
||||
{ "avatar", required_argument, NULL, ARG_AVATAR },
|
||||
{ "login-background", required_argument, NULL, ARG_LOGIN_BACKGROUND },
|
||||
+ { "tmp-limit", required_argument, NULL, ARG_TMP_LIMIT },
|
||||
+ { "dev-shm-limit", required_argument, NULL, ARG_DEV_SHM_LIMIT },
|
||||
{ "match", required_argument, NULL, ARG_MATCH },
|
||||
{}
|
||||
};
|
||||
@@ -4541,6 +4548,56 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
+ case ARG_TMP_LIMIT:
|
||||
+ case ARG_DEV_SHM_LIMIT: {
|
||||
+ const char *field =
|
||||
+ c == ARG_TMP_LIMIT ? "tmpLimit" :
|
||||
+ c == ARG_DEV_SHM_LIMIT ? "devShmLimit" : NULL;
|
||||
+ const char *field_scale =
|
||||
+ c == ARG_TMP_LIMIT ? "tmpLimitScale" :
|
||||
+ c == ARG_DEV_SHM_LIMIT ? "devShmLimitScale" : NULL;
|
||||
+
|
||||
+ assert(field);
|
||||
+ assert(field_scale);
|
||||
+
|
||||
+ if (isempty(optarg)) {
|
||||
+ r = drop_from_identity(field);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ r = drop_from_identity(field_scale);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ r = parse_permyriad(optarg);
|
||||
+ if (r < 0) {
|
||||
+ uint64_t u;
|
||||
+
|
||||
+ r = parse_size(optarg, 1024, &u);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to parse %s/%s parameter: %s", field, field_scale, optarg);
|
||||
+
|
||||
+ r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field, u);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to set %s field: %m", field);
|
||||
+
|
||||
+ r = drop_from_identity(field_scale);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ } else {
|
||||
+ r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field_scale, UINT32_SCALE_FROM_PERMYRIAD(r));
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to set %s field: %m", field_scale);
|
||||
+
|
||||
+ r = drop_from_identity(field);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ }
|
||||
+
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
case ARG_MATCH:
|
||||
if (streq(optarg, "any"))
|
||||
match_identity = &arg_identity_extra;
|
||||
@ -0,0 +1,40 @@
|
||||
From 2425eb1611a0176aa096296d28e612be41c917ee Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Wed, 15 Jan 2025 00:25:22 +0100
|
||||
Subject: [PATCH] test: add test case for tmpfs quota logic + PAMName=
|
||||
ask-password logic
|
||||
|
||||
(cherry picked from commit d58d449fc6b828429f2e4d06779a45318eb17f27)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
test/units/TEST-46-HOMED.sh | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
diff --git a/test/units/TEST-46-HOMED.sh b/test/units/TEST-46-HOMED.sh
|
||||
index 8de170a1c9..3663e53908 100755
|
||||
--- a/test/units/TEST-46-HOMED.sh
|
||||
+++ b/test/units/TEST-46-HOMED.sh
|
||||
@@ -652,6 +652,22 @@ getent passwd aliastest@myrealm
|
||||
getent passwd aliastest2@myrealm
|
||||
getent passwd aliastest3@myrealm
|
||||
|
||||
+if findmnt -n -o options /tmp | grep -q usrquota ; then
|
||||
+
|
||||
+ NEWPASSWORD=quux homectl create tmpfsquota --storage=subvolume --dev-shm-limit=50K -P
|
||||
+
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/urandom of=/dev/shm/quotatestfile1 bs=1024 count=30
|
||||
+ (! run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/urandom of=/dev/shm/quotatestfile2 bs=1024 count=30)
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm /dev/shm/quotatestfile1 /dev/shm/quotatestfile2
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/urandom of=/dev/shm/quotatestfile1 bs=1024 count=30
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm /dev/shm/quotatestfile1
|
||||
+
|
||||
+ systemctl stop user@"$(id -u tmpfsquota)".service
|
||||
+
|
||||
+ wait_for_state tmpfsquota inactive
|
||||
+ homectl remove tmpfsquota
|
||||
+fi
|
||||
+
|
||||
systemd-analyze log-level info
|
||||
|
||||
touch /testok
|
||||
52
0647-update-TODO.patch
Normal file
52
0647-update-TODO.patch
Normal file
@ -0,0 +1,52 @@
|
||||
From aedee1c91632bc2f50e23733a94f3ca106960f05 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Wed, 15 Jan 2025 09:44:52 +0100
|
||||
Subject: [PATCH] update TODO
|
||||
|
||||
(cherry picked from commit 0054b7dce986b73e6cb10bf4ae51a1dd5ef57191)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
TODO | 8 --------
|
||||
1 file changed, 8 deletions(-)
|
||||
|
||||
diff --git a/TODO b/TODO
|
||||
index d6c2cef2f1..4ed9f5a834 100644
|
||||
--- a/TODO
|
||||
+++ b/TODO
|
||||
@@ -257,10 +257,6 @@ Features:
|
||||
|
||||
* pcrlock: add support for multi-profile UKIs
|
||||
|
||||
-* logind: when logging in use new tmpfs quota support to configure quota on
|
||||
- /tmp/ + /dev/shm/. But do so only in case of tmpfs, because otherwise quota
|
||||
- is persistent and any persistent settings mean we don#t have to reapply them.
|
||||
-
|
||||
* initrd: when transitioning from initrd to host, validate that
|
||||
/lib/modules/`uname -r` exists, refuse otherwise
|
||||
|
||||
@@ -1447,8 +1443,6 @@ Features:
|
||||
|
||||
* rework recursive read-only remount to use new mount API
|
||||
|
||||
-* PAM: pick up authentication token from credentials
|
||||
-
|
||||
* when mounting disk images: if IMAGE_ID/IMAGE_VERSION is set in os-release
|
||||
data in the image, make sure the image filename actually matches this, so
|
||||
that images cannot be misused.
|
||||
@@ -1515,7 +1509,6 @@ Features:
|
||||
- pass creds via keyring?
|
||||
- pass creds via memfd?
|
||||
- acquire + decrypt creds from pkcs11?
|
||||
- - make PAMName= acquire pw via creds logic
|
||||
- make macsec code in networkd read key via creds logic (copy logic from
|
||||
wireguard)
|
||||
- make gatewayd/remote read key via creds logic
|
||||
@@ -2378,7 +2371,6 @@ Features:
|
||||
- maybe make automatic, read-only, time-based reflink-copies of LUKS disk
|
||||
images (and btrfs snapshots of subvolumes) (think: time machine)
|
||||
- distinguish destroy / remove (i.e. currently we can unregister a user, unregister+remove their home directory, but not just remove their home directory)
|
||||
- - in systemd's PAMName= logic: query passwords with ssh-askpassword, so that we can make "loginctl set-linger" mode work
|
||||
- fingerprint authentication, pattern authentication, …
|
||||
- make sure "classic" user records can also be managed by homed
|
||||
- make size of $XDG_RUNTIME_DIR configurable in user record
|
||||
31
0648-core-dbus-service-fix-alignment.patch
Normal file
31
0648-core-dbus-service-fix-alignment.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From b1731e6bef1276d5081284fe7d0aa46a62e6749c Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Sun, 9 Feb 2025 19:59:13 +0100
|
||||
Subject: [PATCH] core/dbus-service: fix alignment
|
||||
|
||||
(cherry picked from commit 5fe4c30ca78679551edd7152b70d66b481453b66)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/core/dbus-service.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
|
||||
index 85eb99f218..a1c452e29f 100644
|
||||
--- a/src/core/dbus-service.c
|
||||
+++ b/src/core/dbus-service.c
|
||||
@@ -393,10 +393,10 @@ const sd_bus_vtable bus_service_vtable[] = {
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_METHOD_WITH_ARGS("MountImage",
|
||||
- SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir, "a(ss)", options),
|
||||
- SD_BUS_NO_RESULT,
|
||||
- bus_service_method_mount_image,
|
||||
- SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
+ SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir, "a(ss)", options),
|
||||
+ SD_BUS_NO_RESULT,
|
||||
+ bus_service_method_mount_image,
|
||||
+ SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_METHOD_WITH_ARGS("DumpFileDescriptorStore",
|
||||
SD_BUS_NO_ARGS,
|
||||
25
0649-core-mount-filter-out-fail-option-as-well.patch
Normal file
25
0649-core-mount-filter-out-fail-option-as-well.patch
Normal file
@ -0,0 +1,25 @@
|
||||
From 31d4a35652e852905137c532f2f8bd1fa2391dc0 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Sun, 9 Feb 2025 20:25:21 +0100
|
||||
Subject: [PATCH] core/mount: filter out "fail" option as well
|
||||
|
||||
(cherry picked from commit 7e9a78d6bea96bf8e9de615f6013c72f912f3e2d)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/core/mount.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index 136c3f1453..786c3ae5f5 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -1131,7 +1131,7 @@ static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParamete
|
||||
}
|
||||
|
||||
_cleanup_free_ char *opts = NULL;
|
||||
- r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts);
|
||||
+ r = fstab_filter_options(p->options, "nofail\0" "fail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
155
0650-core-mount-check-parameters_fragment-first-in-mount_.patch
Normal file
155
0650-core-mount-check-parameters_fragment-first-in-mount_.patch
Normal file
@ -0,0 +1,155 @@
|
||||
From db653b7fc6bc1fb503152c34f0d3e374d115a236 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Sun, 9 Feb 2025 20:41:20 +0100
|
||||
Subject: [PATCH] core/mount: check parameters_fragment first in
|
||||
mount_enter_(re)mounting()
|
||||
|
||||
I.e. don't perform any action if we can't spawn mount task anyway.
|
||||
Later the same check would be added to mount_can_start/reload(),
|
||||
so this makes things more coherent too.
|
||||
|
||||
(cherry picked from commit 65bc0c03b97065847b187af2092458977173def4)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/core/mount.c | 85 +++++++++++++++++++++++-------------------------
|
||||
1 file changed, 41 insertions(+), 44 deletions(-)
|
||||
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index 786c3ae5f5..b317af03a7 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -1160,7 +1160,12 @@ static void mount_enter_mounting(Mount *m) {
|
||||
goto fail;
|
||||
|
||||
p = get_mount_parameters_fragment(m);
|
||||
- if (p && mount_is_bind(p)) {
|
||||
+ if (!p) {
|
||||
+ r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ if (mount_is_bind(p)) {
|
||||
r = is_dir(p->what, /* follow = */ true);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_unit_info_errno(UNIT(m), r, "Failed to determine type of bind mount source '%s', ignoring: %m", p->what);
|
||||
@@ -1176,7 +1181,7 @@ static void mount_enter_mounting(Mount *m) {
|
||||
log_unit_warning_errno(UNIT(m), r, "Failed to create mount point '%s', ignoring: %m", m->where);
|
||||
|
||||
/* If we are asked to create an OverlayFS, create the upper/work directories if they are missing */
|
||||
- if (p && streq_ptr(p->fstype, "overlay")) {
|
||||
+ if (streq_ptr(p->fstype, "overlay")) {
|
||||
_cleanup_strv_free_ char **dirs = NULL;
|
||||
|
||||
r = fstab_filter_options(
|
||||
@@ -1205,13 +1210,9 @@ static void mount_enter_mounting(Mount *m) {
|
||||
|
||||
if (source_is_dir)
|
||||
unit_warn_if_dir_nonempty(UNIT(m), m->where);
|
||||
- unit_warn_leftover_processes(UNIT(m), /* start = */ true);
|
||||
-
|
||||
- m->control_command_id = MOUNT_EXEC_MOUNT;
|
||||
- m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
|
||||
|
||||
/* Create the source directory for bind-mounts if needed */
|
||||
- if (p && mount_is_bind(p)) {
|
||||
+ if (mount_is_bind(p)) {
|
||||
r = mkdir_p_label(p->what, m->directory_mode);
|
||||
/* mkdir_p_label() can return -EEXIST if the target path exists and is not a directory - which is
|
||||
* totally OK, in case the user wants us to overmount a non-directory inode. Also -EROFS can be
|
||||
@@ -1223,19 +1224,18 @@ static void mount_enter_mounting(Mount *m) {
|
||||
r, "Failed to make bind mount source '%s', ignoring: %m", p->what);
|
||||
}
|
||||
|
||||
- if (p) {
|
||||
- r = mount_set_mount_command(m, m->control_command, p);
|
||||
- if (r < 0) {
|
||||
- log_unit_warning_errno(UNIT(m), r, "Failed to prepare mount command line: %m");
|
||||
- goto fail;
|
||||
- }
|
||||
- } else {
|
||||
- r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
|
||||
+ mount_unwatch_control_pid(m);
|
||||
+ unit_warn_leftover_processes(UNIT(m), /* start = */ true);
|
||||
+
|
||||
+ m->control_command_id = MOUNT_EXEC_MOUNT;
|
||||
+ m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
|
||||
+
|
||||
+ r = mount_set_mount_command(m, m->control_command, p);
|
||||
+ if (r < 0) {
|
||||
+ log_unit_warning_errno(UNIT(m), r, "Failed to prepare mount command line: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- mount_unwatch_control_pid(m);
|
||||
-
|
||||
r = mount_spawn(m, m->control_command, &m->control_pid);
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(m), r, "Failed to spawn 'mount' task: %m");
|
||||
@@ -1265,42 +1265,39 @@ static void mount_enter_remounting(Mount *m) {
|
||||
|
||||
assert(m);
|
||||
|
||||
- /* Reset reload result when we are about to start a new remount operation */
|
||||
+ p = get_mount_parameters_fragment(m);
|
||||
+ if (!p) {
|
||||
+ r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ mount_unwatch_control_pid(m);
|
||||
m->reload_result = MOUNT_SUCCESS;
|
||||
|
||||
m->control_command_id = MOUNT_EXEC_REMOUNT;
|
||||
m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
|
||||
|
||||
- p = get_mount_parameters_fragment(m);
|
||||
- if (p) {
|
||||
- const char *o;
|
||||
-
|
||||
- if (p->options)
|
||||
- o = strjoina("remount,", p->options);
|
||||
- else
|
||||
- o = "remount";
|
||||
-
|
||||
- r = exec_command_set(m->control_command, MOUNT_PATH,
|
||||
- p->what, m->where,
|
||||
- "-o", o, NULL);
|
||||
- if (r >= 0 && m->sloppy_options)
|
||||
- r = exec_command_append(m->control_command, "-s", NULL);
|
||||
- if (r >= 0 && m->read_write_only)
|
||||
- r = exec_command_append(m->control_command, "-w", NULL);
|
||||
- if (r >= 0 && p->fstype)
|
||||
- r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
|
||||
- if (r < 0) {
|
||||
- log_unit_warning_errno(UNIT(m), r, "Failed to prepare remount command line: %m");
|
||||
- goto fail;
|
||||
- }
|
||||
+ const char *o;
|
||||
|
||||
- } else {
|
||||
- r = log_unit_warning_errno(UNIT(m), SYNTHETIC_ERRNO(ENOENT), "No mount parameters to operate on.");
|
||||
+ if (p->options)
|
||||
+ o = strjoina("remount,", p->options);
|
||||
+ else
|
||||
+ o = "remount";
|
||||
+
|
||||
+ r = exec_command_set(m->control_command, MOUNT_PATH,
|
||||
+ p->what, m->where,
|
||||
+ "-o", o, NULL);
|
||||
+ if (r >= 0 && m->sloppy_options)
|
||||
+ r = exec_command_append(m->control_command, "-s", NULL);
|
||||
+ if (r >= 0 && m->read_write_only)
|
||||
+ r = exec_command_append(m->control_command, "-w", NULL);
|
||||
+ if (r >= 0 && p->fstype)
|
||||
+ r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
|
||||
+ if (r < 0) {
|
||||
+ log_unit_warning_errno(UNIT(m), r, "Failed to prepare remount command line: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- mount_unwatch_control_pid(m);
|
||||
-
|
||||
r = mount_spawn(m, m->control_command, &m->control_pid);
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(m), r, "Failed to spawn 'remount' task: %m");
|
||||
@ -0,0 +1,49 @@
|
||||
From 341da00c9aea8c3987cbf7042c5392bd7b8f2181 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Mon, 10 Feb 2025 20:22:09 +0100
|
||||
Subject: [PATCH] core/mount: report accurate can_start and can_reload
|
||||
|
||||
(cherry picked from commit 74c0d9726cfbd4ecdf1807adf5433fcf4b1d86b4)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/core/mount.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index b317af03a7..6b38ee9431 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -1393,6 +1393,12 @@ static int mount_reload(Unit *u) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static bool mount_can_reload(Unit *u) {
|
||||
+ Mount *m = ASSERT_PTR(MOUNT(u));
|
||||
+
|
||||
+ return get_mount_parameters_fragment(m);
|
||||
+}
|
||||
+
|
||||
static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
Mount *m = ASSERT_PTR(MOUNT(u));
|
||||
|
||||
@@ -2334,6 +2340,9 @@ static int mount_test_startable(Unit *u) {
|
||||
return r;
|
||||
}
|
||||
|
||||
+ if (!get_mount_parameters_fragment(m))
|
||||
+ return -ENOENT;
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2448,7 +2457,9 @@ const UnitVTable mount_vtable = {
|
||||
|
||||
.start = mount_start,
|
||||
.stop = mount_stop,
|
||||
+
|
||||
.reload = mount_reload,
|
||||
+ .can_reload = mount_can_reload,
|
||||
|
||||
.clean = mount_clean,
|
||||
.can_clean = mount_can_clean,
|
||||
67
0652-core-mount-trivial-coding-style-cleanups.patch
Normal file
67
0652-core-mount-trivial-coding-style-cleanups.patch
Normal file
@ -0,0 +1,67 @@
|
||||
From 3aa54774b2d343c63feb3f7eafa5b489e526a8dc Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Wed, 12 Feb 2025 14:56:34 +0100
|
||||
Subject: [PATCH] core/mount: trivial coding style cleanups
|
||||
|
||||
(cherry picked from commit c7c6cf2031c1c0eb1839d2ea83b5a8de4af6da00)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/core/mount.c | 7 +++----
|
||||
src/core/mount.h | 2 +-
|
||||
2 files changed, 4 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index 6b38ee9431..8ec18d8952 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -45,9 +45,9 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
|
||||
[MOUNT_MOUNTING_DONE] = UNIT_ACTIVATING,
|
||||
[MOUNT_MOUNTED] = UNIT_ACTIVE,
|
||||
[MOUNT_REMOUNTING] = UNIT_RELOADING,
|
||||
- [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
|
||||
[MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
|
||||
[MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
|
||||
+ [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
|
||||
[MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
|
||||
[MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
|
||||
[MOUNT_FAILED] = UNIT_FAILED,
|
||||
@@ -1038,6 +1038,8 @@ static void mount_enter_unmounting(Mount *m) {
|
||||
MOUNT_UNMOUNTING_SIGKILL))
|
||||
m->n_retry_umount = 0;
|
||||
|
||||
+ mount_unwatch_control_pid(m);
|
||||
+
|
||||
m->control_command_id = MOUNT_EXEC_UNMOUNT;
|
||||
m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
|
||||
|
||||
@@ -1047,8 +1049,6 @@ static void mount_enter_unmounting(Mount *m) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
- mount_unwatch_control_pid(m);
|
||||
-
|
||||
r = mount_spawn(m, m->control_command, &m->control_pid);
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(m), r, "Failed to spawn 'umount' task: %m");
|
||||
@@ -1056,7 +1056,6 @@ static void mount_enter_unmounting(Mount *m) {
|
||||
}
|
||||
|
||||
mount_set_state(m, MOUNT_UNMOUNTING);
|
||||
-
|
||||
return;
|
||||
|
||||
fail:
|
||||
diff --git a/src/core/mount.h b/src/core/mount.h
|
||||
index 28cc7785d8..a8ae25e638 100644
|
||||
--- a/src/core/mount.h
|
||||
+++ b/src/core/mount.h
|
||||
@@ -81,7 +81,7 @@ struct Mount {
|
||||
|
||||
MountState state, deserialized_state;
|
||||
|
||||
- ExecCommand* control_command;
|
||||
+ ExecCommand *control_command;
|
||||
MountExecCommand control_command_id;
|
||||
PidRef control_pid;
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
From f9204b8dccc68a3256f1e03ac9aaa1db1721f9df Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Mon, 10 Feb 2025 20:24:22 +0100
|
||||
Subject: [PATCH] core/dbus-mount: add missing ReloadResult and CleanResult
|
||||
properties
|
||||
|
||||
(cherry picked from commit 0fa062f9836ea5ed09bc42026d2d576dfb52c409)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
man/org.freedesktop.systemd1.xml | 14 +++++++++++++-
|
||||
src/core/dbus-mount.c | 2 ++
|
||||
2 files changed, 15 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
|
||||
index 71d2a11d29..4e9d72be25 100644
|
||||
--- a/man/org.freedesktop.systemd1.xml
|
||||
+++ b/man/org.freedesktop.systemd1.xml
|
||||
@@ -7002,6 +7002,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b ReadWriteOnly = ...;
|
||||
readonly s Result = '...';
|
||||
+ readonly s ReloadResult = '...';
|
||||
+ readonly s CleanResult = '...';
|
||||
readonly u UID = ...;
|
||||
readonly u GID = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
@@ -7602,6 +7604,10 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<!--property ReadWriteOnly is not documented!-->
|
||||
|
||||
+ <!--property ReloadResult is not documented!-->
|
||||
+
|
||||
+ <!--property CleanResult is not documented!-->
|
||||
+
|
||||
<!--property UID is not documented!-->
|
||||
|
||||
<!--property GID is not documented!-->
|
||||
@@ -8150,6 +8156,10 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Result"/>
|
||||
|
||||
+ <variablelist class="dbus-property" generated="True" extra-ref="ReloadResult"/>
|
||||
+
|
||||
+ <variablelist class="dbus-property" generated="True" extra-ref="CleanResult"/>
|
||||
+
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="UID"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="GID"/>
|
||||
@@ -12386,7 +12396,9 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<varname>ManagedOOMMemoryPressureDurationUSec</varname>,
|
||||
<varname>ProtectControlGroupsEx</varname>, and
|
||||
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
||||
- <para><varname>GracefulOptions</varname> were added in version 258.</para>
|
||||
+ <para><varname>GracefulOptions</varname>,
|
||||
+ <varname>ReloadResult</varname>, and
|
||||
+ <varname>CleanResult</varname> were added in version 258.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Swap Unit Objects</title>
|
||||
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
|
||||
index 855300d025..72bd4c697a 100644
|
||||
--- a/src/core/dbus-mount.c
|
||||
+++ b/src/core/dbus-mount.c
|
||||
@@ -73,6 +73,8 @@ const sd_bus_vtable bus_mount_vtable[] = {
|
||||
SD_BUS_PROPERTY("ForceUnmount", "b", bus_property_get_bool, offsetof(Mount, force_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ReadWriteOnly", "b", bus_property_get_bool, offsetof(Mount, read_write_only), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
+ SD_BUS_PROPERTY("ReloadResult", "s", property_get_result, offsetof(Mount, reload_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
+ SD_BUS_PROPERTY("CleanResult", "s", property_get_result, offsetof(Mount, clean_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("GracefulOptions", "as", NULL, offsetof(Mount, graceful_options), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
49
0654-bus-unit-util-add-missing-assertions.patch
Normal file
49
0654-bus-unit-util-add-missing-assertions.patch
Normal file
@ -0,0 +1,49 @@
|
||||
From 3f7834fccb42fa5ffffc17c93e43a1bbced00964 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Tue, 11 Feb 2025 18:13:01 +0100
|
||||
Subject: [PATCH] bus-unit-util: add missing assertions
|
||||
|
||||
(cherry picked from commit 85f759baeeab59f25080bd19b2f338ae2d05ad8b)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/shared/bus-unit-util.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
|
||||
index 8667d10077..9128c06555 100644
|
||||
--- a/src/shared/bus-unit-util.c
|
||||
+++ b/src/shared/bus-unit-util.c
|
||||
@@ -148,9 +148,11 @@ static int bus_append_string(sd_bus_message *m, const char *field, const char *e
|
||||
}
|
||||
|
||||
static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) {
|
||||
- const char *p;
|
||||
int r;
|
||||
|
||||
+ assert(m);
|
||||
+ assert(field);
|
||||
+
|
||||
r = sd_bus_message_open_container(m, 'r', "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
@@ -167,16 +169,16 @@ static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq,
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
- for (p = eq;;) {
|
||||
+ for (const char *p = eq;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, separator, flags);
|
||||
- if (r == 0)
|
||||
- break;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Invalid syntax: %s", eq);
|
||||
+ if (r == 0)
|
||||
+ break;
|
||||
|
||||
r = sd_bus_message_append_basic(m, 's', word);
|
||||
if (r < 0)
|
||||
439
0655-core-mount-rework-GracefulOptions-to-be-just-x-syste.patch
Normal file
439
0655-core-mount-rework-GracefulOptions-to-be-just-x-syste.patch
Normal file
@ -0,0 +1,439 @@
|
||||
From 4c474d4d10e0c52e108bbb75ad3aad0ca2dca469 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Tue, 11 Feb 2025 18:43:25 +0100
|
||||
Subject: [PATCH] core/mount: rework GracefulOptions= to be just
|
||||
x-systemd.graceful-option=
|
||||
|
||||
09fbff57fcde47782a73f23b3d5cfdcd0e8f699b introduced new knob
|
||||
for such functionality. However, that seems unnecessary.
|
||||
|
||||
The mount option string is ubiquitous in that all of fstab,
|
||||
kernel cmdline, credentials, systemd-mount, ... speak it.
|
||||
And we already have x-systemd.device-bound= that's parsed
|
||||
by pid1 instead of fstab-generator. It feels hence more natural
|
||||
for graceful options to be an extension of that, rather than
|
||||
its own property.
|
||||
|
||||
There's also one nice side effect that the setting itself
|
||||
is now more graceful for systemd versions not supporting
|
||||
such feature.
|
||||
|
||||
(cherry picked from commit 0d76f1c4237a3e4adda828c694721fd709374b36)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
man/org.freedesktop.systemd1.xml | 9 +---
|
||||
man/systemd.mount.xml | 29 +++++------
|
||||
src/core/dbus-mount.c | 26 +---------
|
||||
src/core/load-fragment-gperf.gperf.in | 1 -
|
||||
src/core/load-fragment.c | 45 -----------------
|
||||
src/core/load-fragment.h | 1 -
|
||||
src/core/mount.c | 62 +++++++++++-------------
|
||||
src/core/mount.h | 2 -
|
||||
src/shared/bus-unit-util.c | 3 --
|
||||
test/units/TEST-87-AUX-UTILS-VM.mount.sh | 4 +-
|
||||
units/tmp.mount | 3 +-
|
||||
11 files changed, 47 insertions(+), 138 deletions(-)
|
||||
|
||||
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
|
||||
index 4e9d72be25..0b6be4c755 100644
|
||||
--- a/man/org.freedesktop.systemd1.xml
|
||||
+++ b/man/org.freedesktop.systemd1.xml
|
||||
@@ -7006,8 +7006,6 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
readonly s CleanResult = '...';
|
||||
readonly u UID = ...;
|
||||
readonly u GID = ...;
|
||||
- @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
- readonly as GracefulOptions = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
|
||||
readonly a(sasbttttuii) ExecMount = [...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
|
||||
@@ -7612,8 +7610,6 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<!--property GID is not documented!-->
|
||||
|
||||
- <!--property GracefulOptions is not documented!-->
|
||||
-
|
||||
<!--property ExecUnmount is not documented!-->
|
||||
|
||||
<!--property ExecRemount is not documented!-->
|
||||
@@ -8164,8 +8160,6 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="GID"/>
|
||||
|
||||
- <variablelist class="dbus-property" generated="True" extra-ref="GracefulOptions"/>
|
||||
-
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecMount"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecUnmount"/>
|
||||
@@ -12396,8 +12390,7 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
|
||||
<varname>ManagedOOMMemoryPressureDurationUSec</varname>,
|
||||
<varname>ProtectControlGroupsEx</varname>, and
|
||||
<varname>PrivatePIDs</varname> were added in version 257.</para>
|
||||
- <para><varname>GracefulOptions</varname>,
|
||||
- <varname>ReloadResult</varname>, and
|
||||
+ <para><varname>ReloadResult</varname>, and
|
||||
<varname>CleanResult</varname> were added in version 258.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
|
||||
index 9b394f6079..e84b6a9d48 100644
|
||||
--- a/man/systemd.mount.xml
|
||||
+++ b/man/systemd.mount.xml
|
||||
@@ -284,6 +284,19 @@
|
||||
<xi:include href="version-info.xml" xpointer="v220"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><option>x-systemd.graceful-option=</option></term>
|
||||
+
|
||||
+ <listitem><para>Additional mount option that shall be appended if supported by the kernel.
|
||||
+ This may be used to configure mount options that are optional and only enabled on kernels that
|
||||
+ support them. Note that this is supported only for native kernel mount options (i.e. explicitly not
|
||||
+ for mount options implemented in userspace, such as those processed by
|
||||
+ <command>/usr/bin/mount</command> itself, by FUSE or by mount helpers such as
|
||||
+ <command>mount.nfs</command>). This option may be specified more than once.</para>
|
||||
+
|
||||
+ <xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<varlistentry>
|
||||
<term><option>x-systemd.device-bound=</option></term>
|
||||
|
||||
@@ -650,22 +663,6 @@
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
-
|
||||
- <varlistentry>
|
||||
- <term><varname>GracefulOptions=</varname></term>
|
||||
-
|
||||
- <listitem><para>Additional mount options that shall be appended to <varname>Options=</varname> if
|
||||
- supported by the kernel. This may be used to configure mount options that are optional and only
|
||||
- enabled on kernels that support them. Note that this is supported only for native kernel mount
|
||||
- options (i.e. explicitly not for mount options implemented in userspace, such as those processed by
|
||||
- <command>/usr/bin/mount</command> itself, by FUSE or by mount helpers such as
|
||||
- <command>mount.nfs</command>).</para>
|
||||
-
|
||||
- <para>May be specified multiple times. If specified multiple times, all listed, supported mount
|
||||
- options are combined. If an empty string is assigned, the list is reset.</para>
|
||||
-
|
||||
- <xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
- </varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<xi:include href="systemd.service.xml" xpointer="shared-unit-options" />
|
||||
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
|
||||
index 72bd4c697a..6b30b90f7f 100644
|
||||
--- a/src/core/dbus-mount.c
|
||||
+++ b/src/core/dbus-mount.c
|
||||
@@ -77,7 +77,7 @@ const sd_bus_vtable bus_mount_vtable[] = {
|
||||
SD_BUS_PROPERTY("CleanResult", "s", property_get_result, offsetof(Mount, clean_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
- SD_BUS_PROPERTY("GracefulOptions", "as", NULL, offsetof(Mount, graceful_options), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
+
|
||||
BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
BUS_EXEC_COMMAND_VTABLE("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||
@@ -153,30 +153,6 @@ static int bus_mount_set_transient_property(
|
||||
if (streq(name, "ReadWriteOnly"))
|
||||
return bus_set_transient_bool(u, name, &m->read_write_only, message, flags, error);
|
||||
|
||||
- if (streq(name, "GracefulOptions")) {
|
||||
- _cleanup_strv_free_ char **add = NULL;
|
||||
- r = sd_bus_message_read_strv(message, &add);
|
||||
- if (r < 0)
|
||||
- return r;
|
||||
-
|
||||
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
-
|
||||
- if (strv_isempty(add)) {
|
||||
- m->graceful_options = strv_free(m->graceful_options);
|
||||
- unit_write_settingf(u, flags, name, "GracefulOptions=");
|
||||
- } else {
|
||||
- r = strv_extend_strv(&m->graceful_options, add, /* filter_duplicates= */ false);
|
||||
- if (r < 0)
|
||||
- return r;
|
||||
-
|
||||
- STRV_FOREACH(a, add)
|
||||
- unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "GracefulOptions=%s", *a);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
|
||||
index 5b67d7b554..d7564b3767 100644
|
||||
--- a/src/core/load-fragment-gperf.gperf.in
|
||||
+++ b/src/core/load-fragment-gperf.gperf.in
|
||||
@@ -546,7 +546,6 @@ Mount.SloppyOptions, config_parse_bool,
|
||||
Mount.LazyUnmount, config_parse_bool, 0, offsetof(Mount, lazy_unmount)
|
||||
Mount.ForceUnmount, config_parse_bool, 0, offsetof(Mount, force_unmount)
|
||||
Mount.ReadWriteOnly, config_parse_bool, 0, offsetof(Mount, read_write_only)
|
||||
-Mount.GracefulOptions, config_parse_mount_graceful_options, 0, offsetof(Mount, graceful_options)
|
||||
{{ EXEC_CONTEXT_CONFIG_ITEMS('Mount') }}
|
||||
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Mount') }}
|
||||
{{ KILL_CONTEXT_CONFIG_ITEMS('Mount') }}
|
||||
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
||||
index 9007846e64..90f054ec9e 100644
|
||||
--- a/src/core/load-fragment.c
|
||||
+++ b/src/core/load-fragment.c
|
||||
@@ -6121,51 +6121,6 @@ int config_parse_mount_node(
|
||||
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, path, data, userdata);
|
||||
}
|
||||
|
||||
-int config_parse_mount_graceful_options(
|
||||
- const char *unit,
|
||||
- const char *filename,
|
||||
- unsigned line,
|
||||
- const char *section,
|
||||
- unsigned section_line,
|
||||
- const char *lvalue,
|
||||
- int ltype,
|
||||
- const char *rvalue,
|
||||
- void *data,
|
||||
- void *userdata) {
|
||||
-
|
||||
- const Unit *u = ASSERT_PTR(userdata);
|
||||
- char ***sv = ASSERT_PTR(data);
|
||||
- int r;
|
||||
-
|
||||
- assert(filename);
|
||||
- assert(lvalue);
|
||||
- assert(rvalue);
|
||||
-
|
||||
- if (isempty(rvalue)) {
|
||||
- *sv = strv_free(*sv);
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
- _cleanup_free_ char *resolved = NULL;
|
||||
- r = unit_full_printf(u, rvalue, &resolved);
|
||||
- if (r < 0) {
|
||||
- log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- _cleanup_strv_free_ char **strv = NULL;
|
||||
-
|
||||
- r = strv_split_full(&strv, resolved, ",", EXTRACT_RETAIN_ESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
|
||||
- if (r < 0)
|
||||
- return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
-
|
||||
- r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates = */ false);
|
||||
- if (r < 0)
|
||||
- return log_oom();
|
||||
-
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
static int merge_by_names(Unit *u, Set *names, const char *id) {
|
||||
char *k;
|
||||
int r;
|
||||
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
|
||||
index 673088a42d..8ac962a94b 100644
|
||||
--- a/src/core/load-fragment.h
|
||||
+++ b/src/core/load-fragment.h
|
||||
@@ -164,7 +164,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_open_file);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_memory_pressure_watch);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_nft_set);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_mount_node);
|
||||
-CONFIG_PARSER_PROTOTYPE(config_parse_mount_graceful_options);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index 8ec18d8952..037902c91c 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -231,8 +231,6 @@ static void mount_done(Unit *u) {
|
||||
mount_unwatch_control_pid(m);
|
||||
|
||||
m->timer_event_source = sd_event_source_disable_unref(m->timer_event_source);
|
||||
-
|
||||
- m->graceful_options = strv_free(m->graceful_options);
|
||||
}
|
||||
|
||||
static int update_parameters_proc_self_mountinfo(
|
||||
@@ -1062,22 +1060,25 @@ fail:
|
||||
mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES, /* flush_result = */ false);
|
||||
}
|
||||
|
||||
-static int mount_append_graceful_options(Mount *m, const MountParameters *p, char **opts) {
|
||||
+static int mount_apply_graceful_options(Mount *m, const MountParameters *p, char **opts) {
|
||||
+ _cleanup_strv_free_ char **graceful = NULL;
|
||||
+ _cleanup_free_ char *filtered = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(p);
|
||||
assert(opts);
|
||||
|
||||
- if (strv_isempty(m->graceful_options))
|
||||
- return 0;
|
||||
+ r = fstab_filter_options(*opts, "x-systemd.graceful-option\0", NULL, NULL, &graceful, &filtered);
|
||||
+ if (r <= 0)
|
||||
+ return r;
|
||||
|
||||
if (!p->fstype) {
|
||||
- log_unit_warning(UNIT(m), "GracefulOptions= used but file system type not known, suppressing all graceful options.");
|
||||
+ log_unit_warning(UNIT(m), "x-systemd.graceful-option= used but file system type not known, suppressing all graceful options.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
- STRV_FOREACH(o, m->graceful_options) {
|
||||
+ STRV_FOREACH(o, graceful) {
|
||||
_cleanup_free_ char *k = NULL, *v = NULL;
|
||||
|
||||
r = split_pair(*o, "=", &k, &v);
|
||||
@@ -1086,21 +1087,22 @@ static int mount_append_graceful_options(Mount *m, const MountParameters *p, cha
|
||||
|
||||
r = mount_option_supported(p->fstype, k ?: *o, v);
|
||||
if (r < 0)
|
||||
- log_unit_warning_errno(UNIT(m), r, "GracefulOptions=%s specified, but cannot determine availability, suppressing.", *o);
|
||||
+ log_unit_warning_errno(UNIT(m), r,
|
||||
+ "x-systemd.graceful-option=%s specified, but cannot determine availability, suppressing: %m", *o);
|
||||
else if (r == 0)
|
||||
- log_unit_info(UNIT(m), "GracefulOptions=%s specified, but option is not available, suppressing.", *o);
|
||||
+ log_unit_info(UNIT(m), "x-systemd.graceful-option=%s specified, but option is not available, suppressing.", *o);
|
||||
else {
|
||||
- log_unit_debug(UNIT(m), "GracefulOptions=%s specified and supported, appending to mount option string.", *o);
|
||||
+ log_unit_debug(UNIT(m), "x-systemd.graceful-option=%s specified and supported, appending to mount option string.", *o);
|
||||
|
||||
- if (!strextend_with_separator(opts, ",", *o))
|
||||
+ if (!strextend_with_separator(&filtered, ",", *o))
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ return free_and_replace(*opts, filtered);
|
||||
}
|
||||
|
||||
-static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParameters *p) {
|
||||
+static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParameters *p, bool remount) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@@ -1134,10 +1136,19 @@ static int mount_set_mount_command(Mount *m, ExecCommand *c, const MountParamete
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
- r = mount_append_graceful_options(m, p, &opts);
|
||||
+ r = mount_apply_graceful_options(m, p, &opts);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
+ if (remount) {
|
||||
+ if (isempty(opts)) {
|
||||
+ opts = strdup("remount");
|
||||
+ if (!opts)
|
||||
+ return -ENOMEM;
|
||||
+ } else if (!strprepend(&opts, "remount,"))
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
if (!isempty(opts)) {
|
||||
r = exec_command_append(c, "-o", opts, NULL);
|
||||
if (r < 0)
|
||||
@@ -1229,9 +1240,9 @@ static void mount_enter_mounting(Mount *m) {
|
||||
m->control_command_id = MOUNT_EXEC_MOUNT;
|
||||
m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
|
||||
|
||||
- r = mount_set_mount_command(m, m->control_command, p);
|
||||
+ r = mount_set_mount_command(m, m->control_command, p, /* remount = */ false);
|
||||
if (r < 0) {
|
||||
- log_unit_warning_errno(UNIT(m), r, "Failed to prepare mount command line: %m");
|
||||
+ log_unit_error_errno(UNIT(m), r, "Failed to prepare mount command line: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -1276,24 +1287,9 @@ static void mount_enter_remounting(Mount *m) {
|
||||
m->control_command_id = MOUNT_EXEC_REMOUNT;
|
||||
m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
|
||||
|
||||
- const char *o;
|
||||
-
|
||||
- if (p->options)
|
||||
- o = strjoina("remount,", p->options);
|
||||
- else
|
||||
- o = "remount";
|
||||
-
|
||||
- r = exec_command_set(m->control_command, MOUNT_PATH,
|
||||
- p->what, m->where,
|
||||
- "-o", o, NULL);
|
||||
- if (r >= 0 && m->sloppy_options)
|
||||
- r = exec_command_append(m->control_command, "-s", NULL);
|
||||
- if (r >= 0 && m->read_write_only)
|
||||
- r = exec_command_append(m->control_command, "-w", NULL);
|
||||
- if (r >= 0 && p->fstype)
|
||||
- r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
|
||||
+ r = mount_set_mount_command(m, m->control_command, p, /* remount = */ true);
|
||||
if (r < 0) {
|
||||
- log_unit_warning_errno(UNIT(m), r, "Failed to prepare remount command line: %m");
|
||||
+ log_unit_error_errno(UNIT(m), r, "Failed to prepare remount command line: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
diff --git a/src/core/mount.h b/src/core/mount.h
|
||||
index a8ae25e638..7fd643f6fa 100644
|
||||
--- a/src/core/mount.h
|
||||
+++ b/src/core/mount.h
|
||||
@@ -88,8 +88,6 @@ struct Mount {
|
||||
sd_event_source *timer_event_source;
|
||||
|
||||
unsigned n_retry_umount;
|
||||
-
|
||||
- char **graceful_options;
|
||||
};
|
||||
|
||||
extern const UnitVTable mount_vtable;
|
||||
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
|
||||
index 9128c06555..bc58d43140 100644
|
||||
--- a/src/shared/bus-unit-util.c
|
||||
+++ b/src/shared/bus-unit-util.c
|
||||
@@ -2311,9 +2311,6 @@ static int bus_append_mount_property(sd_bus_message *m, const char *field, const
|
||||
"ReadwriteOnly"))
|
||||
return bus_append_parse_boolean(m, field, eq);
|
||||
|
||||
- if (streq(field, "GracefulOptions"))
|
||||
- return bus_append_strv(m, field, eq, /* separator= */ ",", 0);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/test/units/TEST-87-AUX-UTILS-VM.mount.sh b/test/units/TEST-87-AUX-UTILS-VM.mount.sh
|
||||
index c1bfbdc1a2..8ad7ae6fc5 100755
|
||||
--- a/test/units/TEST-87-AUX-UTILS-VM.mount.sh
|
||||
+++ b/test/units/TEST-87-AUX-UTILS-VM.mount.sh
|
||||
@@ -181,9 +181,9 @@ touch "$WORK_DIR/mnt/hello"
|
||||
[[ "$(stat -c "%U:%G" "$WORK_DIR/mnt/hello")" == "testuser:testuser" ]]
|
||||
systemd-umount LABEL=owner-vfat
|
||||
|
||||
-# Mkae sure that graceful mount options work
|
||||
+# Make sure that graceful mount options work
|
||||
GRACEFULTEST="/tmp/graceful/$RANDOM"
|
||||
-systemd-mount --tmpfs -p GracefulOptions=idefinitelydontexist,nr_inodes=4711,idonexisteither "$GRACEFULTEST"
|
||||
+systemd-mount --tmpfs --options="x-systemd.graceful-option=idefinitelydontexist,x-systemd.graceful-option=nr_inodes=4711,x-systemd.graceful-option=idonexisteither" "$GRACEFULTEST"
|
||||
findmnt -n -o options "$GRACEFULTEST"
|
||||
findmnt -n -o options "$GRACEFULTEST" | grep -q nr_inodes=4711
|
||||
umount "$GRACEFULTEST"
|
||||
diff --git a/units/tmp.mount b/units/tmp.mount
|
||||
index d347af56d3..373b131211 100644
|
||||
--- a/units/tmp.mount
|
||||
+++ b/units/tmp.mount
|
||||
@@ -22,8 +22,7 @@ After=swap.target
|
||||
What=tmpfs
|
||||
Where=/tmp
|
||||
Type=tmpfs
|
||||
-Options=mode=1777,strictatime,nosuid,nodev,size=50%%,nr_inodes=1m
|
||||
-GracefulOptions=usrquota
|
||||
+Options=mode=1777,strictatime,nosuid,nodev,size=50%%,nr_inodes=1m,x-systemd.graceful-option=usrquota
|
||||
|
||||
# Make 'systemctl enable tmp.mount' work:
|
||||
[Install]
|
||||
@ -0,0 +1,48 @@
|
||||
From 61d7212e99466780278b2f75be35c5d19cc93087 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Wed, 12 Feb 2025 15:44:13 +0100
|
||||
Subject: [PATCH] mountpoint-util: assume fsopen() works in
|
||||
mount_option_supported()
|
||||
|
||||
Our baseline includes it now.
|
||||
|
||||
(cherry picked from commit c2198d0c3fdbebd30b0653f2e3d148372c5fff31)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/basic/mountpoint-util.c | 12 ++++--------
|
||||
1 file changed, 4 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c
|
||||
index e8471d5974..76f1a6d6b4 100644
|
||||
--- a/src/basic/mountpoint-util.c
|
||||
+++ b/src/basic/mountpoint-util.c
|
||||
@@ -803,14 +803,10 @@ int mount_option_supported(const char *fstype, const char *key, const char *valu
|
||||
assert(key);
|
||||
|
||||
fd = fsopen(fstype, FSOPEN_CLOEXEC);
|
||||
- if (fd < 0) {
|
||||
- if (ERRNO_IS_NOT_SUPPORTED(errno))
|
||||
- return -EAGAIN; /* new mount API not available → don't know */
|
||||
-
|
||||
+ if (fd < 0)
|
||||
return log_debug_errno(errno, "Failed to open superblock context for '%s': %m", fstype);
|
||||
- }
|
||||
|
||||
- /* Various file systems have not been converted to the new mount API yet. For such file systems
|
||||
+ /* Various file systems support fs context only in recent kernels (e.g. btrfs). For older kernels
|
||||
* fsconfig() with FSCONFIG_SET_STRING/FSCONFIG_SET_FLAG never fail. Which sucks, because we want to
|
||||
* use it for testing support, after all. Let's hence do a check if the file system got converted yet
|
||||
* first. */
|
||||
@@ -819,9 +815,9 @@ int mount_option_supported(const char *fstype, const char *key, const char *valu
|
||||
* the new mount API yet. If it returns EINVAL the mount option doesn't exist, but the fstype
|
||||
* is converted. */
|
||||
if (errno == EOPNOTSUPP)
|
||||
- return -EAGAIN; /* FSCONFIG_SET_FD not supported on the fs, hence not converted to new mount API → don't know */
|
||||
+ return -EAGAIN; /* fs not converted to new mount API → don't know */
|
||||
if (errno != EINVAL)
|
||||
- return log_debug_errno(errno, "Failed to check if file system has been converted to new mount API: %m");
|
||||
+ return log_debug_errno(errno, "Failed to check if file system '%s' has been converted to new mount API: %m", fstype);
|
||||
|
||||
/* So FSCONFIG_SET_FD worked, but the option didn't exist (we got EINVAL), this means the fs
|
||||
* is converted. Let's now ask the actual question we wonder about. */
|
||||
@ -0,0 +1,30 @@
|
||||
From 84f15472bcaa058a19bd63434cfb74eeb91d9cc6 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Tue, 11 Feb 2025 19:44:59 +0100
|
||||
Subject: [PATCH] core/mount: log only once about fs not supporting new mount
|
||||
API
|
||||
|
||||
(cherry picked from commit f565e5a94a778979172705e8c3a8581ec9f15865)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/core/mount.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index 037902c91c..530d567a96 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -1086,6 +1086,12 @@ static int mount_apply_graceful_options(Mount *m, const MountParameters *p, char
|
||||
return r;
|
||||
|
||||
r = mount_option_supported(p->fstype, k ?: *o, v);
|
||||
+ if (r == -EAGAIN) {
|
||||
+ log_unit_warning_errno(UNIT(m), r,
|
||||
+ "x-systemd.graceful-option= used but not supported by file system %s, suppressing all.",
|
||||
+ p->fstype);
|
||||
+ break;
|
||||
+ }
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(UNIT(m), r,
|
||||
"x-systemd.graceful-option=%s specified, but cannot determine availability, suppressing: %m", *o);
|
||||
29
0658-user-runtime-dir-correct-quota-size-calculation.patch
Normal file
29
0658-user-runtime-dir-correct-quota-size-calculation.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From 94ce567ebb8175392a2dd7416b15e6561d100cbc Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Mon, 3 Feb 2025 16:18:14 +0100
|
||||
Subject: [PATCH] user-runtime-dir: correct quota size calculation
|
||||
|
||||
Follow-up for b1c95fb2e9d11fc190017dec3d64f468f9d378bc
|
||||
|
||||
Fixes #36245
|
||||
|
||||
(cherry picked from commit 6790db81d6bf59c34ca89f901b34e9f81cbde1a5)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/login/user-runtime-dir.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c
|
||||
index 94117c95db..590b445d41 100644
|
||||
--- a/src/login/user-runtime-dir.c
|
||||
+++ b/src/login/user-runtime-dir.c
|
||||
@@ -262,7 +262,7 @@ static int apply_tmpfs_quota(
|
||||
uint64_t v =
|
||||
(scale == 0) ? 0 :
|
||||
(scale == UINT32_MAX) ? UINT64_MAX :
|
||||
- (uint64_t) ((double) (sfs.f_blocks * sfs.f_frsize) / scale * UINT32_MAX);
|
||||
+ (uint64_t) ((double) (sfs.f_blocks * sfs.f_frsize) * scale / UINT32_MAX);
|
||||
|
||||
v = MIN(v, limit);
|
||||
v /= QIF_DQBLKSIZE;
|
||||
135
0659-test-display-quota-add-a-little-helper-binary-to-sho.patch
Normal file
135
0659-test-display-quota-add-a-little-helper-binary-to-sho.patch
Normal file
@ -0,0 +1,135 @@
|
||||
From 73f66207da99d5f577a4be1cbcf34030e5b4a9b4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Fri, 28 Mar 2025 18:45:23 +0100
|
||||
Subject: [PATCH] test-display-quota: add a little helper binary to show quota
|
||||
on tmpfs
|
||||
|
||||
quota from quota project fails:
|
||||
$ quota
|
||||
quota: Cannot stat() mounted device tmpfs: No such file or directory
|
||||
quota: Cannot stat() mounted device tmpfs: No such file or directory
|
||||
|
||||
Having this helper helped me understand what is going on with the quotas when
|
||||
the tests failed. I think it'd be useful to keep it around for now, even though
|
||||
it is not actually connected in the tests.
|
||||
|
||||
(cherry picked from commit cb6b1611622ee717d4d6e9251fa41652b8ba8e2f)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
src/test/meson.build | 4 ++
|
||||
src/test/test-display-quota.c | 90 +++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 94 insertions(+)
|
||||
create mode 100644 src/test/test-display-quota.c
|
||||
|
||||
diff --git a/src/test/meson.build b/src/test/meson.build
|
||||
index 5dd9e3b8bd..0f5de6a5d0 100644
|
||||
--- a/src/test/meson.build
|
||||
+++ b/src/test/meson.build
|
||||
@@ -277,6 +277,10 @@ executables += [
|
||||
'dependencies' : lib_openssl_or_gcrypt,
|
||||
'conditions' : ['HAVE_OPENSSL_OR_GCRYPT'],
|
||||
},
|
||||
+ test_template + {
|
||||
+ 'sources' : files('test-display-quota.c'),
|
||||
+ 'type' : 'manual',
|
||||
+ },
|
||||
test_template + {
|
||||
'sources' : files('test-dlopen-so.c'),
|
||||
'dependencies' : [
|
||||
diff --git a/src/test/test-display-quota.c b/src/test/test-display-quota.c
|
||||
new file mode 100644
|
||||
index 0000000000..57e8352826
|
||||
--- /dev/null
|
||||
+++ b/src/test/test-display-quota.c
|
||||
@@ -0,0 +1,90 @@
|
||||
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
+
|
||||
+#include "bitfield.h"
|
||||
+#include "fd-util.h"
|
||||
+#include "log.h"
|
||||
+#include "main-func.h"
|
||||
+#include "missing_syscall.h"
|
||||
+#include "quota-util.h"
|
||||
+#include "strv.h"
|
||||
+#include "userdb.h"
|
||||
+#include "user-util.h"
|
||||
+
|
||||
+static int show_quota(uid_t uid, const char *path) {
|
||||
+ int r;
|
||||
+
|
||||
+ _cleanup_close_ int fd = open(path, O_DIRECTORY|O_CLOEXEC);
|
||||
+ if (fd < 0)
|
||||
+ return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||
+
|
||||
+ struct dqblk req;
|
||||
+ r = quotactl_fd_with_fallback(fd, QCMD_FIXED(Q_GETQUOTA, USRQUOTA), uid, &req);
|
||||
+ if (r == -ESRCH) {
|
||||
+ log_info_errno(r, "No quota set on %s for UID "UID_FMT": %m", path, uid);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
+ return log_warning_errno(r, "No UID quota support on %s: %m", path);
|
||||
+ if (ERRNO_IS_NEG_PRIVILEGE(r))
|
||||
+ return log_error_errno(r, "Lacking privileges to query UID quota on %s: %m", path);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to query disk quota on %s for UID "UID_FMT": %m", path, uid);
|
||||
+
|
||||
+ printf("** Quota on %s for UID "UID_FMT" **\n"
|
||||
+ "block hardlimit: %"PRIu64"\n"
|
||||
+ "block softlimit: %"PRIu64"\n"
|
||||
+ "blocks current: %"PRIu64"\n"
|
||||
+ "inodes hardlimit: %"PRIu64"\n"
|
||||
+ "inodes softlimit: %"PRIu64"\n"
|
||||
+ "inodes current: %"PRIu64"\n"
|
||||
+ "excess block time: %"PRIu64"\n"
|
||||
+ "excess inode time: %"PRIu64"\n"
|
||||
+ "validity mask: 0x%"PRIx32,
|
||||
+ path, uid,
|
||||
+ req.dqb_bhardlimit,
|
||||
+ req.dqb_bsoftlimit,
|
||||
+ req.dqb_curspace,
|
||||
+ req.dqb_ihardlimit,
|
||||
+ req.dqb_isoftlimit,
|
||||
+ req.dqb_curinodes,
|
||||
+ req.dqb_btime,
|
||||
+ req.dqb_itime,
|
||||
+ req.dqb_valid);
|
||||
+
|
||||
+ const char* fields[] = {"BLIMITS", "SPACE", "INODES", "BTIME", "ITIME"};
|
||||
+ bool first = true;
|
||||
+ for (size_t i = 0; i < ELEMENTSOF(fields); i++)
|
||||
+ if (BIT_SET(req.dqb_valid, i)) {
|
||||
+ printf("%c%s", first ? ' ' : '|', fields[i]);
|
||||
+ first = false;
|
||||
+ }
|
||||
+ printf("%s\n", first ? "(none)" : "");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int run(int argc, char **argv) {
|
||||
+ int r;
|
||||
+
|
||||
+ if (argc < 2)
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
+ "This program requires at least one argument\n"
|
||||
+ "syntax: test-display-quota USER PATH…");
|
||||
+
|
||||
+ const char *user = argv[1];
|
||||
+ _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
|
||||
+ r = userdb_by_name(user, /* match= */ NULL, USERDB_PARSE_NUMERIC|USERDB_SUPPRESS_SHADOW, &ur);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to resolve user '%s': %m", user);
|
||||
+
|
||||
+ if (!uid_is_valid(ur->uid))
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(ENOMSG), "User '%s' lacks UID.", ur->user_name);
|
||||
+
|
||||
+ r = 0;
|
||||
+ STRV_FOREACH(path, strv_skip(argv, 2))
|
||||
+ RET_GATHER(r, show_quota(ur->uid, *path));
|
||||
+
|
||||
+ return r;
|
||||
+}
|
||||
+
|
||||
+DEFINE_MAIN_FUNCTION(run);
|
||||
@ -0,0 +1,61 @@
|
||||
From e94a7c655a3493ddcd7bb68ac1b9112f8976e57c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Sat, 29 Mar 2025 09:24:34 +0100
|
||||
Subject: [PATCH] TEST-46-HOMED: check for support on /dev/shm and /tmp
|
||||
separately
|
||||
|
||||
The test fails in CI. My guess was this is because the enablement of quota on
|
||||
/tmp and /dev/shm is independent. The former fs is mounted by systemd in the
|
||||
host, while the latter is mounted in the initrd, so we can end up with quota
|
||||
support on one but not the other, which is the situation I had on my laptop.
|
||||
This wasn't actually the source of the problems in CI, but it's a reasonable
|
||||
change to make anyway.
|
||||
|
||||
While at it, test both mountpoints separately.
|
||||
|
||||
(cherry picked from commit cb86668f2cf7bc94ed28147fab7293b4795e6ab4)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
test/units/TEST-46-HOMED.sh | 27 +++++++++++++--------------
|
||||
1 file changed, 13 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/test/units/TEST-46-HOMED.sh b/test/units/TEST-46-HOMED.sh
|
||||
index 3663e53908..4af79e971c 100755
|
||||
--- a/test/units/TEST-46-HOMED.sh
|
||||
+++ b/test/units/TEST-46-HOMED.sh
|
||||
@@ -652,21 +652,20 @@ getent passwd aliastest@myrealm
|
||||
getent passwd aliastest2@myrealm
|
||||
getent passwd aliastest3@myrealm
|
||||
|
||||
-if findmnt -n -o options /tmp | grep -q usrquota ; then
|
||||
-
|
||||
- NEWPASSWORD=quux homectl create tmpfsquota --storage=subvolume --dev-shm-limit=50K -P
|
||||
-
|
||||
- run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/urandom of=/dev/shm/quotatestfile1 bs=1024 count=30
|
||||
- (! run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/urandom of=/dev/shm/quotatestfile2 bs=1024 count=30)
|
||||
- run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm /dev/shm/quotatestfile1 /dev/shm/quotatestfile2
|
||||
- run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/urandom of=/dev/shm/quotatestfile1 bs=1024 count=30
|
||||
- run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm /dev/shm/quotatestfile1
|
||||
-
|
||||
- systemctl stop user@"$(id -u tmpfsquota)".service
|
||||
+NEWPASSWORD=quux homectl create tmpfsquota --storage=subvolume --dev-shm-limit=50K --tmp-limit=50K -P
|
||||
+for p in /dev/shm /tmp; do
|
||||
+ if findmnt -n -o options "$p" | grep -q usrquota; then
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/zero of="$p/quotatestfile1" bs=1024 count=30
|
||||
+ (! run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/zero of="$p/quotatestfile2" bs=1024 count=30)
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm "$p/quotatestfile1" "$p/quotatestfile2"
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/zero of="$p/quotatestfile1" bs=1024 count=30
|
||||
+ run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm "$p/quotatestfile1"
|
||||
+ fi
|
||||
+done
|
||||
|
||||
- wait_for_state tmpfsquota inactive
|
||||
- homectl remove tmpfsquota
|
||||
-fi
|
||||
+systemctl stop user@"$(id -u tmpfsquota)".service
|
||||
+wait_for_state tmpfsquota inactive
|
||||
+homectl remove tmpfsquota
|
||||
|
||||
systemd-analyze log-level info
|
||||
|
||||
46
0661-TEST-46-HOMED-conditionally-skip-usrquota-tests.patch
Normal file
46
0661-TEST-46-HOMED-conditionally-skip-usrquota-tests.patch
Normal file
@ -0,0 +1,46 @@
|
||||
From 05fcb907f1a80d1d1b6a2899a1499faf47aed5d3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Mon, 31 Mar 2025 22:50:38 +0200
|
||||
Subject: [PATCH] TEST-46-HOMED: conditionally skip usrquota tests
|
||||
|
||||
The tests were failing, because the quota was not enforced.
|
||||
It seems that we simply don't have privileges to set or display the quota.
|
||||
The test is running priviled, so this is probably some SELinux:
|
||||
TEST-46-HOMED.sh[117]: + /usr/lib/systemd/tests/unit-tests/manual/test-display-quota tmpfsquota /dev/shm /tmp
|
||||
TEST-46-HOMED.sh[1103]: Lacking privileges to query UID quota on /dev/shm: Operation not permitted
|
||||
TEST-46-HOMED.sh[1103]: Lacking privileges to query UID quota on /tmp: Operation not permitted
|
||||
|
||||
If we cannot display the quota, ignore the test results.
|
||||
In a local run under mkosi, quota is shown and the tests pass. So this is something
|
||||
about how the testing-farm:fedora-rawhide-x86_64 is configured.
|
||||
|
||||
(cherry picked from commit f77a8edfefd47e481fab78e7dd75d5d088d4e5e3)
|
||||
|
||||
Related: RHEL-143028
|
||||
---
|
||||
test/units/TEST-46-HOMED.sh | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/test/units/TEST-46-HOMED.sh b/test/units/TEST-46-HOMED.sh
|
||||
index 4af79e971c..998a52c76a 100755
|
||||
--- a/test/units/TEST-46-HOMED.sh
|
||||
+++ b/test/units/TEST-46-HOMED.sh
|
||||
@@ -655,11 +655,18 @@ getent passwd aliastest3@myrealm
|
||||
NEWPASSWORD=quux homectl create tmpfsquota --storage=subvolume --dev-shm-limit=50K --tmp-limit=50K -P
|
||||
for p in /dev/shm /tmp; do
|
||||
if findmnt -n -o options "$p" | grep -q usrquota; then
|
||||
+ # Check if we can display the quotas. If we cannot, than it's likely
|
||||
+ # that PID1 was also not able to set the limits and we should not fail
|
||||
+ # in the tests below.
|
||||
+ /usr/lib/systemd/tests/unit-tests/manual/test-display-quota tmpfsquota "$p" || set +e
|
||||
+
|
||||
run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/zero of="$p/quotatestfile1" bs=1024 count=30
|
||||
(! run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/zero of="$p/quotatestfile2" bs=1024 count=30)
|
||||
run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm "$p/quotatestfile1" "$p/quotatestfile2"
|
||||
run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota dd if=/dev/zero of="$p/quotatestfile1" bs=1024 count=30
|
||||
run0 --property=SetCredential=pam.authtok.systemd-run0:quux -u tmpfsquota rm "$p/quotatestfile1"
|
||||
+
|
||||
+ set -e
|
||||
fi
|
||||
done
|
||||
|
||||
108
systemd.spec
108
systemd.spec
@ -48,7 +48,7 @@ Url: https://systemd.io
|
||||
# Allow users to specify the version and release when building the rpm by
|
||||
# setting the %%version_override and %%release_override macros.
|
||||
Version: %{?version_override}%{!?version_override:257}
|
||||
Release: 23%{?dist}
|
||||
Release: 24%{?dist}
|
||||
|
||||
%global stable %(c="%version"; [ "$c" = "${c#*.*}" ]; echo $?)
|
||||
|
||||
@ -719,6 +719,58 @@ Patch0606: 0606-TEST-35-LOGIN-test-coldplug-without-fdstore-on-kerne.patch
|
||||
Patch0607: 0607-logind-fix-potential-fd-leak-in-deliver_session_lead.patch
|
||||
Patch0608: 0608-Revert-coredump-lock-down-EnterNamespace-mount-even-.patch
|
||||
Patch0609: 0609-coredump-add-compat-support-for-SYSTEMD_COREDUMP_ALL.patch
|
||||
Patch0610: 0610-ci-re-enable-bpf-framework-option-for-build-and-unit.patch
|
||||
Patch0611: 0611-ci-add-bpftool-workaround-to-codeql-job-too.patch
|
||||
Patch0612: 0612-ci-fix-workaround-about-bpftool-for-codeql.patch
|
||||
Patch0613: 0613-ci-add-bpftool-workaround-to-coverity-too.patch
|
||||
Patch0614: 0614-Revert-man-mention-RHEL-documentation-in-systemctl-s.patch
|
||||
Patch0615: 0615-path-util-add-flavour-of-path_startswith-that-leaves.patch
|
||||
Patch0616: 0616-cgroup-port-some-code-over-to-path_startswith_full.patch
|
||||
Patch0617: 0617-path-util-invert-PATH_STARTSWITH_ACCEPT_DOT_DOT-flag.patch
|
||||
Patch0618: 0618-sd-json-fix-off-by-one-issue-when-updating-parent-fo.patch
|
||||
Patch0619: 0619-core-cgroup-avoid-one-unnecessary-strjoina.patch
|
||||
Patch0620: 0620-core-validate-input-cgroup-path-more-prudently.patch
|
||||
Patch0621: 0621-nspawn-apply-BindUser-Ephemeral-from-settings-file-o.patch
|
||||
Patch0622: 0622-nspawn-normalize-pivot_root-paths.patch
|
||||
Patch0623: 0623-udev-check-for-invalid-chars-in-various-fields-recei.patch
|
||||
Patch0624: 0624-udev-ensure-there-is-space-for-trailing-NUL-before-c.patch
|
||||
Patch0625: 0625-udev-ensure-tag-parsing-stays-within-bounds.patch
|
||||
Patch0626: 0626-udev-fix-review-mixup.patch
|
||||
Patch0627: 0627-udev-scsi-id-check-for-invalid-chars-in-various-fiel.patch
|
||||
Patch0628: 0628-udev-builtin-net-id-print-cescaped-bad-attributes.patch
|
||||
Patch0629: 0629-core-only-activate-transaction-that-contain-useful-j.patch
|
||||
Patch0630: 0630-journald-extend-STDOUT_STREAMS_MAX-to-64k.patch
|
||||
Patch0631: 0631-string-util-introduce-strprepend-helper.patch
|
||||
Patch0632: 0632-missing-add-quotactl_fd-wrapper.patch
|
||||
Patch0633: 0633-homed-always-use-quotactl_fd-if-its-available.patch
|
||||
Patch0634: 0634-pid1-add-GracefulOptions-setting-to-.mount-units.patch
|
||||
Patch0635: 0635-pid1-enable-usrquota-support-on-dev-shm.patch
|
||||
Patch0636: 0636-units-enable-usrquota-support-on-tmp.patch
|
||||
Patch0637: 0637-nspawn-enable-usrquota-support-on-tmp-and-dev-shm.patch
|
||||
Patch0638: 0638-nspawn-downgrade-log-message-about-usrquota-to-debug.patch
|
||||
Patch0639: 0639-mount-setup-drop-outdated-comment.patch
|
||||
Patch0640: 0640-mount-setup-tune-down-log-level-if-usrquota-is-not-s.patch
|
||||
Patch0641: 0641-devnum-util-add-macros-to-safely-convert-dev_t-to-po.patch
|
||||
Patch0642: 0642-user-record-add-fields-for-setting-limits-on-tmp-and.patch
|
||||
Patch0643: 0643-user-runtime-dir-some-smaller-modernizations-refacto.patch
|
||||
Patch0644: 0644-user-runtime-dir-enforce-tmp-and-dev-shm-quota.patch
|
||||
Patch0645: 0645-homectl-add-support-for-configuring-tmpfs-limits.patch
|
||||
Patch0646: 0646-test-add-test-case-for-tmpfs-quota-logic-PAMName-ask.patch
|
||||
Patch0647: 0647-update-TODO.patch
|
||||
Patch0648: 0648-core-dbus-service-fix-alignment.patch
|
||||
Patch0649: 0649-core-mount-filter-out-fail-option-as-well.patch
|
||||
Patch0650: 0650-core-mount-check-parameters_fragment-first-in-mount_.patch
|
||||
Patch0651: 0651-core-mount-report-accurate-can_start-and-can_reload.patch
|
||||
Patch0652: 0652-core-mount-trivial-coding-style-cleanups.patch
|
||||
Patch0653: 0653-core-dbus-mount-add-missing-ReloadResult-and-CleanRe.patch
|
||||
Patch0654: 0654-bus-unit-util-add-missing-assertions.patch
|
||||
Patch0655: 0655-core-mount-rework-GracefulOptions-to-be-just-x-syste.patch
|
||||
Patch0656: 0656-mountpoint-util-assume-fsopen-works-in-mount_option_.patch
|
||||
Patch0657: 0657-core-mount-log-only-once-about-fs-not-supporting-new.patch
|
||||
Patch0658: 0658-user-runtime-dir-correct-quota-size-calculation.patch
|
||||
Patch0659: 0659-test-display-quota-add-a-little-helper-binary-to-sho.patch
|
||||
Patch0660: 0660-TEST-46-HOMED-check-for-support-on-dev-shm-and-tmp-s.patch
|
||||
Patch0661: 0661-TEST-46-HOMED-conditionally-skip-usrquota-tests.patch
|
||||
|
||||
# Downstream-only patches (9000–9999)
|
||||
%endif
|
||||
@ -1670,6 +1722,60 @@ rm -f .file-list-*
|
||||
rm -f %{name}.lang
|
||||
|
||||
%changelog
|
||||
* Thu Apr 16 2026 systemd maintenance team <systemd-maint@redhat.com> - 257-24
|
||||
- ci: re-enable bpf-framework option for build and unit test jobs (RHEL-155454)
|
||||
- ci: add bpftool workaround to codeql job too (RHEL-155454)
|
||||
- ci: fix workaround about bpftool for codeql (RHEL-155454)
|
||||
- ci: add bpftool workaround to coverity too (RHEL-155454)
|
||||
- Revert "man: mention RHEL documentation in systemctl's man page" (RHEL-155805)
|
||||
- path-util: add flavour of path_startswith() that leaves a leading slash in place (RHEL-155396)
|
||||
- cgroup: port some code over to path_startswith_full() (RHEL-155396)
|
||||
- path-util: invert PATH_STARTSWITH_ACCEPT_DOT_DOT flag (RHEL-155396)
|
||||
- sd-json: fix off-by-one issue when updating parent for array elements (RHEL-155396)
|
||||
- core/cgroup: avoid one unnecessary strjoina() (RHEL-155396)
|
||||
- core: validate input cgroup path more prudently (RHEL-155396)
|
||||
- nspawn: apply BindUser/Ephemeral from settings file only if trusted (RHEL-158303)
|
||||
- nspawn: normalize pivot_root paths (RHEL-158303)
|
||||
- udev: check for invalid chars in various fields received from the kernel (RHEL-158354)
|
||||
- udev: ensure there is space for trailing NUL before calling sprintf (RHEL-158354)
|
||||
- udev: ensure tag parsing stays within bounds (RHEL-158354)
|
||||
- udev: fix review mixup (RHEL-158354)
|
||||
- udev/scsi-id: check for invalid chars in various fields received from the kernel (RHEL-158354)
|
||||
- udev-builtin-net-id: print cescaped bad attributes (RHEL-158354)
|
||||
- core: only activate transaction that contain useful jobs (RHEL-143728)
|
||||
- journald: extend STDOUT_STREAMS_MAX to 64k (RHEL-168098)
|
||||
- string-util: introduce strprepend() helper (RHEL-143028)
|
||||
- missing: add quotactl_fd() wrapper (RHEL-143028)
|
||||
- homed: always use quotactl_fd() if its available (RHEL-143028)
|
||||
- pid1: add GracefulOptions= setting to .mount units (RHEL-143028)
|
||||
- pid1: enable usrquota support on /dev/shm (RHEL-143028)
|
||||
- units: enable usrquota support on /tmp/ (RHEL-143028)
|
||||
- nspawn: enable usrquota support on /tmp/ and /dev/shm/ (RHEL-143028)
|
||||
- nspawn: downgrade log message about usrquota to debug (RHEL-143028)
|
||||
- mount-setup: drop outdated comment (RHEL-143028)
|
||||
- mount-setup: tune down log level if usrquota is not supported, apply usrquota when smack is in use too (RHEL-143028)
|
||||
- devnum-util: add macros to safely convert dev_t to pointers and back (RHEL-143028)
|
||||
- user-record: add fields for setting limits on /tmp/ and /dev/shm/ (RHEL-143028)
|
||||
- user-runtime-dir: some smaller modernizations/refactorings (RHEL-143028)
|
||||
- user-runtime-dir: enforce /tmp/ and /dev/shm/ quota (RHEL-143028)
|
||||
- homectl: add support for configuring tmpfs limits (RHEL-143028)
|
||||
- test: add test case for tmpfs quota logic + PAMName= ask-password logic (RHEL-143028)
|
||||
- update TODO (RHEL-143028)
|
||||
- core/dbus-service: fix alignment (RHEL-143028)
|
||||
- core/mount: filter out "fail" option as well (RHEL-143028)
|
||||
- core/mount: check parameters_fragment first in mount_enter_(re)mounting() (RHEL-143028)
|
||||
- core/mount: report accurate can_start and can_reload (RHEL-143028)
|
||||
- core/mount: trivial coding style cleanups (RHEL-143028)
|
||||
- core/dbus-mount: add missing ReloadResult and CleanResult properties (RHEL-143028)
|
||||
- bus-unit-util: add missing assertions (RHEL-143028)
|
||||
- core/mount: rework GracefulOptions= to be just x-systemd.graceful-option= (RHEL-143028)
|
||||
- mountpoint-util: assume fsopen() works in mount_option_supported() (RHEL-143028)
|
||||
- core/mount: log only once about fs not supporting new mount API (RHEL-143028)
|
||||
- user-runtime-dir: correct quota size calculation (RHEL-143028)
|
||||
- test-display-quota: add a little helper binary to show quota on tmpfs (RHEL-143028)
|
||||
- TEST-46-HOMED: check for support on /dev/shm and /tmp separately (RHEL-143028)
|
||||
- TEST-46-HOMED: conditionally skip usrquota tests (RHEL-143028)
|
||||
|
||||
* Tue Feb 17 2026 systemd maintenance team <systemd-maint@redhat.com> - 257-23
|
||||
- test-journal-dump: dump the headers of journal files (RHEL-106795)
|
||||
- journal: store counts, not byte sizes, in table size constants (RHEL-106795)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user