Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d8e0bf5 authored by Li Zefan's avatar Li Zefan Committed by Tejun Heo
Browse files

cgroup: avoid accessing modular cgroup subsys structure without locking



subsys[i] is set to NULL in cgroup_unload_subsys() at modular unload,
and that's protected by cgroup_mutex, and then the memory *subsys[i]
resides will be freed.

So this is unsafe without any locking:

  if (!ss || ss->module)
  ...

v2:
- add a comment for enum cgroup_subsys_id
- simplify the comment in cgroup_exit()

Signed-off-by: default avatarLi Zefan <lizefan@huawei.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent f50daa70
Loading
Loading
Loading
Loading
+14 −3
Original line number Original line Diff line number Diff line
@@ -44,14 +44,25 @@ extern void cgroup_unload_subsys(struct cgroup_subsys *ss);


extern const struct file_operations proc_cgroup_operations;
extern const struct file_operations proc_cgroup_operations;


/* Define the enumeration of all builtin cgroup subsystems */
/*
 * Define the enumeration of all cgroup subsystems.
 *
 * We define ids for builtin subsystems and then modular ones.
 */
#define SUBSYS(_x) _x ## _subsys_id,
#define SUBSYS(_x) _x ## _subsys_id,
#define IS_SUBSYS_ENABLED(option) IS_ENABLED(option)
enum cgroup_subsys_id {
enum cgroup_subsys_id {
#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
#include <linux/cgroup_subsys.h>
#undef IS_SUBSYS_ENABLED
	CGROUP_BUILTIN_SUBSYS_COUNT,

	__CGROUP_SUBSYS_TEMP_PLACEHOLDER = CGROUP_BUILTIN_SUBSYS_COUNT - 1,

#define IS_SUBSYS_ENABLED(option) IS_MODULE(option)
#include <linux/cgroup_subsys.h>
#include <linux/cgroup_subsys.h>
#undef IS_SUBSYS_ENABLED
	CGROUP_SUBSYS_COUNT,
	CGROUP_SUBSYS_COUNT,
};
};
#undef IS_SUBSYS_ENABLED
#undef SUBSYS
#undef SUBSYS


/* Per-subsystem/per-cgroup state maintained by the system. */
/* Per-subsystem/per-cgroup state maintained by the system. */
+14 −14
Original line number Original line Diff line number Diff line
@@ -4940,16 +4940,16 @@ void cgroup_post_fork(struct task_struct *child)
	 * and addition to css_set.
	 * and addition to css_set.
	 */
	 */
	if (need_forkexit_callback) {
	if (need_forkexit_callback) {
		for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
			struct cgroup_subsys *ss = subsys[i];

		/*
		/*
			 * fork/exit callbacks are supported only for
		 * fork/exit callbacks are supported only for builtin
			 * builtin subsystems and we don't need further
		 * subsystems, and the builtin section of the subsys
			 * synchronization as they never go away.
		 * array is immutable, so we don't need to lock the
		 * subsys array here. On the other hand, modular section
		 * of the array can be freed at module unload, so we
		 * can't touch that.
		 */
		 */
			if (!ss || ss->module)
		for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
				continue;
			struct cgroup_subsys *ss = subsys[i];


			if (ss->fork)
			if (ss->fork)
				ss->fork(child);
				ss->fork(child);
@@ -5015,13 +5015,13 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
	tsk->cgroups = &init_css_set;
	tsk->cgroups = &init_css_set;


	if (run_callbacks && need_forkexit_callback) {
	if (run_callbacks && need_forkexit_callback) {
		for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
		/*
		 * fork/exit callbacks are supported only for builtin
		 * subsystems, see cgroup_post_fork() for details.
		 */
		for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
			struct cgroup_subsys *ss = subsys[i];
			struct cgroup_subsys *ss = subsys[i];


			/* modular subsystems can't use callbacks */
			if (!ss || ss->module)
				continue;

			if (ss->exit) {
			if (ss->exit) {
				struct cgroup *old_cgrp =
				struct cgroup *old_cgrp =
					rcu_dereference_raw(cg->subsys[i])->cgroup;
					rcu_dereference_raw(cg->subsys[i])->cgroup;