From 8953fc07c0498d1ddd9a04dc549ffb85862f4c5f Mon Sep 17 00:00:00 2001 From: "\\\"Ken'ichi Ohmichi\\" Date: Fri, 8 May 2009 01:46:02 +0530 Subject: Changelog v2: * Use clock_gettime(2) for getting timestamp since a system boot. * Change parent_info's memory to dynamic allocation. This patch is for changing the cgroup of a forked process while parent changing. This patch adds the following sequence: 1. Store both the timestamp and the process-id when changing the cgroup. 2. If receiving a PROC_EVENT_FORK packet, check its parent-pid and its timestamp. 3. If its parent-pid and the stored process-id are same and its timestamp is older than the stored timestamp, change the cgroup of forked process. Thanks Ken'ichi Ohmichi Signed-off-by: Ken'ichi Ohmichi Signed-off-by: Balbir Singh --- src/daemon/Makefile.am | 2 +- src/daemon/cgrulesengd.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index 17d31d9..f0c9b92 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -2,5 +2,5 @@ INCLUDES = -I $(top_srcdir)/include sbin_PROGRAMS = cgrulesengd cgrulesengd_SOURCES = cgrulesengd.c cgrulesengd.h -cgrulesengd_LDADD = $(top_srcdir)/src/.libs/libcgroup.la +cgrulesengd_LDADD = $(top_srcdir)/src/.libs/libcgroup.la -lrt cgrulesengd_LDFLAGS = -L$(top_srcdir)/src/.libs diff --git a/src/daemon/cgrulesengd.c b/src/daemon/cgrulesengd.c index 74d12e1..07d4a5d 100644 --- a/src/daemon/cgrulesengd.c +++ b/src/daemon/cgrulesengd.c @@ -180,6 +180,91 @@ static int cgre_get_euid_egid_from_status(pid_t pid, uid_t *euid, gid_t *egid) return 0; } +struct parent_info { + __u64 timestamp; + pid_t pid; +}; +struct array_parent_info { + int index; + int num_allocation; + struct parent_info **parent_info; +}; +struct array_parent_info array_pi; + +static int cgre_store_parent_info(pid_t pid) +{ + __u64 uptime_ns; + struct timespec tp; + struct parent_info *info; + + if (clock_gettime(CLOCK_MONOTONIC, &tp) < 0) { + flog(LOG_WARNING, "Failed to get time"); + return 1; + } + uptime_ns = ((__u64)tp.tv_sec * 1000 * 1000 * 1000 ) + tp.tv_nsec; + + if (array_pi.index >= array_pi.num_allocation) { + array_pi.num_allocation += 100; + array_pi.parent_info = realloc(array_pi.parent_info, + sizeof(info) * array_pi.num_allocation); + if (!array_pi.parent_info) { + flog(LOG_WARNING, "Failed to allocate memory"); + return 1; + } + } + info = calloc(1, sizeof(struct parent_info)); + if (!info) { + flog(LOG_WARNING, "Failed to allocate memory"); + return 1; + } + info->timestamp = uptime_ns; + info->pid = pid; + + array_pi.parent_info[array_pi.index] = info; + array_pi.index++; + + return 0; +} + +static void cgre_remove_old_parent_info(__u64 key_timestamp) +{ + int i, j; + + for (i = 0; i < array_pi.index; i++) { + if (key_timestamp < array_pi.parent_info[i]->timestamp) + continue; + free(array_pi.parent_info[i]); + for (j = i; j < array_pi.index - 1; j++) + array_pi.parent_info[j] = array_pi.parent_info[j + 1]; + array_pi.index--; + i--; + } + return; +} + +static int cgre_was_parent_changed_when_forking(const struct proc_event *ev) +{ + int i; + pid_t parent_pid; + __u64 timestamp_child; + __u64 timestamp_parent; + + parent_pid = ev->event_data.fork.parent_pid; + timestamp_child = ev->timestamp_ns; + + cgre_remove_old_parent_info(timestamp_child); + + for (i = 0; i < array_pi.index; i++) { + if (parent_pid != array_pi.parent_info[i]->pid) + continue; + timestamp_parent = array_pi.parent_info[i]->timestamp; + if (timestamp_child > timestamp_parent) + continue; + return 1; + } + return 0; +} + /** * Process an event from the kernel, and determine the correct UID/GID/PID to * pass to libcgroup. Then, libcgroup will decide the cgroup to move the PID @@ -201,6 +286,15 @@ int cgre_process_event(const struct proc_event *ev, const int type) case PROC_EVENT_GID: pid = ev->event_data.id.process_pid; break; + case PROC_EVENT_FORK: + /* + * If this process was forked while changing parent's cgroup, + * this process's cgroup also should be changed. + */ + if (!cgre_was_parent_changed_when_forking(ev)) + return 0; + pid = ev->event_data.fork.child_pid; + break; default: break; } @@ -229,6 +323,12 @@ int cgre_process_event(const struct proc_event *ev, const int type) ev->event_data.id.e.egid, pid, CGFLAG_USECACHE); break; + case PROC_EVENT_FORK: + log_uid = euid; + log_gid = egid; + ret = cgroup_change_cgroup_uid_gid_flags(euid, + egid, pid, CGFLAG_USECACHE); + break; default: break; } @@ -242,6 +342,7 @@ int cgre_process_event(const struct proc_event *ev, const int type) " FAILED! (Error Code: %d)", log_pid, log_uid, log_gid, ret); } else { + ret = cgre_store_parent_info(pid); flog(LOG_INFO, "Cgroup change for PID: %d, UID: %d, GID: %d OK", log_pid, log_uid, log_gid); } @@ -282,6 +383,9 @@ int cgre_handle_msg(struct cn_msg *cn_hdr) ev->event_data.id.e.egid); ret = cgre_process_event(ev, PROC_EVENT_GID); break; + case PROC_EVENT_FORK: + ret = cgre_process_event(ev, PROC_EVENT_FORK); + break; default: break; } -- cgit