[PATCH -next 1/3] cgroup/dmem: fix NULL pointer dereference when setting max

Chen Ridong posted 3 patches 1 week, 3 days ago
There is a newer version of this series
[PATCH -next 1/3] cgroup/dmem: fix NULL pointer dereference when setting max
Posted by Chen Ridong 1 week, 3 days ago
From: Chen Ridong <chenridong@huawei.com>

An issue was triggered:

 BUG: kernel NULL pointer dereference, address: 0000000000000000
 #PF: supervisor read access in kernel mode
 #PF: error_code(0x0000) - not-present page
 PGD 0 P4D 0
 Oops: Oops: 0000 [#1] SMP NOPTI
 CPU: 15 UID: 0 PID: 658 Comm: bash Tainted: 6.19.0-rc6-next-2026012
 Tainted: [O]=OOT_MODULE
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
 RIP: 0010:strcmp+0x10/0x30
 RSP: 0018:ffffc900017f7dc0 EFLAGS: 00000246
 RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff888107cd4358
 RDX: 0000000019f73907 RSI: ffffffff82cc381a RDI: 0000000000000000
 RBP: ffff8881016bef0d R08: 000000006c0e7145 R09: 0000000056c0e714
 R10: 0000000000000001 R11: ffff888107cd4358 R12: 0007ffffffffffff
 R13: ffff888101399200 R14: ffff888100fcb360 R15: 0007ffffffffffff
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 0000000000000000 CR3: 0000000105c79000 CR4: 00000000000006f0
 Call Trace:
  <TASK>
  dmemcg_limit_write.constprop.0+0x16d/0x390
  ? __pfx_set_resource_max+0x10/0x10
  kernfs_fop_write_iter+0x14e/0x200
  vfs_write+0x367/0x510
  ksys_write+0x66/0xe0
  do_syscall_64+0x6b/0x390
  entry_SYSCALL_64_after_hwframe+0x76/0x7e
 RIP: 0033:0x7f42697e1887

It was trriggered setting max without limitation, the command is like:
"echo test/region0 > dmem.max". To fix this issue, add check whether
options is valid after parsing the region_name.

Fixes: b168ed458dde ("kernel/cgroup: Add "dmem" memory accounting cgroup")
Signed-off-by: Chen Ridong <chenridong@huawei.com>
---
 kernel/cgroup/dmem.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index e12b946278b6..30f96627860c 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -700,6 +700,11 @@ static ssize_t dmemcg_limit_write(struct kernfs_open_file *of,
 		if (!region_name[0])
 			continue;
 
+		if (!options || !*options) {
+			err = -EINVAL;
+			goto out_put;
+		}
+
 		rcu_read_lock();
 		region = dmemcg_get_region_by_name(region_name);
 		rcu_read_unlock();
-- 
2.34.1
Re: [PATCH -next 1/3] cgroup/dmem: fix NULL pointer dereference when setting max
Posted by kernel test robot 1 week, 2 days ago
Hi Chen,

kernel test robot noticed the following build warnings:

[auto build test WARNING on next-20260130]

url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Ridong/cgroup-dmem-fix-NULL-pointer-dereference-when-setting-max/20260131-173002
base:   next-20260130
patch link:    https://lore.kernel.org/r/20260131091202.344788-2-chenridong%40huaweicloud.com
patch subject: [PATCH -next 1/3] cgroup/dmem: fix NULL pointer dereference when setting max
config: x86_64-randconfig-161-20260131 (https://download.01.org/0day-ci/archive/20260201/202602010100.5CjcoPFh-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
smatch version: v0.5.0-8994-gd50c5a4c
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260201/202602010100.5CjcoPFh-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602010100.5CjcoPFh-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> kernel/cgroup/dmem.c:703:7: warning: variable 'region' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
     703 |                 if (!options || !*options) {
         |                     ^~~~~~~~~~~~~~~~~~~~~
   kernel/cgroup/dmem.c:729:13: note: uninitialized use occurs here
     729 |                 kref_put(&region->ref, dmemcg_free_region);
         |                           ^~~~~~
   kernel/cgroup/dmem.c:703:3: note: remove the 'if' if its condition is always false
     703 |                 if (!options || !*options) {
         |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
     704 |                         err = -EINVAL;
         |                         ~~~~~~~~~~~~~~
     705 |                         goto out_put;
         |                         ~~~~~~~~~~~~~
     706 |                 }
         |                 ~
>> kernel/cgroup/dmem.c:703:7: warning: variable 'region' is used uninitialized whenever '||' condition is true [-Wsometimes-uninitialized]
     703 |                 if (!options || !*options) {
         |                     ^~~~~~~~
   kernel/cgroup/dmem.c:729:13: note: uninitialized use occurs here
     729 |                 kref_put(&region->ref, dmemcg_free_region);
         |                           ^~~~~~
   kernel/cgroup/dmem.c:703:7: note: remove the '||' if its condition is always false
     703 |                 if (!options || !*options) {
         |                     ^~~~~~~~~~~
   kernel/cgroup/dmem.c:685:36: note: initialize the variable 'region' to silence this warning
     685 |                 struct dmem_cgroup_region *region;
         |                                                  ^
         |                                                   = NULL
   2 warnings generated.


vim +703 kernel/cgroup/dmem.c

   674	
   675	static ssize_t dmemcg_limit_write(struct kernfs_open_file *of,
   676					 char *buf, size_t nbytes, loff_t off,
   677					 void (*apply)(struct dmem_cgroup_pool_state *, u64))
   678	{
   679		struct dmemcg_state *dmemcs = css_to_dmemcs(of_css(of));
   680		int err = 0;
   681	
   682		while (buf && !err) {
   683			struct dmem_cgroup_pool_state *pool = NULL;
   684			char *options, *region_name;
   685			struct dmem_cgroup_region *region;
   686			u64 new_limit;
   687	
   688			options = buf;
   689			buf = strchr(buf, '\n');
   690			if (buf)
   691				*buf++ = '\0';
   692	
   693			options = strstrip(options);
   694	
   695			/* eat empty lines */
   696			if (!options[0])
   697				continue;
   698	
   699			region_name = strsep(&options, " \t");
   700			if (!region_name[0])
   701				continue;
   702	
 > 703			if (!options || !*options) {
   704				err = -EINVAL;
   705				goto out_put;
   706			}
   707	
   708			rcu_read_lock();
   709			region = dmemcg_get_region_by_name(region_name);
   710			rcu_read_unlock();
   711	
   712			if (!region)
   713				return -EINVAL;
   714	
   715			err = dmemcg_parse_limit(options, region, &new_limit);
   716			if (err < 0)
   717				goto out_put;
   718	
   719			pool = get_cg_pool_unlocked(dmemcs, region);
   720			if (IS_ERR(pool)) {
   721				err = PTR_ERR(pool);
   722				goto out_put;
   723			}
   724	
   725			/* And commit */
   726			apply(pool, new_limit);
   727	
   728	out_put:
   729			kref_put(&region->ref, dmemcg_free_region);
   730		}
   731	
   732	
   733		return err ?: nbytes;
   734	}
   735	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH -next 1/3] cgroup/dmem: fix NULL pointer dereference when setting max
Posted by Chen Ridong 1 week, 1 day ago

On 2026/2/1 1:26, kernel test robot wrote:
> Hi Chen,
> 
> kernel test robot noticed the following build warnings:
> 
> [auto build test WARNING on next-20260130]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Ridong/cgroup-dmem-fix-NULL-pointer-dereference-when-setting-max/20260131-173002
> base:   next-20260130
> patch link:    https://lore.kernel.org/r/20260131091202.344788-2-chenridong%40huaweicloud.com
> patch subject: [PATCH -next 1/3] cgroup/dmem: fix NULL pointer dereference when setting max
> config: x86_64-randconfig-161-20260131 (https://download.01.org/0day-ci/archive/20260201/202602010100.5CjcoPFh-lkp@intel.com/config)
> compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
> smatch version: v0.5.0-8994-gd50c5a4c
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260201/202602010100.5CjcoPFh-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202602010100.5CjcoPFh-lkp@intel.com/
> 
> All warnings (new ones prefixed by >>):
> 
>>> kernel/cgroup/dmem.c:703:7: warning: variable 'region' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
>      703 |                 if (!options || !*options) {
>          |                     ^~~~~~~~~~~~~~~~~~~~~
>    kernel/cgroup/dmem.c:729:13: note: uninitialized use occurs here
>      729 |                 kref_put(&region->ref, dmemcg_free_region);
>          |                           ^~~~~~
>    kernel/cgroup/dmem.c:703:3: note: remove the 'if' if its condition is always false
>      703 |                 if (!options || !*options) {
>          |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>      704 |                         err = -EINVAL;
>          |                         ~~~~~~~~~~~~~~
>      705 |                         goto out_put;
>          |                         ~~~~~~~~~~~~~
>      706 |                 }
>          |                 ~
>>> kernel/cgroup/dmem.c:703:7: warning: variable 'region' is used uninitialized whenever '||' condition is true [-Wsometimes-uninitialized]
>      703 |                 if (!options || !*options) {
>          |                     ^~~~~~~~
>    kernel/cgroup/dmem.c:729:13: note: uninitialized use occurs here
>      729 |                 kref_put(&region->ref, dmemcg_free_region);
>          |                           ^~~~~~
>    kernel/cgroup/dmem.c:703:7: note: remove the '||' if its condition is always false
>      703 |                 if (!options || !*options) {
>          |                     ^~~~~~~~~~~
>    kernel/cgroup/dmem.c:685:36: note: initialize the variable 'region' to silence this warning
>      685 |                 struct dmem_cgroup_region *region;
>          |                                                  ^
>          |                                                   = NULL
>    2 warnings generated.
> 
> 
> vim +703 kernel/cgroup/dmem.c
> 
>    674	
>    675	static ssize_t dmemcg_limit_write(struct kernfs_open_file *of,
>    676					 char *buf, size_t nbytes, loff_t off,
>    677					 void (*apply)(struct dmem_cgroup_pool_state *, u64))
>    678	{
>    679		struct dmemcg_state *dmemcs = css_to_dmemcs(of_css(of));
>    680		int err = 0;
>    681	
>    682		while (buf && !err) {
>    683			struct dmem_cgroup_pool_state *pool = NULL;
>    684			char *options, *region_name;
>    685			struct dmem_cgroup_region *region;
>    686			u64 new_limit;
>    687	
>    688			options = buf;
>    689			buf = strchr(buf, '\n');
>    690			if (buf)
>    691				*buf++ = '\0';
>    692	
>    693			options = strstrip(options);
>    694	
>    695			/* eat empty lines */
>    696			if (!options[0])
>    697				continue;
>    698	
>    699			region_name = strsep(&options, " \t");
>    700			if (!region_name[0])
>    701				continue;
>    702	
>  > 703			if (!options || !*options) {
>    704				err = -EINVAL;
>    705				goto out_put;
>    706			}
>    707	

Thanks.

I missed that region is uninitialized. It could just return -EINVAL.
I'll fix it in the next version. If anyone has other opinions, I would like to
update together.

>    708			rcu_read_lock();
>    709			region = dmemcg_get_region_by_name(region_name);
>    710			rcu_read_unlock();
>    711	
>    712			if (!region)
>    713				return -EINVAL;
>    714	
>    715			err = dmemcg_parse_limit(options, region, &new_limit);
>    716			if (err < 0)
>    717				goto out_put;
>    718	
>    719			pool = get_cg_pool_unlocked(dmemcs, region);
>    720			if (IS_ERR(pool)) {
>    721				err = PTR_ERR(pool);
>    722				goto out_put;
>    723			}
>    724	
>    725			/* And commit */
>    726			apply(pool, new_limit);
>    727	
>    728	out_put:
>    729			kref_put(&region->ref, dmemcg_free_region);
>    730		}
>    731	
>    732	
>    733		return err ?: nbytes;
>    734	}
>    735	
> 

-- 
Best regards,
Ridong