]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
cgrules: add support for process/dest cgroups with spaces
authorKamalesh Babulal <kamalesh.babulal@oracle.com>
Tue, 21 Jan 2025 08:10:27 +0000 (13:40 +0530)
committerTom Hromatka <tom.hromatka@oracle.com>
Thu, 13 Feb 2025 16:00:52 +0000 (09:00 -0700)
In a cgrules rule, allow the process names and the destination
cgroups with spaces and other allowed special characters.

Reported-by: @LinuxOnTheDesktop (github username)
Fixes: https://github.com/libcgroup/libcgroup/issues/462
Signed-off-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
TJH: slight logic changes and add gunit support

src/api.c
src/libcgroup-internal.h

index 6df516fa19d6bce6a16fbcb886e00f6eb7d32932..7ff095e72466b4ac194a7da6bd774f9607178f65 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -554,6 +554,71 @@ STATIC int cgroup_parse_rules_options(char *options, struct cgroup_rule * const
 
        return ret;
 }
+
+STATIC int get_next_rule_field(char *rule, char *field, size_t field_len, bool expect_quotes)
+{
+       char *quote_start = NULL, *quote_end = NULL;
+       char *tmp, *_rule = rule;
+       int len = 0;
+
+       if (!rule || !field)
+               return ECGINVAL;
+
+       /* trim the leading whitespace */
+       while (*rule == ' ' || *rule == '\t')
+               rule++;
+
+       tmp = rule;
+
+       while (*rule != ' ' && *rule != '\t' && *rule != '\n' && *rule != '\0') {
+               if (*rule == '"') {
+                       quote_start = rule;
+                       rule++;
+                       break;
+               }
+               rule++;
+       }
+
+       if (quote_start) {
+               if (!expect_quotes)
+                       return ECGINVAL;
+
+               while (*rule != '"' && *rule != '\n' && *rule != '\0')
+                       rule++;
+
+               /* there should be a ending quote */
+               if (*rule != '"')
+                       return ECGINVAL;
+
+               quote_end = rule;
+       }
+
+       if (quote_end) {
+               /* copy until the ending quotes */
+               len = quote_end - quote_start - 1;
+               if (len >= field_len)
+                       return ECGINVAL;
+
+               strncpy(field, quote_start + 1, len);
+               field[len] = '\0';
+       } else {
+               len = rule - tmp;
+               if (len >= field_len)
+                       return ECGINVAL;
+
+               strncpy(field, tmp, len);
+               field[len] = '\0';
+       }
+
+       len = (rule - _rule);
+
+       /* count until the ending quotes */
+       if (quote_start)
+               len += 1;
+
+       return len;
+}
+
 /**
  * Parse the configuration file that maps UID/GIDs to cgroups.  If ever the
  * configuration file is modified, applications should call this function to
@@ -677,15 +742,33 @@ static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid, gid_t
                 * there's an error in the configuration file.
                 */
                skipped = false;
-               i = sscanf(itr, "%s%s%s%s", key, controllers, destination, options);
-               if (i < 3) {
+
+               ret = get_next_rule_field(itr, key, CGRP_RULE_MAXKEY, true);
+               if (!ret) {
+                       cgroup_err("failed to parse configuration file on line %d\n", linenum);
+                       goto parsefail;
+               }
+
+               itr += ret;
+               ret = get_next_rule_field(itr, controllers, CG_CONTROLLER_MAX, false);
+               if (!ret) {
+                       cgroup_err("failed to parse configuration file on line %d\n", linenum);
+                       goto parsefail;
+               }
+
+               itr += ret;
+               ret = get_next_rule_field(itr, destination, FILENAME_MAX, true);
+               if (!ret) {
                        cgroup_err("failed to parse configuration file on line %d\n", linenum);
                        goto parsefail;
-               } else if (i == 3) {
+               }
+
+               itr += ret;
+               ret = get_next_rule_field(itr, options, CG_OPTIONS_MAX, false);
+               if (!ret)
                        has_options = false;
-               } else if (i == 4) {
+               else
                        has_options = true;
-               }
 
                procname = strchr(key, ':');
                if (procname) {
index 48dbf1c08a0093df9a0143daea71c2f70fac7bc7..bb5c2213dd6e4b580f38b4495ad19d257adf9254 100644 (file)
@@ -423,6 +423,7 @@ int cgroup_chown_chmod_tasks(const char * const cg_path, uid_t uid, gid_t gid, m
 int cgroupv2_subtree_control(const char *path, const char *ctrl_name, bool enable);
 int cgroupv2_get_subtree_control(const char *path,  const char *ctrl_name, bool * const enabled);
 int cgroupv2_controller_enabled(const char * const cg_name, const char * const ctrl_name);
+int get_next_rule_field(char *rule, char *field, size_t field_len, bool expect_quotes);
 
 #endif /* UNIT_TEST */