mm/damon/core: validate ranges in damon_set_regions()
Subsystems (3)
SJ Park
maintainerPATCH 1/1 mm/damon/core: validate ranges in damon_set_regions()
DAMON core logic assumes zero length regions don't exist. However, a few DAMON API callers including DAMON_SYSFS, DAMON_RECLAIM and DAMON_LRU_SORT allow users to set empty monitoring target regions. This could result in WARN_ONCE() on CONFIG_DAMON_DEBUG_SANITY enabled kernel, and divide-by-zero from damon_merge_two_regions().
For example, the WANR_ONCE() can be triggered like below.
# grep DAMON_DEBUG_SANITY /boot/config-$(uname -r)
# CONFIG_DAMON_DEBUG_SANITY=y
# damo start
# cd /sys/kernel/mm/damon/admin/kdamonds/0
# echo 0 > contexts/0/targets/0/regions/0/start
# echo 0 > contexts/0/targets/0/regions/0/end
# echo commit > state
# dmesg
[....]
[ 73.705780] ------------[ cut here ]------------
[ 73.707552] start 0 >= end 0
[ 73.708452] WARNING: mm/damon/core.c:359 at damon_new_region+0x6e/0x80, CPU#1: kdamond.0/758
[...]All DAMON API callers eventually use damon_set_regions() to setup the regions. Add the validation logic in the function.
---
Changes from RFC v1.2
- RFC v1.2: https://lore.kernel.org/[email protected]
- Drop RFC tag.
- Rebase to latest mm-new.
Changes from RFC v1.1
- RFC v1.1: https://lore.kernel.org/[email protected]
- Use ALIGN() for end address.
Changes from RFC v1
- RFC v1: https://lore.kernel.org/[email protected]
- Fixup the commit message for how the fix is made.
- Do the validation with min_region_sz-aligned addresses.
FYI, this fix cannot be applied as is to the commit that introduced this class of bugs, because damon_set_regions() was introduced after the bug. I considered making three fixes for each caller to make the backporting on the old kernels easy. However, the first LTS kernel having the bug is 6.1.y, which has damon_set_regions() and all the callers are using it. So porting this to necessary stable kernels should be easy enough.
mm/damon/core.c | 6 ++++++ 1 file changed, 6 insertions(+)
mm/damon/core.c +6 -0
@@ -356,6 +356,12 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,unsigned int i;int err; +for (i =0 ; i < nr_ranges; i++) { +if (ALIGN_DOWN (ranges[i].start, min_region_sz) >= +ALIGN (ranges[i].end, min_region_sz)) +return -EINVAL ; + } +/* Remove regions which are not in the new ranges */ damon_for_each_region_safe (r, next, t) {for (i =0 ; i < nr_ranges; i++) {
base-commit: e861a804dfa410dde21e8d2d20179df9c66edd8d
Signature · 1 line
2.47.3
[email protected]
AI reviewThank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The introduced validation logic in damon_set_regions() is flawed and fails to prevent the WARN_ONCE and divide-by-zero crashes it intends to fix. Distinct valid regions within the same alignment block bypass the check, leading to duplicated overlapping regions, inverted hole regions, and a kernel panic. --
commit 79a8d61a7b1112d3a6da1cff84b7f4a28c66e465
Author: SJ Park <[email protected]>
mm/damon/core: validate ranges in damon_set_regions()
This commit attempts to fix a zero-length region issue that could lead to a WARN_ONCE and a divide-by-zero crash in DAMON. It adds a validation loop in damon_set_regions() to reject empty or invalid target regions before they are processed.
Quoted 5 lines
mm/damon/core.c +0
-0
mm/damon/core.c int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges, · line 364
Quoted 9 lines
mm/damon/core.c +6
-0@@ -356,6 +356,12 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,unsigned int i;int err; +for (i =0 ; i < nr_ranges; i++) { +if (ALIGN_DOWN (ranges[i].start, min_region_sz) >= +ALIGN (ranges[i].end, min_region_sz)) +return -EINVAL ; + } +
[Severity: High]
This is a pre-existing issue, but does this validation fully prevent the divide-by-zero crash?
If a user provides two unaligned regions that fall within the same min_region_sz block (for example, [10, 20] and [20, 30]), this check will evaluate ALIGN_DOWN(10) >= ALIGN(20), which becomes 0 >= 4096. This allows them to bypass rejection.
Because they pass, damon_set_regions() inflates both regions to [0, 4096], creating identical overlapping regions in the list.
If a subsequent update covers these regions (like [0, 8192]), the intersecting boundaries are adjusted but first->ar.end is left at 4096 and last->ar.start at 0. This leads to damon_fill_regions_holes() creating an inverted hole region:
mm/damon/core.c:damon_fill_regions_holes() {
...
if (r->ar.end != next->ar.start) {
newr = damon_new_region(r->ar.end, next->ar.start);
...
}Calling damon_new_region(4096, 0) triggers the WARN_ONCE(start >= end) and results in a region with a negative size (ULONG_MAX - 4095).
When damon_merge_two_regions() eventually tries to merge [0, 4096] with [4096, 0], the combined size underflows to exactly 0, causing a panic here:
mm/damon/core.c:damon_merge_two_regions() {
...
l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) /
(sz_l + sz_r);
...
}Should the alignment check be stricter, or does damon_set_regions() need additional logic to merge or reject identically aligned overlapping blocks?
Quoted 3 lines
mm/damon/core.c +0
-0/* Remove regions which are not in the new ranges */ damon_for_each_region_safe (r, next, t) {for (i =0 ; i < nr_ranges; i++) {
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
SJ Park
maintainerQuoted 71 lines · On Tue, 30 Jun 2026 04:08:28 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The introduced validation logic indamon_set_regions()is flawed and fails to prevent theWARN_ONCEand divide-by-zero crashes it intends to fix. Distinct valid regions within the same alignment block bypass the check, leading to duplicated overlapping regions, inverted hole regions, and a kernel panic. --commit
79a8d61a7b1112d3a6da1cff84b7f4a28c66e465
Author: SJ Park <[email protected]>
mm/damon/core: validate ranges indamon_set_regions()This commit attempts to fix a zero-length region issue that could lead to a
WARN_ONCEand a divide-by-zero crash in DAMON. It adds a validation loop indamon_set_regions()to reject empty or invalid target regions before they are processed.Fixes 43b0536cb471 ("mm/damon: introduce DAMON-based Reclamation (DAMON_RECLAIM)")Cc <[email protected]> # 5.16.xQuoted 5 lines
mm/damon/core.c +0
-0mm/damon/core.c int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges, · line 364
Quoted 9 lines
mm/damon/core.c +6
-0@@ -356,6 +356,12 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,unsigned int i;int err; +for (i =0 ; i < nr_ranges; i++) { +if (ALIGN_DOWN (ranges[i].start, min_region_sz) >= +ALIGN (ranges[i].end, min_region_sz)) +return -EINVAL ; + } +[Severity: High]
This is a pre-existing issue, but does this validation fully prevent the divide-by-zero crash?If a user provides two unaligned regions that fall within the same
min_region_szblock (for example, [10, 20] and [20, 30]), this check will evaluateALIGN_DOWN(10)>= ALIGN(20), which becomes 0 >= 4096. This allows them to bypass rejection.Because they pass,
damon_set_regions()inflates both regions to [0, 4096], creating identical overlapping regions in the list.If a subsequent update covers these regions (like [0, 8192]), the intersecting boundaries are adjusted but
first->ar.endis left at 4096 andlast->ar.startat 0. This leads todamon_fill_regions_holes()creating an inverted hole region:mm/damon/core.c:damon_fill_regions_holes() { ... if (r->ar.end != next->ar.start) { newr = damon_new_region(r->ar.end, next->ar.start); ... }Calling
damon_new_region(4096, 0)triggers theWARN_ONCE(start >= end)and results in a region with a negative size (ULONG_MAX- 4095).When
damon_merge_two_regions()eventually tries to merge [0, 4096] with [4096, 0], the combined size underflows to exactly 0, causing a panic here:mm/damon/core.c:damon_merge_two_regions() { ... l->nr_accesses = (l->nr_accesses * sz_l + r->nr_accesses * sz_r) / (sz_l + sz_r); ... }
Quoted 2 lines
Should the alignment check be stricter, or does
damon_set_regions()need additional logic to merge or reject identically aligned overlapping blocks?
Nice catch. Apparently it is a bug tht is different from the one this patch is fixing. So no blocker for this patch. I will further work on the newly found bug.
Thanks,
SJ
[...]
SJ Park
maintainerQuoted 22 lines · On Mon, 29 Jun 2026 20:52:19 -0700 SJ Park <[email protected]> wrote:
DAMON core logic assumes zero length regions don't exist. However, a few DAMON API callers including
DAMON_SYSFS,DAMON_RECLAIMandDAMON_LRU_SORTallow users to set empty monitoring target regions. This could result inWARN_ONCE()onCONFIG_DAMON_DEBUG_SANITYenabled kernel, and divide-by-zero fromdamon_merge_two_regions().For example, the
WANR_ONCE()can be triggered like below.# grep DAMON_DEBUG_SANITY /boot/config-$(uname -r) # CONFIG_DAMON_DEBUG_SANITY=y # damo start # cd /sys/kernel/mm/damon/admin/kdamonds/0 # echo 0 > contexts/0/targets/0/regions/0/start # echo 0 > contexts/0/targets/0/regions/0/end # echo commit > state # dmesg [....] [ 73.705780] ------------[ cut here ]------------ [ 73.707552] start 0 >= end 0 [ 73.708452] WARNING: mm/damon/core.c:359 at damon_new_region+0x6e/0x80, CPU#1: kdamond.0/758 [...]
Quoted 2 lines
All DAMON API callers eventually use
damon_set_regions()to setup the regions. Add the validation logic in the function.
Sashiko found a pre-existing issue, and it is not a blocker of this patch in my opinion. Read my reply [1] to Sashiko review for more details. So this patch is good to go.
[1] https://lore.kernel.org/[email protected]
Thanks,
SJ
[...]