Skip to content

Commit 2538bd3

Browse files
Cen Zhangklassert
authored andcommitted
xfrm: clear mode callbacks after failed mode setup
xfrm_state_gc_task can run long after a failed IPTFS state setup. In the reproduced case, __xfrm_init_state() cached x->mode_cbs, IPTFS setup returned -ENOMEM before publishing mode_data, and the temporary module reference from xfrm_get_mode_cbs() was dropped immediately. The dead state then kept x->mode_cbs until deferred GC ran after xfrm_iptfs had been unloaded. Clear x->mode_cbs when mode init or clone fails before publishing mode_data. Those states never installed mode-specific state or the long-term IPTFS module pin, so deferred GC has nothing mode-specific to destroy and must not retain a callback table pointer past the temporary lookup reference. The buggy scenario involves two paths, with each column showing the order within that path: failed setup path: 1. cache x->mode_cbs 2. mode setup fails before mode_data 3. drop the temporary module ref 4. dead state keeps x->mode_cbs cached GC/unload path: 1. xfrm_state_put() queues GC work 2. xfrm_iptfs unloads later 3. xfrm_state_gc_task runs 4. GC dereferences stale x->mode_cbs This also covers the failed clone path where clone_state() returns before publishing mode_data. Validation reproduced this kernel report: Kernel panic - not syncing: Fatal exception CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y failslab_stacktrace_filter matched xfrm_iptfs frames ack_error=-12 FAULT_INJECTION: forcing a failure BUG: unable to handle page fault Workqueue: events xfrm_state_gc_task RIP: xfrm_state_gc_task+0x142/0x650 Modules linked in: esp4_offload xfrm_user [last unloaded: xfrm_iptfs] Kernel panic - not syncing: Fatal exception Fixes: 4b3faf6 ("xfrm: iptfs: add new iptfs xfrm mode impl") Assisted-by: Codex:gpt-5.5 Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
1 parent ea528f1 commit 2538bd3

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

net/xfrm/xfrm_state.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2072,8 +2072,11 @@ static struct xfrm_state *xfrm_state_clone_and_setup(struct xfrm_state *orig,
20722072

20732073
x->mode_cbs = orig->mode_cbs;
20742074
if (x->mode_cbs && x->mode_cbs->clone_state) {
2075-
if (x->mode_cbs->clone_state(x, orig))
2075+
if (x->mode_cbs->clone_state(x, orig)) {
2076+
if (!x->mode_data)
2077+
x->mode_cbs = NULL;
20762078
goto error;
2079+
}
20772080
}
20782081

20792082
x->props.reqid = m->new_reqid;
@@ -3292,6 +3295,8 @@ int __xfrm_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
32923295
if (x->mode_cbs->init_state)
32933296
err = x->mode_cbs->init_state(x);
32943297
module_put(x->mode_cbs->owner);
3298+
if (err && !x->mode_data)
3299+
x->mode_cbs = NULL;
32953300
}
32963301
error:
32973302
return err;

0 commit comments

Comments
 (0)