diff options
author | Thomas Haller <thaller@redhat.com> | 2022-03-15 11:46:14 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-03-16 23:09:46 (GMT) |
commit | 7f7452c973a4f55f4d8ab6f8b36493a3b00a9397 (patch) | |
tree | 9ae27c85627e12d8f9e0870cae2c476325102b9e /lib/route | |
parent | 620d024d00921bfdd5a5a957713d1431aa4a74f2 (diff) | |
download | libnl-7f7452c973a4f55f4d8ab6f8b36493a3b00a9397.zip libnl-7f7452c973a4f55f4d8ab6f8b36493a3b00a9397.tar.gz libnl-7f7452c973a4f55f4d8ab6f8b36493a3b00a9397.tar.bz2 |
route: fix ref counting for l_info_ops and io_clone()
nl_object_clone() first does a shallow copy, before calling
oo_clone() (link_clone()). That means, the pointer values
of the link object in link_clone() are invalid (as they alias
the pointers from the source object).
We need to get the ref-counting for dst->l_info_ops right.
It was not.
For example, previously when we called io_clone() handler, dst->l_info_ops
would still point to the one from src->l_info_ops, but without owning
the additional reference. Then we call io_clone(), for example
can_clone() for can devices. That one calls first rtnl_link_set_type(),
which first calls release_link_info() -- and unrefs the ops, without
having owned a reference.
Fix that, by getting the reference counting right, before calling
io_clone(). Arguably, we now do duplicate work. First taking a ref, then
calling rtnl_link_set_type() which releases and retakes the ref. But at
least, this way it's correct.
This probably did not cause issues before, because the entire
ref-counting is mostly useless anyway. It's only used for asserting
during rtnl_link_unregister_info() -- and then it checks that the ref
count is not positive (but we release too many references, not too few).
Anyway. *sigh*.
Diffstat (limited to 'lib/route')
-rw-r--r-- | lib/route/link.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/lib/route/link.c b/lib/route/link.c index a7583a4..700ad57 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -306,10 +306,16 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src) if (!(dst->l_info_slave_kind = strdup(src->l_info_slave_kind))) return -NLE_NOMEM; - if (src->l_info_ops && src->l_info_ops->io_clone) { - err = src->l_info_ops->io_clone(dst, src); - if (err < 0) - return err; + if (src->l_info_ops) { + + rtnl_link_info_ops_get(src->l_info_ops); + dst->l_info_ops = src->l_info_ops; + + if (src->l_info_ops->io_clone) { + err = src->l_info_ops->io_clone(dst, src); + if (err < 0) + return err; + } } if ((err = do_foreach_af(src, af_clone, dst)) < 0) |