From: jackysliu 1972843537@qq.com
[ Upstream commit add4c4850363d7c1b72e8fce9ccb21fdd2cf5dc9 ]
When the bfad_im_probe() function fails during initialization, the memory pointed to by bfad->im is freed without setting bfad->im to NULL.
Subsequently, during driver uninstallation, when the state machine enters the bfad_sm_stopping state and calls the bfad_im_probe_undo() function, it attempts to free the memory pointed to by bfad->im again, thereby triggering a double-free vulnerability.
Set bfad->im to NULL if probing fails.
Signed-off-by: jackysliu 1972843537@qq.com Link: https://lore.kernel.org/r/tencent_3BB950D6D2D470976F55FC879206DE0B9A09@qq.co... Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
**Backport Status: YES**
This commit is a clear candidate for backporting to stable kernel trees. Here's my extensive analysis:
## Bug Analysis
The commit fixes a **critical double-free vulnerability** in the BFA (Brocade Fibre Channel Adapter) SCSI driver. The issue occurs in the following scenario:
1. During driver initialization, `bfad_im_probe()` allocates memory for `bfad->im` (line 700: `im = kzalloc(sizeof(struct bfad_im_s), GFP_KERNEL)`) 2. The pointer is assigned to `bfad->im` (line 704: `bfad->im = im`) 3. If `bfad_thread_workq()` fails (line 707), the function frees the memory (line 708: `kfree(im)`) but **fails to set `bfad->im = NULL`** 4. Later, during driver uninstallation, when the state machine enters `bfad_sm_stopping` state, it calls `bfad_im_probe_undo()` (line 714 in bfad.c) 5. `bfad_im_probe_undo()` checks `if (bfad->im)` (line 720) and since the pointer wasn't nulled, it attempts to free the already-freed memory again (line 722: `kfree(bfad->im)`)
## Why This Should Be Backported
1. **Security Impact**: Double-free vulnerabilities can lead to memory corruption, system crashes, and potentially be exploited for privilege escalation. This is a real security issue.
2. **Simple Fix**: The fix is minimal - just a single line addition (`bfad->im = NULL;`) after the `kfree(im)` call. This follows the exact same pattern already used in `bfad_im_probe_undo()` where after freeing, the pointer is set to NULL (line 723).
3. **Clear Bug**: The bug is straightforward - the code inconsistently handles the cleanup path. The fix makes it consistent with the cleanup function's expectations.
4. **Limited Scope**: The change is confined to error handling in a single function (`bfad_im_probe()`). It doesn't modify any normal operation paths or introduce new features.
5. **Low Risk**: Setting a pointer to NULL after freeing is a standard defensive programming practice with essentially zero risk of regression.
6. **Affects Users**: Any system using Brocade Fibre Channel adapters could hit this issue if the driver initialization fails (e.g., due to memory allocation failure in `bfad_thread_workq()`).
7. **Follows Stable Rules**: The commit: - Fixes a real bug (double-free vulnerability) - Is small and contained (1 line change) - Has clear causality - Doesn't introduce new features - Has minimal risk of causing regressions
The commit follows the Linux stable kernel rules perfectly - it's a small, obvious fix for a real bug that could affect users in production environments.
drivers/scsi/bfa/bfad_im.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index a719a18f0fbc..f56e008ee52b 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -706,6 +706,7 @@ bfad_im_probe(struct bfad_s *bfad)
if (bfad_thread_workq(bfad) != BFA_STATUS_OK) { kfree(im); + bfad->im = NULL; return BFA_STATUS_FAILED; }