mm/damon/core: hide core-private struct fields
Subsystems (2)
SJ Park
maintainercover mm/damon/core: hide core-private struct fields
DAMON core structs hide core-private fields using 'private:' comment tags. It is incomplete and inconsistent. The linked list heads in a few structs, for example, are intended to be hidden, and always be used using the wrapper macros like damon_for_each_region(). But those were mistakenly marked as non-private. A few core layer-only fields were also mistakenly added as non-private.
This only encourages callers to directly use the private fields. It is easy to make mistakes, and difficult to control. Mark all such DAMON core struct fields as private.
Patches 1-8 mark the private fields for damon_region, damon_target, damos_quota_goal, damos_quota, damos_filter, damos, damon_filter and damon_probe, respectively. Patch 9 removes DAMON_SYSFS's direct access to core-private field, damon_ctx->ops. Finally patch 10 mark the private fields for damon_ctx.
SJ Park (10):
mm/damon/core: hide private damon_region fields mm/damon/core: hide private damon_target fields mm/damon/core: hide private damos_quota_goal fields mm/damon/core: hide private damos_quota fields mm/damon/core: hide private damos_filter fields mm/damon/core: hide private damos fields mm/damon/core: hide private damon_filter fields mm/damon/core: hide private damon_probe fields mm/damon/sysfs: do not directly access damon_ctx->ops mm/damon/core: hide core-private damon_ctx fields
include/linux/damon.h | 110 +++++++++++++++++++++++------------------- mm/damon/sysfs.c | 2 +- 2 files changed, 62 insertions(+), 50 deletions(-)
base-commit: ddf3f75c217672edd46466c9156d64abf5119b68
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 1/10 mm/damon/core: hide private damon_region fields
damon_region->list is intended to be used by only the DAMON core layer. But it is mistakenly not marked as private. Hide it from the callers by marking it private.
--- include/linux/damon.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
include/linux/damon.h +4 -3
@@ -46,7 +46,6 @@ struct damon_size_range {* @sampling_addr: Address of the sample for the next access check. * @nr_accesses: Access frequency of this region. * @probe_hits: Number of probe-positive region samples. -* @list: List head for siblings. * @age: Age of this region. * * For any use case, @ar should be non-zero positive size. damon_set_regions()
@@ -68,9 +67,11 @@ struct damon_region {unsigned long sampling_addr;unsigned int nr_accesses;unsigned char probe_hits[DAMON_MAX_PROBES ]; -struct list_head list;unsigned int age; -/* private: Internal value for age calculation. */ +/* private: internal use only. */ +/* List head for siblings. */ +struct list_head list; +/* for age calculation. */ unsigned int last_nr_accesses;unsigned char last_probe_hits[DAMON_MAX_PROBES ]; };
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 2/10 mm/damon/core: hide private damon_target fields
In reply to SJ Park'nr_regions', 'regions_list' and 'list' fields of damon_target are intended to be used by only the DAMON core layer. Those are mistakenly not marked as private. Mark as private.
--- include/linux/damon.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
include/linux/damon.h +5 -4
@@ -79,9 +79,6 @@ struct damon_region {/** * struct damon_target - Represents a monitoring target. * @pid: The PID of the virtual address space to monitor. -* @nr_regions: Number of monitoring target regions of this target. -* @regions_list: Head of the monitoring target regions of this target. -* @list: List head for siblings. * @obsolete: Whether the commit destination target is obsolete. * * Each monitoring context could have multiple targets. For example, a context
@@ -95,10 +92,14 @@ struct damon_region {*/ struct damon_target {struct pid *pid; +bool obsolete; +/* private: */ +/* Number of monitoring target regions of this target. */ unsigned int nr_regions; +/* Head of the monitoring target regions of this target. */ struct list_head regions_list; +/* List head for siblings. */ struct list_head list; -bool obsolete; };/**
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 3/10 mm/damon/core: hide private damos_quota_goal fields
In reply to SJ Park'last_psi_total' and 'list' of damos_quota_goal are intended to be used by only the DAMON core layer. Those are mistakenly not marked as private, though. Mark as private.
--- include/linux/damon.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
include/linux/damon.h +6 -3
@@ -175,10 +175,8 @@ enum damos_quota_goal_metric {* @metric: Metric to be used for representing the goal. * @target_value: Target value of @metric to achieve with the tuning. * @current_value: Current value of @metric. -* @last_psi_total: Last measured total PSI * @nid: Node id. * @memcg_id: Memcg id. -* @list: List head for siblings. * * Data structure for getting the current score of the quota tuning goal. The * score is calculated by how close @current_value and @target_value are. Then
@@ -201,12 +199,17 @@ struct damos_quota_goal {unsigned long current_value;/* metric-dependent fields */ union { -u64 last_psi_total;struct {int nid;u64 memcg_id; }; +/* private: */ +/* Last measured total PSI */ +u64 last_psi_total; + }; +/* private: */ +/* List head for siblings. */ struct list_head list; };
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 4/10 mm/damon/core: hide private damos_quota fields
In reply to SJ Parkdamos_quota->goals is intended to be used by only the DAMON core layer. But it is mistakenly not marked as private. Mark as private.
--- include/linux/damon.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
include/linux/damon.h +4 -3
@@ -228,7 +228,6 @@ enum damos_quota_goal_tuner {* @reset_interval: Charge reset interval in milliseconds. * @ms: Maximum milliseconds that the scheme can use. * @sz: Maximum bytes of memory that the action can be applied. -* @goals: Head of quota tuning goals (&damos_quota_goal) list. * @goal_tuner: Goal-based @esz tuning algorithm to use. * @esz: Effective size quota in bytes. * @fail_charge_num: Failed regions charge rate numerator.
@@ -255,7 +254,7 @@ enum damos_quota_goal_tuner {* the scheme's action. DAMON then compares it against &sz and uses smaller * one as the effective quota. * -* If @goals is not empty, DAMON calculates yet another size quota based on the +* If goals is not empty, DAMON calculates yet another size quota based on the * goals using its internal feedback loop algorithm, for every @reset_interval. * Then, if the new size quota is smaller than the effective quota, it uses the * new size quota as the effective quota.
@@ -276,7 +275,7 @@ struct damos_quota {unsigned long reset_interval;unsigned long ms;unsigned long sz; -struct list_head goals; +enum damos_quota_goal_tuner goal_tuner;unsigned long esz;
@@ -288,6 +287,8 @@ struct damos_quota {unsigned int weight_age;/* private: */ +/* Head of quota tuning goals (&damos_quota_goal) list. */ +struct list_head goals;/* For throughput estimation */ unsigned long total_charged_sz;unsigned long total_charged_ns;
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 5/10 mm/damon/core: hide private damos_filter fields
In reply to SJ Parkdamos_filter->list is intended to be used by only the DAMON core layer. However, it is mistakenly not marked as private. Mark as private.
--- include/linux/damon.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
include/linux/damon.h +2 -1
@@ -432,7 +432,6 @@ enum damos_filter_type {* &damon_ctx->adaptive_targets if @type is * DAMOS_FILTER_TYPE_TARGET. * @sz_range: Size range if @type is DAMOS_FILTER_TYPE_HUGEPAGE_SIZE. -* @list: List head for siblings. * * Before applying the &damos->action to a memory region, DAMOS checks if each * byte of the region matches to this given condition and avoid applying the
@@ -450,6 +449,8 @@ struct damos_filter {int target_idx;struct damon_size_range sz_range; }; +/* private: */ +/* List head for siblings. */ struct list_head list; };
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 6/10 mm/damon/core: hide private damos fields
In reply to SJ Park'core_filters', 'ops_filters', 'last_applied' and 'list' fields of damos are intended to be used by only the DAMON core layer. However, those are mistakenly not marked as private. Mark as private.
--- include/linux/damon.h | 52 ++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 25 deletions(-)
include/linux/damon.h +27 -25
@@ -522,12 +522,8 @@ struct damos_migrate_dests {* @wmarks: Watermarks for automated (in)activation of this scheme. * @migrate_dests: Destination nodes if @action is "migrate_{hot,cold}". * @target_nid: Destination node if @action is "migrate_{hot,cold}". -* @core_filters: Additional set of &struct damos_filter for &action. -* @ops_filters: ops layer handling &struct damos_filter objects list. -* @last_applied: Last @action applied ops-managing entity. * @stat: Statistics of this scheme. * @max_nr_snapshots: Upper limit of nr_snapshots stat. -* @list: List head for siblings. * * For each @apply_interval_us, DAMON finds regions which fit in the * &pattern and applies &action to those. To avoid consuming too much
@@ -549,16 +545,7 @@ struct damos_migrate_dests {* * Before applying the &action to a memory region, &struct damon_operations * implementation could check pages of the region and skip &action to respect -* &core_filters -* -* The minimum entity that @action can be applied depends on the underlying -* &struct damon_operations. Since it may not be aligned with the core layer -* abstract, namely &struct damon_region, &struct damon_operations could apply -* @action to same entity multiple times. Large folios that underlying on -* multiple &struct damon region objects could be such examples. The &struct -* damon_operations can use @last_applied to avoid that. DAMOS core logic -* unsets @last_applied when each regions walking for applying the scheme is -* finished. +* &struct damos_filter. * * After applying the &action to each region, &stat is updated. *
@@ -569,6 +556,16 @@ struct damos {struct damos_access_pattern pattern;enum damos_action action;unsigned long apply_interval_us; +struct damos_quota quota; +struct damos_watermarks wmarks; +union { +struct { +int target_nid; +struct damos_migrate_dests migrate_dests; + }; + }; +struct damos_stat stat; +unsigned long max_nr_snapshots;/* private: internal use only */ /* * number of sample intervals that should be passed before applying
@@ -585,20 +582,25 @@ struct damos {/* whether to reject core/ops filters umatched regions */ bool core_filters_default_reject;bool ops_filters_default_reject; -/* public: */ -struct damos_quota quota; -struct damos_watermarks wmarks; -union { -struct { -int target_nid; -struct damos_migrate_dests migrate_dests; - }; - }; +/* Additional set of &struct damos_filter for &action. */ struct list_head core_filters; +/* ops layer handling &struct damos_filter objects list. */ struct list_head ops_filters; +/* +* Last @action applied ops-managing entity. +* +* The minimum entity that @action can be applied depends on the +* underlying &struct damon_operations. Since it may not be aligned +* with the core layer abstract, namely &struct damon_region, &struct +* damon_operations could apply @action to same entity multiple times. +* Large folios that underlying on multiple &struct damon region +* objects could be such examples. The &struct damon_operations can +* use @last_applied to avoid that. DAMOS core logic unsets +* @last_applied when each regions walking for applying the scheme is +* finished. +*/ void *last_applied; -struct damos_stat stat; -unsigned long max_nr_snapshots; +/* List head for siblings. */ struct list_head list; };
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [RFC PATCH 06/10] mm/damon/core: hide private damos fields
Thank 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] struct damos->last_applied is left uninitialized upon allocation in damon_new_scheme(), leading to a potential read of uninitialized memory during the first scheme application. --
--- Patch [6]: [RFC PATCH 06/10] mm/damon/core: hide private damos fields ---
Note: The format of this report has been altered to provide a free-form summary instead of quoting the original patch code directly, due to system recitation restrictions.
commit 74f6565901cd9e992427e68af079cc1885de502e
Author: SJ Park <[email protected]>mm/damon/core: hide private damos fields
This commit updates struct damos to hide several fields intended only for the DAMON core layer by moving them under a private comment block.
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the changes to the last_applied field, I noticed a potential uninitialized memory read.
In mm/damon/core.c:damon_new_scheme(), a new struct damos is allocated using a non-zeroing kmalloc variant. While several fields are explicitly initialized in this function, the last_applied pointer is skipped and left uninitialized.
When kdamond_apply_schemes() performs the very first region walk, it calls into operations layers like mm/damon/paddr.c:damon_pa_invalid_damos_folio() before last_applied is ever cleared to NULL.
This causes damon_pa_invalid_damos_folio() to read the uninitialized heap value and compare it against the valid folio pointer currently being walked.
If a local user configures DAMON and the uninitialized heap memory happens to match a valid folio pointer being walked, could this result in an erroneous folio_put() being executed prematurely? Does this open up an exploitable use-after-free vulnerability during the initial scheme application?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
SJ Park
maintainerRe: [RFC PATCH 06/10] mm/damon/core: hide private damos fields
Quoted 35 lines · On Tue, 14 Jul 2026 04:52:40 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High]struct damos->last_appliedis left uninitialized upon allocation indamon_new_scheme(), leading to a potential read of uninitialized memory during the first scheme application. ----- Patch [6]: [RFC PATCH 06/10]
mm/damon/core: hide private damos fields ---
Note: The format of this report has been altered to provide a free-form summary instead of quoting the original patch code directly, due to system recitation restrictions.commit
74f6565901cd9e992427e68af079cc1885de502e
Author: SJ Park <[email protected]>mm/damon/core: hide private damos fieldsThis commit updates struct damos to hide several fields intended only for the DAMON core layer by moving them under a private comment block.
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the changes to thelast_appliedfield, I noticed a potential uninitialized memory read.In mm/damon/core.c:damon_new_scheme(), a new struct damos is allocated using a non-zeroing kmalloc variant. While several fields are explicitly initialized in this function, the
last_appliedpointer is skipped and left uninitialized.When
kdamond_apply_schemes()performs the very first region walk, it calls into operations layers like mm/damon/paddr.c:damon_pa_invalid_damos_folio() beforelast_appliedis ever cleared to NULL.This causes
damon_pa_invalid_damos_folio()to read the uninitialized heap value and compare it against the valid folio pointer currently being walked.
Quoted 5 lines
If a local user configures DAMON and the uninitialized heap memory happens to match a valid folio pointer being walked, could this result in an erroneous
folio_put()being executed prematurely? Does this open up an exploitable use-after-free vulnerability during the initial scheme application?
Good finding. I will separately work on this.
Quoted 3 lines
Signature · 2 lines
-- Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Thanks,
SJ
SJ Park
maintainerRe: [RFC PATCH 06/10] mm/damon/core: hide private damos fields
Quoted 37 lines · On Mon, 13 Jul 2026 22:54:50 -0700 SJ Park <[email protected]> wrote:
Quoted 35 lines · On Tue, 14 Jul 2026 04:52:40 +0000 [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High]struct damos->last_appliedis left uninitialized upon allocation indamon_new_scheme(), leading to a potential read of uninitialized memory during the first scheme application. ----- Patch [6]: [RFC PATCH 06/10]
mm/damon/core: hide private damos fields ---
Note: The format of this report has been altered to provide a free-form summary instead of quoting the original patch code directly, due to system recitation restrictions.commit
74f6565901cd9e992427e68af079cc1885de502e
Author: SJ Park <[email protected]>mm/damon/core: hide private damos fieldsThis commit updates struct damos to hide several fields intended only for the DAMON core layer by moving them under a private comment block.
[Severity: High]
This isn't a bug introduced by this patch, but while reviewing the changes to thelast_appliedfield, I noticed a potential uninitialized memory read.In mm/damon/core.c:damon_new_scheme(), a new struct damos is allocated using a non-zeroing kmalloc variant. While several fields are explicitly initialized in this function, the
last_appliedpointer is skipped and left uninitialized.When
kdamond_apply_schemes()performs the very first region walk, it calls into operations layers like mm/damon/paddr.c:damon_pa_invalid_damos_folio() beforelast_appliedis ever cleared to NULL.This causes
damon_pa_invalid_damos_folio()to read the uninitialized heap value and compare it against the valid folio pointer currently being walked.
Quoted 7 lines
Quoted 5 lines
If a local user configures DAMON and the uninitialized heap memory happens to match a valid folio pointer being walked, could this result in an erroneous
folio_put()being executed prematurely? Does this open up an exploitable use-after-free vulnerability during the initial scheme application?Good finding. I will separately work on this.
That said, the premature folio_put() and use-after-free cannot happen, because damon_pa_invalid_damos_folio() is called only for the folio that DAMON_PADDR has increased the reference. The consequence is just not applying DAMOS action to a valid folio, only once per DAMOS run, only if the uninitialized value matches the valid folio.
I think this is still better to be fixed as long as the fix is simple. Quite a mild issue, though.
Thanks,
SJ
[...]
SJ Park
maintainerRFC PATCH 7/10 mm/damon/core: hide private damon_filter fields
In reply to SJ Parkdamon_filter->list is intended to be used by only the DAMON core layer. However, it is mistakenly not marked as private. Mark as private.
--- include/linux/damon.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
include/linux/damon.h +2 -1
@@ -758,7 +758,6 @@ enum damon_filter_type {* @matching: Whether this filter is for the type-matching ones. * @allow: Whether the @type-@matching ones should pass this filter. * @memcg_id: Memcg id of the question if @type is DAMON_FILTER_MEMCG. -* @list: Siblings list. */ struct damon_filter {enum damon_filter_type type;
@@ -767,6 +766,8 @@ struct damon_filter {union {u64 memcg_id; }; +/* private: */ +/* Siblings list. */ struct list_head list; };
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 8/10 mm/damon/core: hide private damon_probe fields
In reply to SJ Park'filters' and 'list' fields of damon_probe are intended to be used by only the DAMON core layer. However, those are mistakenly not marked as private. Mark as private.
--- include/linux/damon.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
include/linux/damon.h +3 -2
@@ -775,12 +775,13 @@ struct damon_filter {* struct damon_probe - Data region attribute probe. * * @weight: Relative priority of the attribute for this probe. -* @filters: Filters for assessing if a given region is for this probe. -* @list: Siblings list. */ struct damon_probe {unsigned int weight; +/* private: */ +/* Filters for assessing if a given region is for this probe. */ struct list_head filters; +/* Siblings list. */ struct list_head list; };
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 9/10 mm/damon/sysfs: do not directly access damon_ctx->ops
In reply to SJ Parkdamon_ctx->ops field is intended to be used by only the DAMON core layer. DAMON_SYSFS is directly reading the field to find if it is for physical address monitoring, though. Use the API function for the purpose, damon_target_has_pid(), instead.
--- mm/damon/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/damon/sysfs.c +1 -1
@@ -2051,7 +2051,7 @@ static int damon_sysfs_add_targets(struct damon_ctx *ctx,int i, err;/* Multiple physical address space monitoring targets makes no sense */ -if (ctx->ops.id ==DAMON_OPS_PADDR && sysfs_targets->nr >1 ) +if (!damon_target_has_pid (ctx) && sysfs_targets->nr >1 )return -EINVAL ;for (i =0 ; i < sysfs_targets->nr; i++) {
Signature · 1 line
2.47.3
SJ Park
maintainerRFC PATCH 10/10 mm/damon/core: hide core-private damon_ctx fields
In reply to SJ Park'ops', 'probes', 'adaptive_targets', 'schemes', and 'rnd_state' fields of damon_ctx are intended to be used by only the DAMON core layer. However, those are mistakenly not marked as private. Mark as private.
--- include/linux/damon.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
include/linux/damon.h +8 -7
@@ -848,14 +848,9 @@ struct damon_attrs {* thread other than the kdamond should be made using safe DAMON APIs, * including damon_call() and damos_walk(). * -* @ops: Set of monitoring operations for given use cases. -* @probes: Head of probes (&damon_probe) list. * @addr_unit: Scale factor for core to ops address conversion. * @min_region_sz: Minimum region size. * @pause: Pause kdamond main loop. -* @adaptive_targets: Head of monitoring targets (&damon_target) list. -* @schemes: Head of schemes (&damos) list. -* @rnd_state: Per-ctx PRNG state for damon_rand(). */ struct damon_ctx {struct damon_attrs attrs;
@@ -904,15 +899,21 @@ struct damon_ctx {struct mutex kdamond_lock;/* public: */ -struct damon_operations ops; -struct list_head probes;unsigned long addr_unit;unsigned long min_region_sz;bool pause; +/* private: */ +/* Set of monitoring operations for given use cases. */ +struct damon_operations ops; +/* Head of monitoring targets (&damon_target) list. */ struct list_head adaptive_targets; +/* Head of probes (&damon_probe) list. */ +struct list_head probes; +/* Head of schemes (&damos) list. */ struct list_head schemes; +/* @rnd_state: Per-ctx PRNG state for damon_rand(). */ struct rnd_state rnd_state; };
Signature · 1 line
2.47.3