summaryrefslogtreecommitdiffstats
path: root/lib/route
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-03-04 21:03:05 (GMT)
committerThomas Haller <thaller@redhat.com>2022-03-04 21:07:54 (GMT)
commit3147d865da73009c13500ae296441c54aa2e3551 (patch)
tree4c1ff76f98d83735223cd22b801b4bafc0402c22 /lib/route
parentc027e54ffed247358b152f5330b5dc62c821024f (diff)
downloadlibnl-3147d865da73009c13500ae296441c54aa2e3551.zip
libnl-3147d865da73009c13500ae296441c54aa2e3551.tar.gz
libnl-3147d865da73009c13500ae296441c54aa2e3551.tar.bz2
route:tc: fix rtnl_tc_clone() calling to_clone() and add comment
rtnl_tc_data() allocates a data if necessary (or ENOMEM). So the code void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src); if (!a) return 0; else if (!b) return -NLE_NOMEM; is not right. It also means, rtnl_tc_clone() will always add the data pointers if the previously doesn't exist. In particular, it means that clone modifies "src", and that "dst" will always have an allocated pointer afterwards. Fix that. Also, add a comment about the subtleties for how to_clone() must fix the aliased pointers. Otherwise, we will crash. All implementations actually got this wrong earlier, and it only worked if they didn't encounter ENOMEM.
Diffstat (limited to 'lib/route')
-rw-r--r--lib/route/tc.c18
1 files changed, 8 insertions, 10 deletions
diff --git a/lib/route/tc.c b/lib/route/tc.c
index b47172f..3d993b9 100644
--- a/lib/route/tc.c
+++ b/lib/route/tc.c
@@ -837,18 +837,16 @@ int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj)
if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) {
return -NLE_NOMEM;
}
- }
-
- ops = rtnl_tc_get_ops(src);
- if (ops && ops->to_clone) {
- void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src);
- if (!a)
- return 0;
- else if (!b)
- return -NLE_NOMEM;
+ /* Warning: if the data contains pointer, then at this point, dst->tc_subdata
+ * will alias those pointers.
+ *
+ * ops->to_clone() MUST fix that. */
- return ops->to_clone(a, b);
+ ops = rtnl_tc_get_ops(src);
+ if (ops && ops->to_clone) {
+ return ops->to_clone(rtnl_tc_data(dst), rtnl_tc_data(src));
+ }
}
return 0;