backport several upstream fixes

set Delegate property for cgconfig service to make sure complete cgroup hierarchy is always created by systemd
This commit is contained in:
Nikola Forró 2018-04-17 13:42:19 +02:00
parent 4220b6fe81
commit 871fc3e5db
8 changed files with 399 additions and 1 deletions

View File

@ -10,6 +10,7 @@ Before=basic.target shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
Delegate=yes
ExecStart=/usr/sbin/cgconfigparser -l /etc/cgconfig.conf -s 1664
ExecStop=/usr/sbin/cgclear -l /etc/cgconfig.conf -e

View File

@ -0,0 +1,63 @@
From 647274d80d18686a3129a2b50605869ac5178ccf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Forr=C3=B3?= <nforro@redhat.com>
Date: Tue, 8 Dec 2015 17:09:08 +0100
Subject: [PATCH 1/6] api.c: change cgroup of every thread of a process
When changing cgroup of multi-threaded process, only the main threads
cgroup actually changed. Now all threads of a process are enumerated
and cgroup is changed for each of them.
---
src/api.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/src/api.c b/src/api.c
index 0cc15c6..df90a6f 100644
--- a/src/api.c
+++ b/src/api.c
@@ -3177,10 +3177,13 @@ int cgroup_change_all_cgroups(void)
return -ECGOTHER;
while ((pid_dir = readdir(dir)) != NULL) {
- int err, pid;
+ int err, pid, tid;
uid_t euid;
gid_t egid;
char *procname = NULL;
+ DIR *tdir;
+ struct dirent *tid_dir = NULL;
+ char tpath[FILENAME_MAX] = { '\0' };
err = sscanf(pid_dir->d_name, "%i", &pid);
if (err < 1)
@@ -3194,11 +3197,24 @@ int cgroup_change_all_cgroups(void)
if (err)
continue;
- err = cgroup_change_cgroup_flags(euid,
- egid, procname, pid, CGFLAG_USECACHE);
- if (err)
- cgroup_dbg("cgroup change pid %i failed\n", pid);
+ snprintf(tpath, FILENAME_MAX, "%s%d/task/", path, pid);
+
+ tdir = opendir(tpath);
+ if (!tdir)
+ continue;
+
+ while ((tid_dir = readdir(tdir)) != NULL) {
+ err = sscanf(tid_dir->d_name, "%i", &tid);
+ if (err < 1)
+ continue;
+
+ err = cgroup_change_cgroup_flags(euid,
+ egid, procname, tid, CGFLAG_USECACHE);
+ if (err)
+ cgroup_dbg("cgroup change tid %i failed\n", tid);
+ }
+ closedir(tdir);
free(procname);
}
--
2.17.0

View File

@ -0,0 +1,40 @@
From 62bab9d121d4fb416205f5ac53ad342184ae42b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Forr=C3=B3?= <nforro@redhat.com>
Date: Tue, 8 Dec 2015 16:53:41 +0100
Subject: [PATCH 2/6] api.c: fix infinite loop
If getgrnam or getpwuid functions failed, the program entered
an infinite loop, because the rule pointer was never advanced.
This is now fixed by updating the pointer before continuing
to the next iteration.
---
src/api.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/api.c b/src/api.c
index df90a6f..217d6c9 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2664,13 +2664,17 @@ static struct cgroup_rule *cgroup_find_matching_rule_uid_gid(uid_t uid,
/* Get the group data. */
sp = &(rule->username[1]);
grp = getgrnam(sp);
- if (!grp)
+ if (!grp) {
+ rule = rule->next;
continue;
+ }
/* Get the data for UID. */
usr = getpwuid(uid);
- if (!usr)
+ if (!usr) {
+ rule = rule->next;
continue;
+ }
/* If UID is a member of group, we matched. */
for (i = 0; grp->gr_mem[i]; i++) {
--
2.17.0

View File

@ -0,0 +1,38 @@
From 7c99c167f41d3f8810808436d2ac58afc3a7d6c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Forr=C3=B3?= <nforro@redhat.com>
Date: Tue, 17 Apr 2018 13:33:03 +0200
Subject: [PATCH 5/6] api.c: Fix level of failed user/group lookup warnings
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Nikola Forró <nforro@redhat.com>
---
src/api.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/api.c b/src/api.c
index 51081b4..efde2d1 100644
--- a/src/api.c
+++ b/src/api.c
@@ -639,7 +639,7 @@ static int cgroup_parse_rules(bool cache, uid_t muid,
uid = CGRULE_INVALID;
gid = grp->gr_gid;
} else {
- cgroup_dbg("Warning: Entry for %s not"
+ cgroup_warn("Warning: Entry for %s not"
"found. Skipping rule on line"
" %d.\n", itr, linenum);
skipped = true;
@@ -656,7 +656,7 @@ static int cgroup_parse_rules(bool cache, uid_t muid,
uid = pwd->pw_uid;
gid = CGRULE_INVALID;
} else {
- cgroup_dbg("Warning: Entry for %s not"
+ cgroup_warn("Warning: Entry for %s not"
"found. Skipping rule on line"
" %d.\n", user, linenum);
skipped = true;
--
2.17.0

View File

@ -0,0 +1,46 @@
From 9c80e2cb4bca26993a12027c46a274bb43645630 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Forr=C3=B3?= <nforro@redhat.com>
Date: Wed, 22 Jun 2016 14:12:46 +0200
Subject: [PATCH 3/6] api.c: fix potential buffer overflow
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It is assumed that arguments read from /proc/<pid>/cmdline don't exceed
buf_pname buffer size, which is FILENAME_MAX - 1 characters, but that's
not always the case.
Add check to prevent buffer overflow and discard the excessive part of
an argument.
Signed-off-by: Nikola Forró <nforro@redhat.com>
---
src/api.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/api.c b/src/api.c
index 217d6c9..4d98081 100644
--- a/src/api.c
+++ b/src/api.c
@@ -4065,13 +4065,17 @@ static int cg_get_procname_from_proc_cmdline(pid_t pid,
while (c != EOF) {
c = fgetc(f);
- if ((c != EOF) && (c != '\0')) {
+ if ((c != EOF) && (c != '\0') && (len < FILENAME_MAX - 1)) {
buf_pname[len] = c;
len++;
continue;
}
buf_pname[len] = '\0';
+ if (len == FILENAME_MAX - 1)
+ while ((c != EOF) && (c != '\0'))
+ c = fgetc(f);
+
/*
* The taken process name from /proc/<pid>/status is
* shortened to 15 characters if it is over. So the
--
2.17.0

View File

@ -0,0 +1,142 @@
From 5a64a79144e58a62426a34ef51b14e891f042fa2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Forr=C3=B3?= <nforro@redhat.com>
Date: Tue, 17 Apr 2018 13:54:38 +0200
Subject: [PATCH 6/6] Increase maximal size of controller values
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Maximal length of a controller value is determined by CG_VALUE_MAX,
which is equal to 100. That is not sufficient in some cases.
Add new constant CG_CONTROL_VALUE_MAX (to prevent breaking current API)
and set it to 4096, which is usually equal to the amount of bytes that
can be written to a sysctl file directly.
Add warning message about exceeding the limit while parsing
configuration file.
Signed-off-by: Nikola Forró <nforro@redhat.com>
---
src/api.c | 6 +++---
src/libcgroup-internal.h | 5 ++++-
src/tools/cgset.c | 4 ++--
src/wrapper.c | 17 ++++++++++++-----
4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/src/api.c b/src/api.c
index efde2d1..1cd30df 100644
--- a/src/api.c
+++ b/src/api.c
@@ -1561,7 +1561,7 @@ static int cgroup_copy_controller_values(struct cgroup_controller *dst,
}
dst_val = dst->values[i];
- strncpy(dst_val->value, src_val->value, CG_VALUE_MAX);
+ strncpy(dst_val->value, src_val->value, CG_CONTROL_VALUE_MAX);
strncpy(dst_val->name, src_val->name, FILENAME_MAX);
dst_val->dirty = src_val->dirty;
}
@@ -2286,7 +2286,7 @@ static int cg_rd_ctrl_file(const char *subsys, const char *cgroup,
if (ctrl_file < 0)
return ECGROUPVALUENOTEXIST;
- *value = calloc(CG_VALUE_MAX, 1);
+ *value = calloc(CG_CONTROL_VALUE_MAX, 1);
if (!*value) {
close(ctrl_file);
last_errno = errno;
@@ -2297,7 +2297,7 @@ static int cg_rd_ctrl_file(const char *subsys, const char *cgroup,
* using %as or fread crashes when we try to read from files like
* memory.stat
*/
- ret = read(ctrl_file, *value, CG_VALUE_MAX-1);
+ ret = read(ctrl_file, *value, CG_CONTROL_VALUE_MAX-1);
if (ret < 0) {
free(*value);
*value = NULL;
diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h
index 4c0f46c..3a8e336 100644
--- a/src/libcgroup-internal.h
+++ b/src/libcgroup-internal.h
@@ -32,6 +32,9 @@ __BEGIN_DECLS
/* Estimated number of groups created */
#define MAX_GROUP_ELEMENTS 128
+/* Maximum length of a value */
+#define CG_CONTROL_VALUE_MAX 4096
+
#define CG_NV_MAX 100
#define CG_CONTROLLER_MAX 100
/* Max number of mounted hierarchies. Event if one controller is mounted per
@@ -73,7 +76,7 @@ __BEGIN_DECLS
struct control_value {
char name[FILENAME_MAX];
- char value[CG_VALUE_MAX];
+ char value[CG_CONTROL_VALUE_MAX];
bool dirty;
};
diff --git a/src/tools/cgset.c b/src/tools/cgset.c
index ea9f90d..3d3c8cc 100644
--- a/src/tools/cgset.c
+++ b/src/tools/cgset.c
@@ -151,8 +151,8 @@ int main(int argc, char *argv[])
goto err;
}
- strncpy(name_value[nv_number].value, buf, CG_VALUE_MAX);
- name_value[nv_number].value[CG_VALUE_MAX-1] = '\0';
+ strncpy(name_value[nv_number].value, buf, CG_CONTROL_VALUE_MAX);
+ name_value[nv_number].value[CG_CONTROL_VALUE_MAX-1] = '\0';
nv_number++;
break;
diff --git a/src/wrapper.c b/src/wrapper.c
index c03472a..0952823 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -132,10 +132,10 @@ int cgroup_add_value_string(struct cgroup_controller *controller,
if (!controller)
return ECGINVAL;
- if (controller->index >= CG_VALUE_MAX)
+ if (controller->index >= CG_NV_MAX)
return ECGMAXVALUESEXCEEDED;
- for (i = 0; i < controller->index && i < CG_VALUE_MAX; i++) {
+ for (i = 0; i < controller->index && i < CG_NV_MAX; i++) {
if (!strcmp(controller->values[i]->name, name))
return ECGVALUEEXISTS;
}
@@ -145,8 +145,15 @@ int cgroup_add_value_string(struct cgroup_controller *controller,
if (!cntl_value)
return ECGCONTROLLERCREATEFAILED;
- strncpy(cntl_value->name, name, sizeof(cntl_value->name));
- strncpy(cntl_value->value, value, sizeof(cntl_value->value));
+ if (strlen(value) >= sizeof(cntl_value->value)) {
+ fprintf(stderr, "value exceeds the maximum of %d characters\n",
+ sizeof(cntl_value->value));
+ free(cntl_value);
+ return ECGCONFIGPARSEFAIL;
+ }
+
+ strncpy(cntl_value->name, name, sizeof(cntl_value->name) - 1);
+ strncpy(cntl_value->value, value, sizeof(cntl_value->value) - 1);
cntl_value->dirty = true;
controller->values[controller->index] = cntl_value;
controller->index++;
@@ -356,7 +363,7 @@ int cgroup_set_value_string(struct cgroup_controller *controller,
for (i = 0; i < controller->index; i++) {
struct control_value *val = controller->values[i];
if (!strcmp(val->name, name)) {
- strncpy(val->value, value, CG_VALUE_MAX);
+ strncpy(val->value, value, CG_CONTROL_VALUE_MAX - 1);
val->dirty = true;
return 0;
}
--
2.17.0

View File

@ -0,0 +1,49 @@
From 437b68f34c459d136c806e61dafb5825d2f97170 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Forr=C3=B3?= <nforro@redhat.com>
Date: Tue, 17 Apr 2018 13:32:28 +0200
Subject: [PATCH 4/6] api.c: Show warning when tasks file can not be opened
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Nikola Forró <nforro@redhat.com>
---
src/api.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/api.c b/src/api.c
index 4d98081..51081b4 100644
--- a/src/api.c
+++ b/src/api.c
@@ -1190,12 +1190,15 @@ static int __cgroup_attach_task_pid(char *path, pid_t tid)
if (!tasks) {
switch (errno) {
case EPERM:
- return ECGROUPNOTOWNER;
+ ret = ECGROUPNOTOWNER;
+ break;
case ENOENT:
- return ECGROUPNOTEXIST;
+ ret = ECGROUPNOTEXIST;
+ break;
default:
- return ECGROUPNOTALLOWED;
+ ret = ECGROUPNOTALLOWED;
}
+ goto err;
}
ret = fprintf(tasks, "%d", tid);
if (ret < 0) {
@@ -1214,7 +1217,8 @@ static int __cgroup_attach_task_pid(char *path, pid_t tid)
err:
cgroup_warn("Warning: cannot write tid %d to %s:%s\n",
tid, path, strerror(errno));
- fclose(tasks);
+ if (tasks)
+ fclose(tasks);
return ret;
}
--
2.17.0

View File

@ -5,7 +5,7 @@
Summary: Library to control and monitor control groups
Name: libcgroup
Version: 0.41
Release: 16%{?dist}
Release: 17%{?dist}
License: LGPLv2+
Group: Development/Libraries
URL: http://libcg.sourceforge.net/
@ -23,6 +23,12 @@ Patch6: libcgroup-0.41-api.c-support-for-setting-multiline-values-in-contro.patc
Patch7: libcgroup-0.41-api.c-fix-order-of-memory-subsystem-parameters.patch
# resolves #1384504
Patch8: libcgroup-0.41-api.c-preserve-dirty-flag.patch
Patch9: libcgroup-0.41-change-cgroup-of-threads.patch
Patch10: libcgroup-0.41-fix-infinite-loop.patch
Patch11: libcgroup-0.41-prevent-buffer-overflow.patch
Patch12: libcgroup-0.41-tasks-file-warning.patch
Patch13: libcgroup-0.41-fix-log-level.patch
Patch14: libcgroup-0.41-size-of-controller-values.patch
BuildRequires: gcc, gcc-c++
BuildRequires: byacc, coreutils, flex, pam-devel, systemd-units
@ -39,6 +45,8 @@ administrate and monitor control groups and the associated controllers.
Summary: Command-line utility programs, services and daemons for libcgroup
Group: System Environment/Base
Requires: %{name}%{?_isa} = %{version}-%{release}
# needed for Delegate property in cgconfig.service
Requires: systemd >= 217-0.2
%description tools
This package contains command-line programs, services and a daemon for
@ -74,6 +82,12 @@ provide scripts to manage that configuration.
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%build
%configure --enable-pam-module-dir=%{_libdir}/security \
@ -174,6 +188,11 @@ getent group cgred >/dev/null || groupadd -r cgred
%{_libdir}/pkgconfig/libcgroup.pc
%changelog
* Tue Apr 17 2018 Nikola Forró <nforro@redhat.com> - 0.41-17
- backport several upstream fixes
- set Delegate property for cgconfig service to make sure complete
cgroup hierarchy is always created by systemd
* Tue Feb 20 2018 Nikola Forró <nforro@redhat.com> - 0.41-16
- add missing gcc-c++ build dependency