hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9NC0J CVE: NA
--------------------------------
The function sysctl_memcg_swap_qos_handler() doesn't handle error case correctly and care nothing about concurrency. To fix it, we should do two thing:
1. reset sysctl_memcg_swap_qos_stat to old value for error case. 2. add a mutex_lock to protect the process.
Fixes: 8202acc60f97 ("memcg/swap: add ability to disable memcg swap") Signed-off-by: Liu Shixin liushixin2@huawei.com --- mm/memcontrol.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index f5add1247f43..9f8646bf51e2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4095,22 +4095,21 @@ static int sysctl_memcg_swap_qos_handler(struct ctl_table *table, int write, void __user *buffer, size_t *length, loff_t *ppos) { int ret; - int qos_stat_old = sysctl_memcg_swap_qos_stat; + int qos_stat_old; int swap_type; + static DEFINE_MUTEX(sysctl_mutex);
+ mutex_lock(&sysctl_mutex); + qos_stat_old = sysctl_memcg_swap_qos_stat; ret = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (ret) - return ret; - - if (qos_stat_old == sysctl_memcg_swap_qos_stat) - return 0; - - if (write) { + if (write && !ret) { + if (qos_stat_old == sysctl_memcg_swap_qos_stat) + goto unlock;
switch (sysctl_memcg_swap_qos_stat) { case MEMCG_SWAP_STAT_DISABLE: static_branch_disable(&memcg_swap_qos_key); - return 0; + goto unlock; case MEMCG_SWAP_STAT_ALL: swap_type = SWAP_TYPE_ALL; break; @@ -4119,16 +4118,26 @@ static int sysctl_memcg_swap_qos_handler(struct ctl_table *table, int write, break; }
+ /* + * Enable the feature when it is in disabled state. + * If it is already in enabled state, don't allowed + * to switch it to other state directly since it is + * dangerous that will impact all memory cgroups. + */ if (!qos_stat_old) { memcg_swap_qos_reset(swap_type); static_branch_enable(&memcg_swap_qos_key); enable_swap_slots_cache_max(); } else { - return -EINVAL; + sysctl_memcg_swap_qos_stat = qos_stat_old; + ret = -EINVAL; } }
- return 0; +unlock: + mutex_unlock(&sysctl_mutex); + + return ret; }
static struct ctl_table memcg_swap_qos_sysctls[] = {