The following shows some important code snippets of function
route4_change
for understanding CVE-2022-2588.
static int route4_change(...) { ... f = kzalloc(sizeof(struct route4_filter), GFP_KERNEL); [0] ... // if there exists a filter with the same handler, copy some information if (fold) { [1] f->id = fold->id; f->iif = fold->iif; f->res = fold->res; f->handle = fold->handle; f->tp = fold->tp; f->bkt = fold->bkt; new = false; } // initialize the new filter err = route4_set_parms(net, tp, base, f, handle, head, tb, [2] tca[TCA_RATE], new, flags, extack); if (err < 0) goto errout; // insert the new filter to the list h = from_hash(f->handle >> 16); [3] fp = &f->bkt->ht[h]; for (pfp = rtnl_dereference(*fp); (f1 = rtnl_dereference(*fp)) != NULL; fp = &f1->next) if (f->handle < f1->handle) break; tcf_block_netif_keep_dst(tp->chain->block); rcu_assign_pointer(f->next, f1); rcu_assign_pointer(*fp, f); // remove fold filter from the list if fold exists if (fold && fold->handle && f->handle != fold->handle) { [4] th = to_hash(fold->handle); h = from_hash(fold->handle >> 16); b = rtnl_dereference(head->table[th]); if (b) { fp = &b->ht[h]; for (pfp = rtnl_dereference(*fp); pfp; fp = &pfp->next, pfp = rtnl_dereference(*fp)) { if (pfp == fold) { rcu_assign_pointer(*fp, fold->next); [5]// remove the old from the linked list break; } } } } ... // free the fold filter if it exists [6] if (fold) { tcf_unbind_filter(tp, &fold->res); tcf_exts_get_net(&fold->exts); tcf_queue_work(&fold->rwork, route4_delete_filter_work); }