From 0923efc7df209ddc774e3dedb51461ca57d8d91e Mon Sep 17 00:00:00 2001 From: Li Ruilin Date: Wed, 17 Dec 2025 17:30:49 +0800 Subject: [PATCH 1/3] obmm: Fix race condition of region release and device release euleros inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IDBKX6 CVE: NA ------------------------------------- Due to the Linux inode cache mechanism, the release callback of the device embedded in an OBMM region might execute after the region itself has been freed with kfree(region) . This creates a potential use-after-free vulnerability, as the callback would be operating on already deallocated memory. To address this, we need to implement a proper synchronization mechanism to ensure the region memory is only freed after the device release callback has completed execution. Fixes: b100600e5c18 ("obmm: Add shared memory device interface") Signed-off-by: Li Ruilin --- drivers/ub/obmm/obmm_core.h | 1 + drivers/ub/obmm/obmm_export.c | 2 ++ drivers/ub/obmm/obmm_export_from_pool.c | 2 ++ drivers/ub/obmm/obmm_export_from_user.c | 2 ++ drivers/ub/obmm/obmm_import.c | 5 +++++ drivers/ub/obmm/obmm_shm_dev.c | 11 +++++++++++ drivers/ub/obmm/obmm_shm_dev.h | 2 ++ 7 files changed, 25 insertions(+) diff --git a/drivers/ub/obmm/obmm_core.h b/drivers/ub/obmm/obmm_core.h index 4d844334dbad..ff3e717754ef 100644 --- a/drivers/ub/obmm/obmm_core.h +++ b/drivers/ub/obmm/obmm_core.h @@ -87,6 +87,7 @@ struct obmm_region { struct cdev cdevice; struct device device; + atomic_t device_released; refcount_t refcnt; diff --git a/drivers/ub/obmm/obmm_export.c b/drivers/ub/obmm/obmm_export.c index e1ec90cf15dd..237eb1e122f9 100644 --- a/drivers/ub/obmm/obmm_export.c +++ b/drivers/ub/obmm/obmm_export.c @@ -25,6 +25,7 @@ #include "obmm_core.h" #include "obmm_cache.h" #include "obmm_export.h" +#include "obmm_shm_dev.h" int export_flags_to_region_flags(unsigned long *region_flags, unsigned long user_flags) { @@ -266,6 +267,7 @@ int set_export_vendor(struct obmm_export_region *e_reg, const void __user *vendo void free_export_region(struct obmm_export_region *e_reg) { + wait_until_dev_released(&e_reg->region); if (e_reg->vendor_len) kfree(e_reg->vendor_info); diff --git a/drivers/ub/obmm/obmm_export_from_pool.c b/drivers/ub/obmm/obmm_export_from_pool.c index dabf5373ea2c..daa4214955da 100644 --- a/drivers/ub/obmm/obmm_export_from_pool.c +++ b/drivers/ub/obmm/obmm_export_from_pool.c @@ -255,6 +255,8 @@ static struct obmm_export_region *alloc_region_from_cmd(struct obmm_cmd_export * if (e_reg == NULL) return ERR_PTR(-ENOMEM); + atomic_set(&e_reg->region.device_released, 1); + e_reg->region.type = OBMM_EXPORT_REGION; e_reg->region.mem_size = total_size; e_reg->region.mem_cap = OBMM_MEM_ALLOW_CACHEABLE_MMAP | OBMM_MEM_ALLOW_NONCACHEABLE_MMAP; diff --git a/drivers/ub/obmm/obmm_export_from_user.c b/drivers/ub/obmm/obmm_export_from_user.c index bd0663bb197f..94e1c85b7190 100644 --- a/drivers/ub/obmm/obmm_export_from_user.c +++ b/drivers/ub/obmm/obmm_export_from_user.c @@ -279,6 +279,8 @@ alloc_export_region_from_obmm_cmd_export_pid(const struct obmm_cmd_export_pid *e if (e_reg == NULL) return ERR_PTR(-ENOMEM); + atomic_set(&e_reg->region.device_released, 1); + e_reg->mem_desc_pid.pid = export_pid->pid; e_reg->mem_desc_pid.user_va = export_pid->va; e_reg->region.mem_size = export_pid->length; diff --git a/drivers/ub/obmm/obmm_import.c b/drivers/ub/obmm/obmm_import.c index 18f59efa90c6..4a56a86f68f2 100644 --- a/drivers/ub/obmm/obmm_import.c +++ b/drivers/ub/obmm/obmm_import.c @@ -16,6 +16,7 @@ #include "obmm_preimport.h" #include "obmm_resource.h" #include "obmm_addr_check.h" +#include "obmm_shm_dev.h" static void set_import_region_datapath(const struct obmm_import_region *i_reg, struct obmm_datapath *datapath) @@ -415,6 +416,8 @@ int obmm_import(struct obmm_cmd_import *cmd_import) if (i_reg == NULL) return -ENOMEM; + atomic_set(&i_reg->region.device_released, 1); + /* arguments to region (logs produced by callee) */ retval = init_import_region_from_cmd(cmd_import, i_reg); if (retval) @@ -455,6 +458,7 @@ int obmm_import(struct obmm_cmd_import *cmd_import) out_region_uninit: uninit_obmm_region(&i_reg->region); out_free_ireg: + wait_until_dev_released(&i_reg->region); kfree(i_reg); return retval; } @@ -493,6 +497,7 @@ int obmm_unimport(const struct obmm_cmd_unimport *cmd_unimport) deregister_obmm_region(reg); uninit_obmm_region(reg); + wait_until_dev_released(&i_reg->region); kfree(i_reg); pr_info("%s: mem_id=%llu completed.\n", __func__, cmd_unimport->mem_id); diff --git a/drivers/ub/obmm/obmm_shm_dev.c b/drivers/ub/obmm/obmm_shm_dev.c index 0272287fea64..81b4b9d86bce 100644 --- a/drivers/ub/obmm/obmm_shm_dev.c +++ b/drivers/ub/obmm/obmm_shm_dev.c @@ -881,9 +881,18 @@ const struct file_operations obmm_shm_fops = { .owner = THIS_MODULE, static void obmm_shm_dev_release(struct device *dev) { + struct obmm_region *reg = container_of(dev, struct obmm_region, device); + + atomic_set(®->device_released, 1); module_put(THIS_MODULE); } +void wait_until_dev_released(struct obmm_region *reg) +{ + while (atomic_read(®->device_released) == 0) + cpu_relax(); +} + int obmm_shm_dev_add(struct obmm_region *reg) { int ret; @@ -918,6 +927,8 @@ int obmm_shm_dev_add(struct obmm_region *reg) goto err_put_dev; } + atomic_set(®->device_released, 0); + return 0; /* NOTE: If the device is properly initialized, the refcount of module diff --git a/drivers/ub/obmm/obmm_shm_dev.h b/drivers/ub/obmm/obmm_shm_dev.h index bfced747a2aa..e0bf3553a3ce 100644 --- a/drivers/ub/obmm/obmm_shm_dev.h +++ b/drivers/ub/obmm/obmm_shm_dev.h @@ -12,5 +12,7 @@ int obmm_shm_dev_init(void); void obmm_shm_dev_exit(void); int obmm_shm_dev_add(struct obmm_region *reg); void obmm_shm_dev_del(struct obmm_region *reg); +void wait_until_dev_released(struct obmm_region *reg); + #endif -- Gitee From 43087a8da5cc9401bc461906e47e3e28aeb312a8 Mon Sep 17 00:00:00 2001 From: Li Ruilin Date: Wed, 17 Dec 2025 18:17:41 +0800 Subject: [PATCH 2/3] obmm: Rollback mmap_granu when mmap failed euleros inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IDBKX6 CVE: NA ------------------------------------- During the mmap() handling, there's an oversight in the error recovery path for the mmap_granu field. When initializing a memory region, the code sets reg->mmap_granu to the requested granularity (either PAGE or PMD) but fails to revert this setting if the mapping operation encounters an error. This creates a persistent state where the region is marked as using a specific granularity, even though the actual mapping failed. This issue breaks the expected behavior where failed mapping attempts should not prevent users from retrying with different mapping parameters. Implementing proper rollback of the mmap_granu field in error paths would resolve this limitation. Fixes: 49ddfaab9aa3 ("obmm: Add mmap support for shared memory regions") Signed-off-by: Li Ruilin --- drivers/ub/obmm/obmm_shm_dev.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/ub/obmm/obmm_shm_dev.c b/drivers/ub/obmm/obmm_shm_dev.c index 81b4b9d86bce..0814c37d12b4 100644 --- a/drivers/ub/obmm/obmm_shm_dev.c +++ b/drivers/ub/obmm/obmm_shm_dev.c @@ -310,7 +310,7 @@ static int obmm_shm_fops_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size, offset; uint8_t mem_state; enum obmm_mmap_mode old_mmap_mode; - enum obmm_mmap_granu mmap_granu; + enum obmm_mmap_granu mmap_granu, init_mmap_granu; int ret; bool cacheable, o_sync; @@ -331,21 +331,23 @@ static int obmm_shm_fops_mmap(struct file *file, struct vm_area_struct *vma) if (offset & OBMM_MMAP_FLAG_HUGETLB_PMD) { pr_debug("trying hugepage mmap\n"); - mmap_granu = OBMM_MMAP_GRANU_PMD; offset &= ~OBMM_MMAP_FLAG_HUGETLB_PMD; if (vma->vm_start % PMD_SIZE || vma->vm_end % PMD_SIZE) { pr_err("error running huge mmap for not pmd-aligned vma: %#lx-%#lx\n", vma->vm_start, vma->vm_end); return -EINVAL; } + mmap_granu = OBMM_MMAP_GRANU_PMD; } else { mmap_granu = OBMM_MMAP_GRANU_PAGE; } + init_mmap_granu = reg->mmap_granu; if (reg->mmap_granu == OBMM_MMAP_GRANU_NONE) { reg->mmap_granu = mmap_granu; } else if (reg->mmap_granu != mmap_granu) { pr_err("map with PAGE_SIZE and PMD_SIZE granu should not be mixed on the same region\n"); - return -EINVAL; + ret = -EPERM; + goto err_reset_mmap_granu; } vma->vm_pgoff = offset >> PAGE_SHIFT; @@ -353,7 +355,8 @@ static int obmm_shm_fops_mmap(struct file *file, struct vm_area_struct *vma) if (offset >= reg->mem_size || size > reg->mem_size - offset) { pr_err("mmap region %d: offset:%#lx, size:%#lx over region size: %#llx", reg->regionid, offset, size, reg->mem_size); - return -EINVAL; + ret = -EINVAL; + goto err_reset_mmap_granu; } /* @@ -404,6 +407,11 @@ static int obmm_shm_fops_mmap(struct file *file, struct vm_area_struct *vma) ret = init_ownership_info(reg); if (ret) goto err_release_local_state_info; + /* + * after ownership_info initialized, mmap_granu should not be + * reset to OBMM_MMAP_GRANU_NONE. + */ + init_mmap_granu = reg->mmap_granu; ret = check_mmap_allowed(reg, vma, mem_state); if (ret) goto err_release_local_state_info; @@ -454,6 +462,8 @@ static int obmm_shm_fops_mmap(struct file *file, struct vm_area_struct *vma) reg->mmap_mode = OBMM_MMAP_INIT; err_mutex_unlock: mutex_unlock(®->state_mutex); +err_reset_mmap_granu: + reg->mmap_granu = init_mmap_granu; return ret; } -- Gitee From a2b968884d48555aed651ebebe79e95726777bf4 Mon Sep 17 00:00:00 2001 From: Li Ruilin Date: Wed, 17 Dec 2025 18:30:43 +0800 Subject: [PATCH 3/3] obmm: Add FAST flag check for obmm_export_from_user euleros inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IDBKX6 CVE: NA ------------------------------------- The "FAST" flag does not actually take effect in the export_from_user function. Validation for this flag in the user input parameters needs to be added. Fixes: 2a3becabc966 ("obmm: Add user address export support") Signed-off-by: Li Ruilin --- drivers/ub/obmm/obmm_export_from_user.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ub/obmm/obmm_export_from_user.c b/drivers/ub/obmm/obmm_export_from_user.c index 94e1c85b7190..f136d3398753 100644 --- a/drivers/ub/obmm/obmm_export_from_user.c +++ b/drivers/ub/obmm/obmm_export_from_user.c @@ -255,6 +255,10 @@ static int obmm_cmd_export_pid_allowed(struct obmm_cmd_export_pid *cmd) pr_err("ALLOW_MMAP flag is not allowed in export_user_addr.\n"); return -EINVAL; } + if (cmd->flags & OBMM_EXPORT_FLAG_FAST) { + pr_err("FAST flag is not allowed in export_user_addr.\n"); + return -EINVAL; + } if (cmd->length == 0) { pr_err("export sizeof 0 memory is not allowed.\n"); -- Gitee