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 | 228 | static void |
| 229 | 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 | 240 | /* first pull it out of the global list */ |
| 232 | 241 | hlist_del_rcu(&inst->hlist); |
| 233 | 242 | |
| 234 | − /* then flush all pending packets from skb */ | |
| 235 | − | |
| 236 | − spin_lock(&inst->lock); | |
| 237 | − | |
| 238 | 243 | /* lockless readers wont be able to use us */ |
| 239 | 244 | inst->copy_mode = NFULNL_COPY_DISABLED; |
| 240 | 245 | |