Instances are refcounted. However, only memory release happens on the 1 -> 0 transition; the unlink from hashes can occur with any refcount. Uncooperative userspace can force a situation where a queue is pending for destruction from netlink event while a different socket with same portid processes an UNBIND request. With right timing, this will unhash the instance again: Oops: general protection fault, [..] Call Trace: <TASK> nfulnl_recv_config+0x31a/0xd50 nfnetlink_rcv_msg+0x7c2/0xeb0
Unified · Split
| @@ -228,13 +228,18 @@ static void __nfulnl_flush(struct nfulnl_instance *inst); · 227 unmodified lines | |||
| 228 | static void | 228 | static void |
| 229 | __instance_destroy(struct nfulnl_instance *inst) | 229 | __instance_destroy(struct nfulnl_instance *inst) |
| 230 | { | 230 | { |
| 231 | spin_lock(&inst->lock); | ||
| 232 | if (inst->copy_mode == NFULNL_COPY_DISABLED) { | ||
| 233 | /* attempt to UNBIND a queue already pending | ||
| 234 | * destruction via netlink close event. Ignore. | ||
| 235 | */ | ||
| 236 | spin_unlock(&inst->lock); | ||
| 237 | return; | ||
| 238 | } | ||
| 239 | |||
| 231 | /* first pull it out of the global list */ | 240 | /* first pull it out of the global list */ |
| 232 | hlist_del_rcu(&inst->hlist); | 241 | hlist_del_rcu(&inst->hlist); |
| 233 | 242 | ||
| 234 | /* then flush all pending packets from skb */ | ||
| 235 | |||
| 236 | spin_lock(&inst->lock); | ||
| 237 | |||
| 238 | /* lockless readers wont be able to use us */ | 243 | /* lockless readers wont be able to use us */ |
| 239 | inst->copy_mode = NFULNL_COPY_DISABLED; | 244 | inst->copy_mode = NFULNL_COPY_DISABLED; |
| 240 | 245 | ||