* [PATCH] fbdev:modedb: fix a possible UAF in fb_find_mode()
@ 2026-05-26 9:15 Tuo Li
2026-05-27 5:06 ` Claude review: " Claude Code Review Bot
2026-05-27 5:06 ` Claude Code Review Bot
0 siblings, 2 replies; 3+ messages in thread
From: Tuo Li @ 2026-05-26 9:15 UTC (permalink / raw)
To: simona, deller, kees, tzimmermann
Cc: linux-fbdev, dri-devel, linux-kernel, Tuo Li
If mode_option is NULL, it is assigned from mode_option_buf:
if (!mode_option) {
fb_get_options(NULL, &mode_option_buf);
mode_option = mode_option_buf;
}
Later, name is assigned from mode_option:
const char *name = mode_option;
However, mode_option_buf is freed before name is no longer used:
kfree(mode_option_buf);
while name is still accessed by:
if ((name_matches(db[i], name, namelen) ||
Since name aliases mode_option_buf, this may result in a
use-after-free.
Fix this by moving the kfree(mode_option_buf) call behind the access, and
add corresponding cleanup before early returns.
Signed-off-by: Tuo Li <islituo@gmail.com>
---
drivers/video/fbdev/core/modedb.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c
index 703d0b7aec32..91f6c78f9e19 100644
--- a/drivers/video/fbdev/core/modedb.c
+++ b/drivers/video/fbdev/core/modedb.c
@@ -724,7 +724,6 @@ int fb_find_mode(struct fb_var_screeninfo *var,
res_specified = 1;
}
done:
- kfree(mode_option_buf);
if (cvt) {
struct fb_videomode cvt_mode;
int ret;
@@ -749,6 +748,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
DPRINTK("modedb CVT: CVT mode ok\n");
+ kfree(mode_option_buf);
return 1;
}
@@ -793,8 +793,10 @@ int fb_find_mode(struct fb_var_screeninfo *var,
if (!interlace_specified ||
db_interlace == interlace)
if (refresh_specified &&
- db[i].refresh == refresh)
+ db[i].refresh == refresh) {
+ kfree(mode_option_buf);
return 1;
+ }
if (score < diff) {
diff = score;
@@ -802,6 +804,8 @@ int fb_find_mode(struct fb_var_screeninfo *var,
}
}
}
+
+ kfree(mode_option_buf);
if (best != -1) {
fb_try_mode(var, info, &db[best], bpp);
return (refresh_specified) ? 2 : 1;
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Claude review: fbdev:modedb: fix a possible UAF in fb_find_mode()
2026-05-26 9:15 [PATCH] fbdev:modedb: fix a possible UAF in fb_find_mode() Tuo Li
@ 2026-05-27 5:06 ` Claude Code Review Bot
2026-05-27 5:06 ` Claude Code Review Bot
1 sibling, 0 replies; 3+ messages in thread
From: Claude Code Review Bot @ 2026-05-27 5:06 UTC (permalink / raw)
To: dri-devel-reviews
Overall Series Review
Subject: fbdev:modedb: fix a possible UAF in fb_find_mode()
Author: Tuo Li <islituo@gmail.com>
Patches: 1
Reviewed: 2026-05-27T15:06:24.893069
---
This is a single patch claiming to fix a use-after-free (UAF) in `fb_find_mode()`. The claimed bug is that `mode_option_buf` (a `kstrdup`'d buffer from `fb_get_options`) is freed while the pointer `name`, which aliases it, is still in use.
**The bug claim is valid in the original code.** In the original code, `kfree(mode_option_buf)` was placed at the `done:` label, immediately before the CVT path and the database-search loop. The `name` pointer (which may alias `mode_option_buf`) is then used in the `name_matches()` call at line 783. This is a genuine UAF when `mode_option` was originally NULL and got populated from `fb_get_options`.
**However, the fix is incomplete and introduces new bugs.** It misses several return paths that still leak `mode_option_buf`.
---
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 3+ messages in thread
* Claude review: fbdev:modedb: fix a possible UAF in fb_find_mode()
2026-05-26 9:15 [PATCH] fbdev:modedb: fix a possible UAF in fb_find_mode() Tuo Li
2026-05-27 5:06 ` Claude review: " Claude Code Review Bot
@ 2026-05-27 5:06 ` Claude Code Review Bot
1 sibling, 0 replies; 3+ messages in thread
From: Claude Code Review Bot @ 2026-05-27 5:06 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
**The bug diagnosis is correct.** The original `kfree(mode_option_buf)` at `done:` (line 726 pre-patch) frees the buffer before `name` is used in the loop at line 783 (`name_matches(db[i], name, namelen)`). Since `name = mode_option` and `mode_option` may point to `mode_option_buf`, this is a real UAF.
**Issue 1: Missing kfree on multiple remaining return paths (memory leak)**
The patch adds `kfree(mode_option_buf)` before three return points:
1. The CVT success return at line 751
2. The exact-refresh-match return at line 797
3. Before the `best != -1` check at line 808
But it **misses** these return paths that still leak:
- **Line 838** (`return 5`): The "best-fit modes" fallback return. If execution reaches the second best-fit loop and finds a match, `mode_option_buf` is leaked.
```c
if (best != -1) {
fb_try_mode(var, info, &db[best], bpp);
return 5; // <-- mode_option_buf leaked here
}
```
- **Line 844** (`return 3`): Default mode path — after the `if (mode_option)` block closes at line 840, the function tries the default mode. If mode_option was NULL (so `mode_option_buf` was allocated), but the parsing inside `if (mode_option)` still ran, this path is actually unreachable since `mode_option` would be non-NULL if `mode_option_buf` was allocated. However, if `fb_get_options` sets `*option = NULL` (which it does when `options` is NULL), then `mode_option_buf` stays NULL and `mode_option` stays NULL, so the `if (mode_option)` block is skipped entirely. In that case `mode_option_buf` is NULL and `kfree(NULL)` is a no-op, so this is fine.
- **Line 811** (`return (refresh_specified) ? 2 : 1`): This is the path where `best != -1` after the first database loop. The patch places `kfree` just before this check at line 808, so this path **is** covered. Good.
So the substantive miss is the `return 5` at line 838.
**Issue 2: Fragile and error-prone approach**
The fundamental approach of sprinkling `kfree()` before each `return` statement is fragile and error-prone. The standard kernel pattern for this is to use a single cleanup label (`goto out` / `goto free`) and route all returns through it. This would be cleaner and less bug-prone:
```c
int ret = 0;
...
/* at each early return, instead of return N: */
ret = 1;
goto out;
...
out:
kfree(mode_option_buf);
return ret;
```
However, this function has returns both inside and outside the `if (mode_option)` block, and the returns outside that block don't need the free (since `mode_option_buf` can only be non-NULL inside). A simpler alternative: move the `kfree` to just before line 840 (closing brace of `if (mode_option)`) and also keep it before the early returns within that block. But even simpler: just defer the free to the end of the function since `kfree(NULL)` is safe, and route all returns through a cleanup label.
**Issue 3: Commit message inaccuracy**
The commit message says "fix a possible UAF" but the fix introduces a memory leak on the `return 5` path, so it trades one bug for another (albeit a less severe one — leak vs. UAF).
**Summary:** The bug identification is correct, but the fix is incomplete. Recommend NAK and request the author use a `goto`-based cleanup pattern to catch all return paths.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-27 5:06 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-26 9:15 [PATCH] fbdev:modedb: fix a possible UAF in fb_find_mode() Tuo Li
2026-05-27 5:06 ` Claude review: " Claude Code Review Bot
2026-05-27 5:06 ` Claude Code Review Bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox