From 4269fdf58b097e330d40facfeea9465a86686193 Mon Sep 17 00:00:00 2001 From: Tony Asleson Date: Fri, 20 Mar 2026 23:35:01 -0500 Subject: [PATCH 1/2] bug: memleak in block_device_init Each time ledmon is looping we end up going through block_device_init which internally is calling _get_host. Get host returns a string that is on the heap and must be freed. It is being freed in the error path, but not in the good path. Leak is dependent on the number of block devices. Signed-off-by: Tony Asleson --- src/lib/block.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/block.c b/src/lib/block.c index 77ec8419..36f12fc2 100644 --- a/src/lib/block.c +++ b/src/lib/block.c @@ -292,7 +292,7 @@ struct block_device *block_device_init(const struct list *cntrl_list, const char if (cntrl->cntrl_type == LED_CNTRL_TYPE_VMD && !vmdssd_find_pci_slot(cntrl->ctx, link)) goto error; - host = _get_host(link, cntrl); + host = _get_host(link, cntrl); //host is on the heap! if (host == NULL) goto error; host_name = get_path_hostN(link); @@ -340,6 +340,7 @@ struct block_device *block_device_init(const struct list *cntrl_list, const char } } + free(host); return device; error: free(host); From cb809bdcf5f33055e56c07363e704828ae58db62 Mon Sep 17 00:00:00 2001 From: Tony Asleson Date: Fri, 20 Mar 2026 23:53:15 -0500 Subject: [PATCH 2/2] bug: fix use-after-return in vmdssd_get_domain vmdssd_get_domain() returned a pointer into a stack-local buffer (real_domain_path) via strtok(basename(...)). The caller in cntrl_device_init() reads from this dangling pointer. Fix by returning a strdup'd copy and freeing it in the caller. This is likely working as the data on the stack isn't getting cleared/ overwritten. Signed-off-by: Tony Asleson --- src/lib/cntrl.c | 4 +++- src/lib/vmdssd.c | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib/cntrl.c b/src/lib/cntrl.c index db54c583..de2b057c 100644 --- a/src/lib/cntrl.c +++ b/src/lib/cntrl.c @@ -424,9 +424,11 @@ struct cntrl_device *cntrl_device_init(const char *path, struct led_ctx *ctx) if (type == LED_CNTRL_TYPE_VMD) { char *domain = vmdssd_get_domain(path); - if (domain != NULL) + if (domain != NULL) { snprintf(device->domain, PATH_MAX, "%s", domain); + free(domain); + } } device->cntrl_type = type; strncpy(device->sysfs_path, path, PATH_MAX - 1); diff --git a/src/lib/vmdssd.c b/src/lib/vmdssd.c index 59219cca..c50e276f 100644 --- a/src/lib/vmdssd.c +++ b/src/lib/vmdssd.c @@ -64,13 +64,18 @@ static char *get_slot_from_syspath(const char *path) char *vmdssd_get_domain(const char *path) { char domain_path[PATH_MAX], real_domain_path[PATH_MAX]; + char *tok; snprintf(domain_path, PATH_MAX, "%s/%s/domain", SYSFS_VMD, basename(path)); if (realpath(domain_path, real_domain_path) == NULL) return NULL; - return strtok(basename(real_domain_path), ":"); + tok = strtok(basename(real_domain_path), ":"); + if (!tok) + return NULL; + + return strdup(tok); } bool vmdssd_check_slot_module(struct led_ctx *ctx, const char *slot_path)