summaryrefslogtreecommitdiffstats
path: root/lib/route
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-03-15 11:46:14 (GMT)
committerThomas Haller <thaller@redhat.com>2022-03-16 23:09:46 (GMT)
commit7f7452c973a4f55f4d8ab6f8b36493a3b00a9397 (patch)
tree9ae27c85627e12d8f9e0870cae2c476325102b9e /lib/route
parent620d024d00921bfdd5a5a957713d1431aa4a74f2 (diff)
downloadlibnl-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.c14
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)