mm/damon: avoid division by zero from damos_quota_score()
Subsystems (3)
SJ Park
maintainercover mm/damon: avoid division by zero from damos_quota_score()
DAMON_SAMPLE_MTIER and DAMON_LRU_SORT allow the user to trigger division by zero in damos_quota_score(). Avoid it by adding parameters validation checks.
Changes from RFC v2
- RFC v2: https://lore.kernel.org/[email protected]
- Drop RFC tag.
Changes from RFC
- RFC: https://lore.kernel.org/[email protected]
- Add a fix for DAMON_LRU_SORT.
SJ Park (2):
samples/damon/mtier: error out for zero quota goal target values mm/damon/lru_sort: error out for >10000 active_mem_bp
mm/damon/lru_sort.c | 2 ++ samples/damon/mtier.c | 3 +++ 2 files changed, 5 insertions(+)
base-commit: 3bf69d5b51b688b8f923a13b7f12eb9b1c6a284f
Signature · 1 line
2.47.3
SJ Park
maintainerPATCH 1/2 samples/damon/mtier: error out for zero quota goal target values
damos_quota_score() can trigger division by zero if the target_value is zero. DAMON_SAMPLE_MTIER lets users set the target_value via node0_mem_{used,free}_bp parameters. It doesn't guard zero value case, though. As a result, users can trigger division by zero. Fix the issue by returning an error when the user tries to start DAMON with zero node0_mem_{used,free}_bp parameter values.
DAMON_SAMPLE_MTIER is just a sample module, but the consequence is quite bad. Also the zero node0_mem_free_bp parameter might look like a reasonable setup to some users. Hence, the issue might really happen in the real world.
One reliable way to reproduce the issue is like below:
# cd /sys/module/damon_sample_mtier/parameters
# echo 4096 > node0_start_addr
# echo 8192 > node0_end_addr
# echo 8192 > node1_start_addr
# echo 81920 > node1_end_addr
# echo 0 > node0_mem_free_bp
# echo Y > enabled
# dmesg -w
[...]
[18792.235916] Oops: divide error: 0000 [#1] SMP NOPTI
[...]
[18792.242787] RIP: 0010:damos_quota_score+0x6f/0x480
[...]This issue was discovered [1] by Sashiko.
[1] https://lore.kernel.org/[email protected]
--- samples/damon/mtier.c | 3 +++ 1 file changed, 3 insertions(+)
samples/damon/mtier.c +3 -0
@@ -156,6 +156,9 @@ static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote)if (!scheme) goto free_out;damon_set_schemes (ctx, &scheme,1 ); +/* zero target value causes division by zero in damos_quota_store() */ +if (!node0_mem_used_bp || !node0_mem_free_bp) + goto free_out; quota_goal = damos_new_quota_goal( promote ? DAMOS_QUOTA_NODE_MEM_USED_BP : DAMOS_QUOTA_NODE_MEM_FREE_BP,
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH 1/2] samples/damon/mtier: error out for zero quota goal target values
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] The safety check for zero values evaluates global module parameters without READ_ONCE(), introducing a TOCTOU race window that bypasses the patch's defense.
- [Low] The newly added comment references a non-existent function damos_quota_store() instead of damos_quota_score().
Pre-existing issues:
- [High] The core API damos_new_quota_goal() fails to validate target_value != 0, forcing ad-hoc checks in caller modules and leaving the subsystem vulnerable to division by zero.
- [High] The DAMON LRU sort module computes a quota goal target value from an unvalidated module parameter, allowing users to trigger a division by zero crash. --
--- Patch [1]: [PATCH 1/2] samples/damon/mtier: error out for zero quota goal target values --- commit 8e87b5068bfcd9e35bdbd23dadaa97f649431adb
Author: SJ Park <[email protected]>
samples/damon/mtier: error out for zero quota goal target values
This patch prevents a division by zero in damos_quota_score() by returning an error when a user configures DAMON with zero target values for the node0_mem_used_bp or node0_mem_free_bp module parameters.
samples/damon/mtier.c static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote) · line 159
Quoted 9 lines
samples/damon/mtier.c +1
-0@@ -156,6 +156,9 @@ static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote)if (!scheme) goto free_out;damon_set_schemes (ctx, &scheme,1 ); +/* zero target value causes division by zero in damos_quota_store() */
[Severity: Low]
This isn't a bug, but there is a typo in the comment. Should damos_quota_store() be damos_quota_score()?
Quoted 6 lines
samples/damon/mtier.c +2
-0+if (!node0_mem_used_bp || !node0_mem_free_bp) + goto free_out; quota_goal = damos_new_quota_goal( promote ? DAMOS_QUOTA_NODE_MEM_USED_BP : DAMOS_QUOTA_NODE_MEM_FREE_BP,promote ?
node0_mem_used_bp:node0_mem_free_bp);
[Severity: High]
Can a concurrent sysfs write bypass this safety check?
The module parameters node0_mem_used_bp and node0_mem_free_bp are read multiple times without READ_ONCE().
A concurrent thread could set a non-zero value to pass the check, and then overwrite it with zero before damos_new_quota_goal() reads the parameter again.
Would this re-introduce the division by zero crash?
This same double-read pattern appears to be present in other DAMON modules:
mm/damon/lru_sort.c:damon_lru_sort_add_quota_goals() {
if (!active_mem_bp)
return 0;
goal = damos_new_quota_goal(DAMOS_QUOTA_ACTIVE_MEM_BP, active_mem_bp);...
}
mm/damon/reclaim.c:damon_reclaim_apply_parameters() {
if (quota_mem_pressure_us) {
goal = damos_new_quota_goal(DAMOS_QUOTA_SOME_MEM_PSI_US,
quota_mem_pressure_us);...
}
Should these parameters be cached in local variables or read with READ_ONCE() to prevent a Time-of-Check to Time-of-Use race?
[Severity: High]
This is a pre-existing issue, but does the core API damos_new_quota_goal() need a check for a zero target_value?
Currently, callers are responsible for validating the target value to avoid a division by zero in damos_quota_score(). If damos_new_quota_goal() validated this and returned NULL when target_value is 0, it would protect the entire DAMON subsystem systematically without relying on ad-hoc checks in caller modules:
mm/damon/core.c:damos_new_quota_goal() {
struct damos_quota_goal *goal;
goal = kmalloc_obj(*goal);
if (!goal)
return NULL;
goal->metric = metric;
goal->target_value = target_value;
...
}[Severity: High]
This is a pre-existing issue, but can the LRU sort module trigger a division by zero despite parameter validation?
In damon_lru_sort_add_quota_goals(), the cold scheme's quota goal is computed dynamically:
mm/damon/lru_sort.c:damon_lru_sort_add_quota_goals() {
...
goal = damos_new_quota_goal(DAMOS_QUOTA_INACTIVE_MEM_BP,
10000 - active_mem_bp + 2);
...
}
If a user configures the active_mem_bp module parameter to exactly 10002 via sysfs, the resulting target_value evaluates to 0.
Since this value is passed directly to damos_new_quota_goal(), wouldn't this crash the kernel in damos_quota_score()?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
SJ Park
maintainerRe: [PATCH 1/2] samples/damon/mtier: error out for zero quota goal target values
Quoted 69 lines · On Mon, 03 Aug 2026 14:06:52 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] The safety check for zero values evaluates global module parameters withoutREAD_ONCE(), introducing a TOCTOU race window that bypasses the patch's defense.
- [Low] The newly added comment references a non-existent functiondamos_quota_store()instead ofdamos_quota_score().Pre-existing issues:
- [High] The core APIdamos_new_quota_goal()fails to validatetarget_value != 0, forcing ad-hoc checks in caller modules and leaving the subsystem vulnerable to division by zero.
- [High] The DAMON LRU sort module computes a quota goal target value from an unvalidated module parameter, allowing users to trigger a division by zero crash. ----- Patch [1]: [PATCH 1/2]
samples/damon/mtier: error out for zero quota goal target values --- commit8e87b5068bfcd9e35bdbd23dadaa97f649431adb
Author: SJ Park <[email protected]>
samples/damon/mtier: error out for zero quota goal target valuesThis patch prevents a division by zero in
damos_quota_score()by returning an error when a user configures DAMON with zero target values for thenode0_mem_used_bpornode0_mem_free_bpmodule parameters.samples/damon/mtier.c static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote) · line 159
Quoted 9 lines
samples/damon/mtier.c +1
-0@@ -156,6 +156,9 @@ static struct damon_ctx *damon_sample_mtier_build_ctx(bool promote)if (!scheme) goto free_out;damon_set_schemes (ctx, &scheme,1 ); +/* zero target value causes division by zero in damos_quota_store() */ [Severity: Low]
This isn't a bug, but there is a typo in the comment. Shoulddamos_quota_store()bedamos_quota_score()?Quoted 6 lines
samples/damon/mtier.c +2
-0+if (!node0_mem_used_bp || !node0_mem_free_bp) + goto free_out; quota_goal = damos_new_quota_goal( promote ? DAMOS_QUOTA_NODE_MEM_USED_BP : DAMOS_QUOTA_NODE_MEM_FREE_BP,promote ?
node0_mem_used_bp:node0_mem_free_bp);[Severity: High]
Can a concurrent sysfs write bypass this safety check?The module parameters
node0_mem_used_bpandnode0_mem_free_bpare read multiple times withoutREAD_ONCE().A concurrent thread could set a non-zero value to pass the check, and then overwrite it with zero before
damos_new_quota_goal()reads the parameter again.Would this re-introduce the division by zero crash?
This same double-read pattern appears to be present in other DAMON modules:
mm/damon/lru_sort.c:damon_lru_sort_add_quota_goals() { if (!active_mem_bp) return 0; goal = damos_new_quota_goal(DAMOS_QUOTA_ACTIVE_MEM_BP, active_mem_bp);...
}mm/damon/reclaim.c:damon_reclaim_apply_parameters() { if (quota_mem_pressure_us) { goal = damos_new_quota_goal(DAMOS_QUOTA_SOME_MEM_PSI_US, quota_mem_pressure_us);
Quoted 5 lines
...
}Should these parameters be cached in local variables or read with
READ_ONCE()to prevent a Time-of-Check to Time-of-Use race?
No, such race is avoided by param_lock.
Quoted 12 lines
[Severity: High]
This is a pre-existing issue, but does the core APIdamos_new_quota_goal()need a check for a zerotarget_value?Currently, callers are responsible for validating the target value to avoid a division by zero in
damos_quota_score(). Ifdamos_new_quota_goal()validated this and returned NULL whentarget_valueis 0, it would protect the entire DAMON subsystem systematically without relying on ad-hoc checks in caller modules:
Quoted 10 lines
mm/damon/core.c:damos_new_quota_goal() {
struct damos_quota_goal *goal;
goal = kmalloc_obj(*goal);
if (!goal)
return NULL;
goal->metric = metric;
goal->target_value = target_value;
...
}I'm planning to make a long term fix in the core layer later.
Quoted 16 lines
[Severity: High]
This is a pre-existing issue, but can the LRU sort module trigger a division by zero despite parameter validation?In
damon_lru_sort_add_quota_goals(), the cold scheme's quota goal is computed dynamically:mm/damon/lru_sort.c:damon_lru_sort_add_quota_goals() {
...
goal = damos_new_quota_goal(DAMOS_QUOTA_INACTIVE_MEM_BP,
10000 -active_mem_bp+ 2);
...
}
Quoted 5 lines
If a user configures the
active_mem_bpmodule parameter to exactly 10002 via sysfs, the resultingtarget_valueevaluates to 0.Since this value is passed directly to
damos_new_quota_goal(), wouldn't this crash the kernel indamos_quota_score()?
The next patch of this series fixes the bug.
Quoted 3 lines
Signature · 2 lines
-- Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Thanks,
SJ
SJ Park
maintainerPATCH 2/2 mm/damon/lru_sort: error out for >10000 active_mem_bp
In reply to SJ Parkdamos_quota_score() can trigger division by zero if the target value is zero. DAMON_LRU_SORT lets users set the target value for the hot memory scheme via active_mem_bp parameter. It avoids setting it as the target value if the parameter value is zero. However, it also sets the cold memory scheme with a target value that is calculated as '10000 - active_mem_bp + 2'. Hence, if a user sets active_mem_bp 10002, the cold memory scheme's quota goal target value can be zero. As a result, division by zero can be triggered. Fix by returning an error when the user tries to start DAMON with >10000 active_mem_bp parameter value.
It makes no sense to set active_mem_bp with 10002. It also requires module parameters write permission to reproduce the issue. That said, the consequence is quite bad.
One reliable way to reproduce the issue is like below:
# cd /sys/module/damon_lru_sort/parameters
# echo 1000 > wmarks_high
# echo 995 > wmarks_mid
# echo 0 > wmarks_low
# echo 10002 > active_mem_bp
# echo Y > enabled
# dmesg -w
[...]
[ 597.421247] Oops: divide error: 0000 [#1] SMP NOPTI
[ 597.428848] RIP: 0010:damos_quota_score+0x6f/0x480This issue was discovered [1] by Sashiko.
[1] https://lore.kernel.org/[email protected]
--- mm/damon/lru_sort.c | 2 ++ 1 file changed, 2 insertions(+)
mm/damon/lru_sort.c +2 -0
@@ -233,6 +233,8 @@ static int damon_lru_sort_add_quota_goals(struct damos *hot_scheme,if (!active_mem_bp)return 0 ; +if (10000 < active_mem_bp) +return -EINVAL ; goal =damos_new_quota_goal (DAMOS_QUOTA_ACTIVE_MEM_BP , active_mem_bp);if (!goal)return -ENOMEM ;
Signature · 1 line
2.47.3
Re: [PATCH 2/2] mm/damon/lru_sort: error out for >10000 active_mem_bp
Quoted 43 lines · On Mon, 3 Aug 2026 06:40:33 -0700 SJ Park <[email protected]> wrote:
damos_quota_score()can trigger division by zero if the target value is zero.DAMON_LRU_SORTlets users set the target value for the hot memory scheme viaactive_mem_bpparameter. It avoids setting it as the target value if the parameter value is zero. However, it also sets the cold memory scheme with a target value that is calculated as '10000 -active_mem_bp+ 2'. Hence, if a user setsactive_mem_bp10002, the cold memory scheme's quota goal target value can be zero. As a result, division by zero can be triggered. Fix by returning an error when the user tries to start DAMON with >10000active_mem_bpparameter value.It makes no sense to set
active_mem_bpwith 10002. It also requires module parameters write permission to reproduce the issue. That said, the consequence is quite bad.One reliable way to reproduce the issue is like below:
# cd /sys/module/damon_lru_sort/parameters # echo 1000 > wmarks_high # echo 995 > wmarks_mid # echo 0 > wmarks_low # echo 10002 > active_mem_bp # echo Y > enabled # dmesg -w [...] [ 597.421247] Oops: divide error: 0000 [#1] SMP NOPTI [ 597.428848] RIP: 0010:damos_quota_score+0x6f/0x480This issue was discovered [1] by Sashiko.
[1] https://lore.kernel.org/[email protected]
Fixes 40d98d31cd70 ("mm/damon/lru_sort: support active:inactive memory ratio based auto-tuning")Cc <[email protected]> # 7.0.xSigned-off-by SJ Park <[email protected]>--- mm/damon/lru_sort.c | 2 ++ 1 file changed, 2 insertions(+)mm/damon/lru_sort.c +0
-0
mm/damon/lru_sort.c static int damon_lru_sort_add_quota_goals(struct damos *hot_scheme, · line 236
Quoted 4 lines
mm/damon/lru_sort.c +1
-0@@ -233,6 +233,8 @@ static int damon_lru_sort_add_quota_goals(struct damos *hot_scheme,if (!active_mem_bp)return 0 ; +if (10000 < active_mem_bp)
That is backwards...
Quoted 4 lines
mm/damon/lru_sort.c +1
-0+return -EINVAL ; goal =damos_new_quota_goal (DAMOS_QUOTA_ACTIVE_MEM_BP , active_mem_bp);if (!goal)return -ENOMEM ;
SJ Park
maintainerRe: [PATCH 2/2] mm/damon/lru_sort: error out for >10000 active_mem_bp
Quoted 2 lines · On Mon, 3 Aug 2026 15:57:15 +0100 David Laight <[email protected]>…
On Mon, 3 Aug 2026 06:40:33 -0700
SJ Park <[email protected]> wrote:
[...]
Quoted 9 lines
mm/damon/lru_sort.c static int damon_lru_sort_add_quota_goals(struct damos *hot_scheme, · line 236
Quoted 7 lines
mm/damon/lru_sort.c +1
-0@@ -233,6 +233,8 @@ static int damon_lru_sort_add_quota_goals(struct damos *hot_scheme,if (!active_mem_bp)return 0 ; +if (10000 < active_mem_bp)That is backwards...
I tend to prefer using only '<' or '<=' because it makes smaller thing comes left. But maybe I was overusing that here. I think 'active_mem_bp > 10000' should also reads well. I will think more carefully for this, from the next time. Andrew already picked this up and he should be busy for next merge window preparation. Hence I'll not revision this for the minor change, if you don't mind.
Thanks,
SJ
[...]