summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>2009-06-26 14:49:50 +0900
committerDhaval Giani <dhaval@linux.vnet.ibm.com>2009-06-29 16:47:32 +0530
commit495c45c844522c29ee4d0a26942e894f1346c237 (patch)
tree68731c59dcce9488cb07e5e925174f264808c370
parentd297b6fc17d51b8c2f6cdc094ada378d49e9a583 (diff)
downloadlibcg-495c45c844522c29ee4d0a26942e894f1346c237.tar.gz
libcg-495c45c844522c29ee4d0a26942e894f1346c237.tar.xz
libcg-495c45c844522c29ee4d0a26942e894f1346c237.zip
Add the key "process name" to find a matching rule.
Hi, Changelog of v6: ================ * No change. Changelog of v5.1: ================== * BUGFIX: Clear the flags meaning "found a matching rule" when a process name does not match. There was a problem that cgexec and cgclassify didn't work correctly if a user executes cgexec/cgclassify based on /etc/cgrules.conf. For example, if a root user executes `cgclassify $$` on the following /etc/cgrules.conf, the process ($$) should be moved to users/root on cpuset and memory subsystems. But the process was moved to users/root/cp on memory subsystem only. Example of /etc/cgrules.conf: ============================= root:cp cpuset users/root/cp % memory users/root/cp root cpuset users/root % memory users/root The cause is why the flags meaning "found a matching rule" (uid, gid, and matched) is not cleared when a process name does not match. This problem is fixed on this patch. Changelog of v5: ================ * Rebase the patch to the latest code. Changelog of v4: ================ * No change. Changelog of v3: ================ * BUGFIX: Fix the handling of '%' in /etc/cgrules.conf. Changelog of v2: ================ * Use strcmp() instead of strncmp() for checking a process name strictly. * Some cleanups. Description: ============ This patch adds the key "process name" to find a matching rule. Thanks Ken'ichi Ohmichi Signed-off-by: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp> Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
-rw-r--r--include/libcgroup.h21
-rw-r--r--src/api.c154
-rw-r--r--src/libcgroup.map1
3 files changed, 117 insertions, 59 deletions
diff --git a/include/libcgroup.h b/include/libcgroup.h
index 6155f09..a9799ab 100644
--- a/include/libcgroup.h
+++ b/include/libcgroup.h
@@ -149,6 +149,27 @@ int cgroup_create_cgroup_from_parent(struct cgroup *cgroup, int ignore_ownership
int cgroup_copy_cgroup(struct cgroup *dst, struct cgroup *src);
/**
+ * Changes the cgroup of a program based on the rules in the config file.
+ * If a rule exists for the given UID, GID or PROCESS NAME, then the given
+ * PID is placed into the correct group. By default, this function parses
+ * the configuration file each time it is called.
+ *
+ * The flags can alter the behavior of this function:
+ * CGFLAG_USECACHE: Use cached rules instead of parsing the config file
+ *
+ * This function may NOT be thread safe.
+ * @param uid The UID to match
+ * @param gid The GID to match
+ * @param procname The PROCESS NAME to match
+ * @param pid The PID of the process to move
+ * @param flags Bit flags to change the behavior, as defined above
+ * @return 0 on success, > 0 on error
+ * TODO: Determine thread-safeness and fix of not safe.
+ */
+int cgroup_change_cgroup_flags(const uid_t uid, const gid_t gid,
+ char *procname, const pid_t pid, const int flags);
+
+/**
* Changes the cgroup of a program based on the rules in the config file. If a
* rule exists for the given UID or GID, then the given PID is placed into the
* correct group. By default, this function parses the configuration file each
diff --git a/src/api.c b/src/api.c
index c5a3579..92bdebd 100644
--- a/src/api.c
+++ b/src/api.c
@@ -294,7 +294,8 @@ static char *cg_skip_unused_charactors_in_rule(char *rule)
* @return 0 on success, -1 if no cache and match found, > 0 on error.
* TODO: Make this function thread safe!
*/
-static int cgroup_parse_rules(bool cache, uid_t muid, gid_t mgid)
+static int cgroup_parse_rules(bool cache, uid_t muid,
+ gid_t mgid, char *mprocname)
{
/* File descriptor for the configuration file */
FILE *fp = NULL;
@@ -486,8 +487,29 @@ static int cgroup_parse_rules(bool cache, uid_t muid, gid_t mgid)
matched = true;
}
- if (!cache && !matched)
- continue;
+ if (!cache) {
+ if (!matched)
+ continue;
+ if (len_procname) {
+ /*
+ * If there is a rule based on process name,
+ * it should be matched with mprocname.
+ */
+ if (!mprocname) {
+ uid = CGRULE_INVALID;
+ gid = CGRULE_INVALID;
+ matched = false;
+ continue;
+ }
+ if (strcmp(mprocname, procname) &&
+ strcmp(basename(mprocname), procname)) {
+ uid = CGRULE_INVALID;
+ gid = CGRULE_INVALID;
+ matched = false;
+ continue;
+ }
+ }
+ }
/*
* Now, we're either caching rules or we found a match. Either
@@ -1821,22 +1843,9 @@ static int cg_prepare_cgroup(struct cgroup *cgroup, pid_t pid,
return ret;
}
-/**
- * Finds the first rule in the cached list that matches the given UID or GID,
- * and returns a pointer to that rule. This function uses rl_lock.
- *
- * This function may NOT be thread safe.
- * @param uid The UID to match
- * @param gid The GID to match
- * @return Pointer to the first matching rule, or NULL if no match
- * TODO: Determine thread-safeness and fix if not safe.
- */
static struct cgroup_rule *cgroup_find_matching_rule_uid_gid(const uid_t uid,
- const gid_t gid)
+ const gid_t gid, struct cgroup_rule *rule)
{
- /* Return value */
- struct cgroup_rule *ret = rl.head;
-
/* Temporary user data */
struct passwd *usr = NULL;
@@ -1849,76 +1858,96 @@ static struct cgroup_rule *cgroup_find_matching_rule_uid_gid(const uid_t uid,
/* Loop variable */
int i = 0;
- pthread_rwlock_wrlock(&rl_lock);
- while (ret) {
- /* The wildcard rule always matches. */
- if ((ret->uid == CGRULE_WILD) && (ret->gid == CGRULE_WILD)) {
- goto finished;
+ while (rule) {
+ /* Skip "%" which indicates continuation of previous rule. */
+ if (rule->username[0] == '%') {
+ rule = rule->next;
+ continue;
}
+ /* The wildcard rule always matches. */
+ if ((rule->uid == CGRULE_WILD) && (rule->gid == CGRULE_WILD))
+ return rule;
/* This is the simple case of the UID matching. */
- if (ret->uid == uid) {
- goto finished;
- }
+ if (rule->uid == uid)
+ return rule;
/* This is the simple case of the GID matching. */
- if (ret->gid == gid) {
- goto finished;
- }
+ if (rule->gid == gid)
+ return rule;
/* If this is a group rule, the UID might be a member. */
- if (ret->username[0] == '@') {
+ if (rule->username[0] == '@') {
/* Get the group data. */
- sp = &(ret->username[1]);
+ sp = &(rule->username[1]);
grp = getgrnam(sp);
- if (!grp) {
+ if (!grp)
continue;
- }
/* Get the data for UID. */
usr = getpwuid(uid);
- if (!usr) {
+ if (!usr)
continue;
- }
/* If UID is a member of group, we matched. */
for (i = 0; grp->gr_mem[i]; i++) {
if (!(strcmp(usr->pw_name, grp->gr_mem[i])))
- goto finished;
+ return rule;
}
}
/* If we haven't matched, try the next rule. */
- ret = ret->next;
+ rule = rule->next;
}
/* If we get here, no rules matched. */
- ret = NULL;
-
-finished:
- pthread_rwlock_unlock(&rl_lock);
- return ret;
+ return NULL;
}
/**
- * Changes the cgroup of a program based on the rules in the config file. If a
- * rule exists for the given UID or GID, then the given PID is placed into the
- * correct group. By default, this function parses the configuration file each
- * time it is called.
- *
- * The flags can alter the behavior of this function:
- * CGFLAG_USECACHE: Use cached rules instead of parsing the config file
+ * Finds the first rule in the cached list that matches the given UID, GID
+ * or PROCESS NAME, and returns a pointer to that rule.
+ * This function uses rl_lock.
*
- * This function may NOT be thread safe.
+ * This function may NOT be thread safe.
* @param uid The UID to match
* @param gid The GID to match
- * @param pid The PID of the process to move
- * @param flags Bit flags to change the behavior, as defined above
- * @return 0 on success, > 0 on error
- * TODO: Determine thread-safeness and fix of not safe.
+ * @param procname The PROCESS NAME to match
+ * @return Pointer to the first matching rule, or NULL if no match
+ * TODO: Determine thread-safeness and fix if not safe.
*/
-int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
- const pid_t pid, const int flags)
+static struct cgroup_rule *cgroup_find_matching_rule(const uid_t uid,
+ const gid_t gid, char *procname)
+{
+ /* Return value */
+ struct cgroup_rule *ret = rl.head;
+
+ pthread_rwlock_wrlock(&rl_lock);
+ while (ret) {
+ ret = cgroup_find_matching_rule_uid_gid(uid, gid, ret);
+ if (!ret)
+ break;
+ if (!procname)
+ /* If procname is NULL, return a rule matching
+ * UID or GID */
+ break;
+ if (!ret->procname)
+ /* If no process name in a rule, that means wildcard */
+ break;
+ if (!strcmp(ret->procname, procname))
+ break;
+ if (!strcmp(ret->procname, basename(procname)))
+ /* Check a rule of basename. */
+ break;
+ ret = ret->next;
+ }
+ pthread_rwlock_unlock(&rl_lock);
+
+ return ret;
+}
+
+int cgroup_change_cgroup_flags(const uid_t uid, const gid_t gid,
+ char *procname, const pid_t pid, const int flags)
{
/* Temporary pointer to a rule */
struct cgroup_rule *tmp = NULL;
@@ -1940,7 +1969,7 @@ int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
*/
if (!(flags & CGFLAG_USECACHE)) {
cgroup_dbg("Not using cached rules for PID %d.\n", pid);
- ret = cgroup_parse_rules(false, uid, gid);
+ ret = cgroup_parse_rules(false, uid, gid, procname);
/* The configuration file has an error! We must exit now. */
if (ret != -1 && ret != 0) {
@@ -1960,7 +1989,7 @@ int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
tmp = trl.head;
} else {
/* Find the first matching rule in the cached list. */
- tmp = cgroup_find_matching_rule_uid_gid(uid, gid);
+ tmp = cgroup_find_matching_rule_uid_gid(uid, gid, procname);
if (!tmp) {
cgroup_dbg("No rule found to match PID: %d, UID: %d, "
"GID: %d\n", pid, uid, gid);
@@ -1994,6 +2023,12 @@ finished:
return ret;
}
+int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
+ const pid_t pid, const int flags)
+{
+ return cgroup_change_cgroup_flags(uid, gid, NULL, pid, flags);
+}
+
/**
* Provides backwards-compatibility with older versions of the API. This
* function is deprecated, and cgroup_change_cgroup_uid_gid_flags() should be
@@ -2107,7 +2142,8 @@ int cgroup_reload_cached_rules()
int ret = 0;
cgroup_dbg("Reloading cached rules from %s.\n", CGRULES_CONF_FILE);
- if ((ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID))) {
+ ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID, NULL);
+ if (ret) {
cgroup_dbg("Error parsing configuration file \"%s\": %d.\n",
CGRULES_CONF_FILE, ret);
ret = ECGROUPPARSEFAIL;
@@ -2132,7 +2168,7 @@ int cgroup_init_rules_cache()
int ret = 0;
/* Attempt to read the configuration file and cache the rules. */
- ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID);
+ ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID, NULL);
if (ret) {
cgroup_dbg("Could not initialize rule cache, error was: %d\n",
ret);
diff --git a/src/libcgroup.map b/src/libcgroup.map
index a101ca1..2935d48 100644
--- a/src/libcgroup.map
+++ b/src/libcgroup.map
@@ -71,4 +71,5 @@ global:
cgroup_get_uid_gid_from_procfs;
cgroup_get_subsys_mount_point;
cgroup_get_procname_from_procfs;
+ cgroup_change_cgroup_flags;
} CGROUP_0.33;