]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cgroup-util: Handle capsule@ paths like user@ paths 36664/head
authorMichal Koutný <mkoutny@suse.com>
Mon, 3 Feb 2025 13:44:20 +0000 (14:44 +0100)
committerMichal Koutný <mkoutny@suse.com>
Tue, 11 Mar 2025 09:37:19 +0000 (10:37 +0100)
The capsule instances are related to user instances, so treat them
equally to user@.service when handling cgroup paths. This also saves us
from polluting public libsystemd API with variant for capsules too.

Fix: #36098

src/basic/cgroup-util.c
src/test/test-cgroup-util.c

index 5cedd45f3d90567365e5ffceb4d8c2a8c1191da3..8067bc082bb97d1a0e59ed31d32922886f53baa4 100644 (file)
@@ -12,6 +12,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "capsule-util.h"
 #include "cgroup-util.h"
 #include "constants.h"
 #include "dirent-util.h"
@@ -1284,7 +1285,7 @@ static const char *skip_session(const char *p) {
 }
 
 /**
- * Skip user@*.service, but require it to be there.
+ * Skip user@*.service or capsule@*.service, but require either of them to be there.
  */
 static const char *skip_user_manager(const char *p) {
         size_t n;
@@ -1295,26 +1296,37 @@ static const char *skip_user_manager(const char *p) {
         p += strspn(p, "/");
 
         n = strcspn(p, "/");
-        if (n < STRLEN("user@x.service"))
+        if (n < CONST_MIN(STRLEN("user@x.service"), STRLEN("capsule@x.service")))
                 return NULL;
 
-        if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
-                char buf[n - 5 - 8 + 1];
+        /* Any possible errors from functions called below are converted to NULL return, so our callers won't
+         * resolve user/capsule name. */
+        _cleanup_free_ char *unit_name = strndup(p, n);
+        if (!unit_name)
+                return NULL;
 
-                memcpy(buf, p + 5, n - 5 - 8);
-                buf[n - 5 - 8] = 0;
+        _cleanup_free_ char *i = NULL;
+        UnitNameFlags type = unit_name_to_instance(unit_name, &i);
 
-                /* Note that user manager services never need unescaping,
-                 * since they cannot conflict with the kernel's own
-                 * names, hence we don't need to call cg_unescape()
-                 * here. */
+        if (type != UNIT_NAME_INSTANCE)
+                return NULL;
 
-                if (parse_uid(buf, NULL) < 0)
+        /* Note that user manager services never need unescaping, since they cannot conflict with the
+         * kernel's own names, hence we don't need to call cg_unescape() here.  Prudently check validity of
+         * instance names, they should be always valid as we validate them upon unit start. */
+        if (startswith(unit_name, "user@")) {
+                if (parse_uid(i, NULL) < 0)
                         return NULL;
 
                 p += n;
                 p += strspn(p, "/");
+                return p;
+        } else if (startswith(unit_name, "capsule@")) {
+                if (capsule_name_is_valid(i) <= 0)
+                        return NULL;
 
+                p += n;
+                p += strspn(p, "/");
                 return p;
         }
 
index 0170cb279bf915431b886d5761e70af34416cd19..3f91aa6a72da8ae33adc5356fe3b84f6efd499dc 100644 (file)
@@ -113,6 +113,9 @@ TEST(path_get_user_unit) {
         check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
         check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
         check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
+        check_p_g_u_u("/capsule.slice/capsule@test.service/app.slice/run-p9-i1.service", 0, "run-p9-i1.service");
+        check_p_g_u_u("/capsule.slice/capsule@usr-joe.service/foo.slice/foo-bar.slice/run-p9-i1.service", 0, "run-p9-i1.service");
+        check_p_g_u_u("/capsule.slice/capsule@#.service/foo.slice/foo-bar.slice/run-p9-i1.service", -ENXIO, NULL);
 }
 
 static void check_p_g_s(const char *path, int code, const char *result) {
@@ -157,6 +160,7 @@ TEST(path_get_slice) {
         check_p_g_slice("foobar", 0, SPECIAL_ROOT_SLICE);
         check_p_g_slice("foobar.slice", 0, "foobar.slice");
         check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice");
+        check_p_g_slice("/capsule.slice/capsule@test.service/app.slice/run-p9-i1.service", 0, "capsule.slice");
 }
 
 static void check_p_g_u_slice(const char *path, int code, const char *result) {
@@ -181,6 +185,10 @@ TEST(path_get_user_slice) {
         check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/waldo.service", 0, SPECIAL_ROOT_SLICE);
         check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/piep.slice/foo.service", 0, "piep.slice");
         check_p_g_u_slice("/foo.slice//foo-bar.slice/user@1000.service/piep.slice//piep-pap.slice//foo.service", 0, "piep-pap.slice");
+
+        check_p_g_u_slice("/capsule.slice/capsule@test.service/app.slice/run-p9-i1.service", 0, "app.slice");
+        check_p_g_u_slice("/capsule.slice/capsule@usr-joe.service/app.slice/run-p9-i1.service", 0, "app.slice");
+        check_p_g_u_slice("/capsule.slice/capsule@usr-joe.service/foo.slice/foo-bar.slice/run-p9-i1.service", 0, "foo-bar.slice");
 }
 
 TEST(get_paths, .sd_booted = true) {