-
Notifications
You must be signed in to change notification settings - Fork 351
fast-get: fix crash by freeing buffer before removing partition #10585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -194,6 +194,7 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size) | |||||||||||||||||||||||||||||||
| int err = fast_get_access_grant(k_current_get(), ret, size); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (err < 0) { | ||||||||||||||||||||||||||||||||
| LOG_ERR("failed to grant additional access err=%d", err); | ||||||||||||||||||||||||||||||||
| ret = NULL; | ||||||||||||||||||||||||||||||||
| goto out; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
@@ -233,6 +234,7 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size) | |||||||||||||||||||||||||||||||
| int err = fast_get_access_grant(entry->thread, ret, size); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (err < 0) { | ||||||||||||||||||||||||||||||||
| LOG_ERR("failed to grant access err=%d", err); | ||||||||||||||||||||||||||||||||
| sof_heap_free(NULL, ret); | ||||||||||||||||||||||||||||||||
| ret = NULL; | ||||||||||||||||||||||||||||||||
| goto out; | ||||||||||||||||||||||||||||||||
|
|
@@ -277,21 +279,36 @@ void fast_put(struct k_heap *heap, const void *sram_ptr) | |||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| entry->refcount--; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!entry->refcount) { | ||||||||||||||||||||||||||||||||
| #if CONFIG_USERSPACE | ||||||||||||||||||||||||||||||||
| if (entry->size > FAST_GET_MAX_COPY_SIZE && entry->thread) { | ||||||||||||||||||||||||||||||||
| struct k_mem_partition part = { | ||||||||||||||||||||||||||||||||
| .start = (uintptr_t)entry->sram_ptr, | ||||||||||||||||||||||||||||||||
| .size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE), | ||||||||||||||||||||||||||||||||
| .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB, | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| LOG_DBG("remove %#zx @ %p", part.size, entry->sram_ptr); | ||||||||||||||||||||||||||||||||
| k_mem_domain_remove_partition(entry->thread->mem_domain_info.mem_domain, &part); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||
| /* For large buffers, we need to: | ||||||||||||||||||||||||||||||||
| * 1. Free the heap buffer FIRST (while partition still grants us access) | ||||||||||||||||||||||||||||||||
| * 2. Then remove the partition (to prevent partition leaks) | ||||||||||||||||||||||||||||||||
| * This order is critical - we must free while we still have access. | ||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||
| if (entry->size > FAST_GET_MAX_COPY_SIZE) { | ||||||||||||||||||||||||||||||||
| struct k_mem_partition part; | ||||||||||||||||||||||||||||||||
| struct k_mem_domain *domain = entry->thread->mem_domain_info.mem_domain; | ||||||||||||||||||||||||||||||||
| void *addr = entry->sram_ptr; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| sof_heap_free(heap, addr); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| part.start = (uintptr_t)addr; | ||||||||||||||||||||||||||||||||
| part.size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE); | ||||||||||||||||||||||||||||||||
| part.attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| int err = k_mem_domain_remove_partition(domain, &part); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (err < 0) | ||||||||||||||||||||||||||||||||
| LOG_WRN("partition removal failed err=%d", err); | ||||||||||||||||||||||||||||||||
|
Comment on lines
+302
to
+303
|
||||||||||||||||||||||||||||||||
| if (err < 0) | |
| LOG_WRN("partition removal failed err=%d", err); | |
| if (err == -ENOENT) { | |
| /* Partition already removed elsewhere; log for diagnostics. */ | |
| LOG_INF("partition not found for addr %p size %zu", addr, entry->size); | |
| } else if (err < 0) { | |
| /* | |
| * Unexpected failure: we have freed the heap buffer but | |
| * the memory-domain mapping may still exist. Treat this | |
| * as a hard error to avoid stale mappings to freed memory. | |
| */ | |
| LOG_ERR("partition removal failed err=%d addr=%p size=%zu", | |
| err, addr, entry->size); | |
| k_panic(); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says removing the partition prevents partition leaks, but
fast_get()can grant access (add partitions) to additional threads (see the additionalfast_get_access_grant(k_current_get(), ...)path).fast_put()currently only removes the partition fromentry->thread's domain, so partitions added to other threads will still leak. Either track/remove partitions for all threads that were granted access, or clarify the comment to match the actual behavior (owner-domain only).