DAMON development mailing list
 help / color / mirror / Atom feed
* [PATCH 6.1.y] mm/damon/core: fix unconditionally skip last region
       [not found] <2026092949-surpass-thimble-02a8@gregkh>
@ 2026-09-30  9:48 ` SJ Park
  2026-09-30 10:05   ` sashiko-bot
  2026-10-02 14:19   ` Sasha Levin
  0 siblings, 2 replies; 4+ messages in thread
From: SJ Park @ 2026-09-30  9:48 UTC (permalink / raw)
  To: stable; +Cc: damon, Liew Rui Yan, SJ Park, Andrew Morton

From: Liew Rui Yan <aethernet65535@gmail.com>

Once quota set, the charge_{target,addr}_from unconditionally skips and
resets at the last region of the tracked target, so the last region can be
skipped even when it has not been processed.

Example:

    1. Target has 2 regions: R1 (0-100 bytes) and R2 (100-200 bytes).
    2. Quota is configured to process only 100 bytes per window.
    3. Window 1: Processes R1 (0-100).  Quota is full.  charge_{target,
       addr}_from is saved at (Target, 100).
    4. Window 2: The loop reaches R2.  Because R2 is
       damon_last_region(t), the old code unconditionally returns true,
       skipping R2 entirely and resetting the charge_{target,addr}_from.

    Result: R2 is permanently skipped even though it has never been
    processed.

However, it is important to note that this is a very minor issue.  This is
because it is triggered only when the previous window saved/kept
charge_{target,addr}_from, and in the next window, all regions except the
last region were skipped by damos_skip_charged_region().

Fix this by only resetting the charge_{target,addr}_from when last region
is reached, only skipping when it is applied or cannot split.

Link: https://lore.kernel.org/20260908134739.96919-1-sj@kernel.org
Fixes: 50585192bc2e ("mm/damon/schemes: skip already charged targets and regions")
Signed-off-by: Liew Rui Yan <aethernet65535@gmail.com>
Reviewed-by: SJ Park <sj@kernel.org>
Signed-off-by: SJ Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: <stable@vger.kernel.org> # v5.16.x
(cherry picked from commit b3723b596b548c837a766aae3553c14a7b15af2b)
Signed-off-by: SJ Park <sj@kernel.org>
---
 mm/damon/core.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/mm/damon/core.c b/mm/damon/core.c
index 859a6a636ab0e..64ff03b15fdef 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -756,6 +756,7 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
 		unsigned long sz = damon_sz_region(r);
 		struct timespec64 begin, end;
 		unsigned long sz_applied = 0;
+		bool skip = false;
 
 		if (!s->wmarks.activated)
 			continue;
@@ -768,14 +769,11 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
 		if (quota->charge_target_from) {
 			if (t != quota->charge_target_from)
 				continue;
-			if (r == damon_last_region(t)) {
-				quota->charge_target_from = NULL;
-				quota->charge_addr_from = 0;
-				continue;
-			}
 			if (quota->charge_addr_from &&
-					r->ar.end <= quota->charge_addr_from)
-				continue;
+					r->ar.end <= quota->charge_addr_from) {
+				skip = true;
+				goto clean_charge_from_skip;
+			}
 
 			if (quota->charge_addr_from && r->ar.start <
 					quota->charge_addr_from) {
@@ -783,17 +781,25 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
 						r->ar.start, DAMON_MIN_REGION);
 				if (!sz) {
 					if (damon_sz_region(r) <=
-					    DAMON_MIN_REGION)
-						continue;
+					    DAMON_MIN_REGION) {
+						skip = true;
+						goto clean_charge_from_skip;
+					}
 					sz = DAMON_MIN_REGION;
 				}
 				damon_split_region_at(t, r, sz);
 				r = damon_next_region(r);
 				sz = damon_sz_region(r);
+				skip = false;
 			}
+		}
+clean_charge_from_skip:
+		if (r == damon_last_region(t)) {
 			quota->charge_target_from = NULL;
 			quota->charge_addr_from = 0;
 		}
+		if (skip)
+			continue;
 
 		if (!damos_valid_target(c, t, r, s))
 			continue;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 6.1.y] mm/damon/core: fix unconditionally skip last region
  2026-09-30  9:48 ` [PATCH 6.1.y] mm/damon/core: fix unconditionally skip last region SJ Park
@ 2026-09-30 10:05   ` sashiko-bot
  2026-09-30 10:23     ` SJ Park
  2026-10-02 14:19   ` Sasha Levin
  1 sibling, 1 reply; 4+ messages in thread
From: sashiko-bot @ 2026-09-30 10:05 UTC (permalink / raw)
  To: SJ Park; +Cc: damon

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] mm/damon: out-of-bounds memory access when region split fails on last region
--

commit e8c0d519ccfab8bb3783274c1139b24ab75f8aa1
Author: Liew Rui Yan <aethernet65535@gmail.com>

mm/damon/core: fix unconditionally skip last region

This commit fixes an issue where the last region of a target is
unconditionally skipped and reset when a quota is set, even if it hasn't
been processed.

Link: https://lore.kernel.org/20260908134739.96919-1-sj@kernel.org

> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 859a6a636ab0e..64ff03b15fdef 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -768,14 +769,11 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
>  		if (quota->charge_target_from) {
>  			if (t != quota->charge_target_from)
>  				continue;
> -			if (r == damon_last_region(t)) {
> -				quota->charge_target_from = NULL;
> -				quota->charge_addr_from = 0;
> -				continue;
> -			}

[ ... ]

> @@ -783,17 +781,25 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
>  						r->ar.start, DAMON_MIN_REGION);
>  				if (!sz) {
>  					if (damon_sz_region(r) <=
> -					    DAMON_MIN_REGION)
> -						continue;
> +					    DAMON_MIN_REGION) {
> +						skip = true;
> +						goto clean_charge_from_skip;
> +					}
>  					sz = DAMON_MIN_REGION;
>  				}
>  				damon_split_region_at(t, r, sz);
>  				r = damon_next_region(r);
>  				sz = damon_sz_region(r);

[Severity: High]
Since this patch removes the early check for the last region, what happens
in damon_do_apply_schemes() if damon_split_region_at() fails on the last
region?

If damon_split_region_at() fails under memory pressure, it returns silently
without splitting the region. The code then unconditionally calls
r = damon_next_region(r).

Because r was the last region and was not split, its list.next points to the
list head. damon_next_region() then returns an invalid pointer. 

The next line calls damon_sz_region(r), which dereferences this invalid
pointer and causes an out-of-bounds memory access.

Does this code need a check to ensure the region was successfully split before
advancing the pointer?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260930094853.52736-1-sj@kernel.org?part=1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 6.1.y] mm/damon/core: fix unconditionally skip last region
  2026-09-30 10:05   ` sashiko-bot
@ 2026-09-30 10:23     ` SJ Park
  0 siblings, 0 replies; 4+ messages in thread
From: SJ Park @ 2026-09-30 10:23 UTC (permalink / raw)
  To: sashiko-bot; +Cc: SJ Park, damon

On Wed, 30 Sep 2026 10:05:10 +0000 sashiko-bot@kernel.org wrote:

> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] mm/damon: out-of-bounds memory access when region split fails on last region
> --
> 
> commit e8c0d519ccfab8bb3783274c1139b24ab75f8aa1
> Author: Liew Rui Yan <aethernet65535@gmail.com>
> 
> mm/damon/core: fix unconditionally skip last region
> 
> This commit fixes an issue where the last region of a target is
> unconditionally skipped and reset when a quota is set, even if it hasn't
> been processed.
> 
> Link: https://lore.kernel.org/20260908134739.96919-1-sj@kernel.org
> 
> > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > index 859a6a636ab0e..64ff03b15fdef 100644
> > --- a/mm/damon/core.c
> > +++ b/mm/damon/core.c
> > @@ -768,14 +769,11 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
> >  		if (quota->charge_target_from) {
> >  			if (t != quota->charge_target_from)
> >  				continue;
> > -			if (r == damon_last_region(t)) {
> > -				quota->charge_target_from = NULL;
> > -				quota->charge_addr_from = 0;
> > -				continue;
> > -			}
> 
> [ ... ]
> 
> > @@ -783,17 +781,25 @@ static void damon_do_apply_schemes(struct damon_ctx *c,
> >  						r->ar.start, DAMON_MIN_REGION);
> >  				if (!sz) {
> >  					if (damon_sz_region(r) <=
> > -					    DAMON_MIN_REGION)
> > -						continue;
> > +					    DAMON_MIN_REGION) {
> > +						skip = true;
> > +						goto clean_charge_from_skip;
> > +					}
> >  					sz = DAMON_MIN_REGION;
> >  				}
> >  				damon_split_region_at(t, r, sz);
> >  				r = damon_next_region(r);
> >  				sz = damon_sz_region(r);
> 
> [Severity: High]
> Since this patch removes the early check for the last region, what happens
> in damon_do_apply_schemes() if damon_split_region_at() fails on the last
> region?
> 
> If damon_split_region_at() fails under memory pressure, it returns silently
> without splitting the region. The code then unconditionally calls
> r = damon_next_region(r).
> 
> Because r was the last region and was not split, its list.next points to the
> list head. damon_next_region() then returns an invalid pointer. 
> 
> The next line calls damon_sz_region(r), which dereferences this invalid
> pointer and causes an out-of-bounds memory access.
> 
> Does this code need a check to ensure the region was successfully split before
> advancing the pointer?

The out-of-bounds memory access is indeed occurs due to this patch.  But the
lack of damon_split_region_at() error handling was anyway a bug.  So, in a
sense, pre-existing issue.  I will work on fixing it separately.

> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/20260930094853.52736-1-sj@kernel.org?part=1


Thanks,
SJ

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 6.1.y] mm/damon/core: fix unconditionally skip last region
  2026-09-30  9:48 ` [PATCH 6.1.y] mm/damon/core: fix unconditionally skip last region SJ Park
  2026-09-30 10:05   ` sashiko-bot
@ 2026-10-02 14:19   ` Sasha Levin
  1 sibling, 0 replies; 4+ messages in thread
From: Sasha Levin @ 2026-10-02 14:19 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, damon, Liew Rui Yan, SJ Park, Andrew Morton

> Fix this by only resetting the charge_{target,addr}_from when last region
> is reached, only skipping when it is applied or cannot split.

I'll hold this until the damon_split_region_at() failure handling fix
you mentioned is posted, and then take 6.12, 6.6 and 6.1 together with
it.

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-02 14:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <2026092949-surpass-thimble-02a8@gregkh>
2026-09-30  9:48 ` [PATCH 6.1.y] mm/damon/core: fix unconditionally skip last region SJ Park
2026-09-30 10:05   ` sashiko-bot
2026-09-30 10:23     ` SJ Park
2026-10-02 14:19   ` Sasha Levin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox