From af581324751caa0a56af4a8f4f1edf13bd7a7bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E9=82=A3=E5=87=A0?= <2078634206@qq.com> Date: Fri, 21 Aug 2026 08:34:26 +0800 Subject: [PATCH] tkernel: killblock/killprotect: fix rule counter drift under flush race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rule counters are updated outside of the list write lock in the flush, add and del paths of the whitelist/blacklist proc write handlers. A flush that empties the list can be interleaved with a concurrent add: flush drops the lock after deleting all rules but before atomic_set(&*_rule_cnt, 0), the add inserts a rule and bumps the counter, and the flush then resets the counter to zero. The counter no longer matches the list length, and the capacity check against the rules limit can be bypassed afterwards. Update the counters inside the write lock critical section in all three paths of both modules, so the counter always transitions together with the list it accounts for. Upstream status: downstream-only Signed-off-by: 陈那几 <2078634206@qq.com> --- kernel/tkernel/killblock/kill_block.c | 6 +++--- kernel/tkernel/killprotect/kill_protect.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/tkernel/killblock/kill_block.c b/kernel/tkernel/killblock/kill_block.c index 50e8484bd51d..5271f615530d 100644 --- a/kernel/tkernel/killblock/kill_block.c +++ b/kernel/tkernel/killblock/kill_block.c @@ -75,8 +75,8 @@ static ssize_t whitelist_write(struct file *file, const char __user *ubuf, list_del(&rule->node); kfree(rule); } - write_unlock(&whitelist_lock); atomic_set(&kb_rule_cnt, 0); + write_unlock(&whitelist_lock); return count; } return -EINVAL; @@ -111,8 +111,8 @@ static ssize_t whitelist_write(struct file *file, const char __user *ubuf, } } list_add(&rule->node, &whitelist_list); - write_unlock(&whitelist_lock); atomic_inc(&kb_rule_cnt); + write_unlock(&whitelist_lock); } else if (!strcmp(token[0], "del")) { write_lock(&whitelist_lock); list_for_each_entry_safe(rule, tmp, &whitelist_list, node) { @@ -120,9 +120,9 @@ static ssize_t whitelist_write(struct file *file, const char __user *ubuf, !strcasecmp(rule->dst_comm, token[2]) && !strcasecmp(rule->dst_cgrp, token[3])) { list_del(&rule->node); + atomic_dec(&kb_rule_cnt); write_unlock(&whitelist_lock); kfree(rule); - atomic_dec(&kb_rule_cnt); return count; } } diff --git a/kernel/tkernel/killprotect/kill_protect.c b/kernel/tkernel/killprotect/kill_protect.c index 4474cad05b14..28f3ec1fd254 100644 --- a/kernel/tkernel/killprotect/kill_protect.c +++ b/kernel/tkernel/killprotect/kill_protect.c @@ -70,8 +70,8 @@ static ssize_t blacklist_write(struct file *file, const char __user *ubuf, list_del(&rule->node); kfree(rule); } - write_unlock(&blacklist_lock); atomic_set(&kp_rule_cnt, 0); + write_unlock(&blacklist_lock); return count; } return -EINVAL; @@ -100,8 +100,8 @@ static ssize_t blacklist_write(struct file *file, const char __user *ubuf, } } list_add(&rule->node, &blacklist_list); - write_unlock(&blacklist_lock); atomic_inc(&kp_rule_cnt); + write_unlock(&blacklist_lock); } else if (strcmp(token[0], "del") == 0) { cnt = min_t(size_t, TASK_COMM_LEN - 1, strlen(token[1])); strncpy(comm, token[1], cnt); @@ -111,9 +111,9 @@ static ssize_t blacklist_write(struct file *file, const char __user *ubuf, list_for_each_entry_safe(rule, tmp, &blacklist_list, node) { if (strcmp(rule->comm, comm) == 0) { list_del(&rule->node); + atomic_dec(&kp_rule_cnt); write_unlock(&blacklist_lock); kfree(rule); - atomic_dec(&kp_rule_cnt); return count; } } -- Gitee