summaryrefslogtreecommitdiffstats
path: root/lib/object.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-03-15 10:35:02 (GMT)
committerThomas Haller <thaller@redhat.com>2022-03-16 23:11:14 (GMT)
commitd23fb814998f7afd26e2eb678919b0e3a796a91f (patch)
tree28f95d689f2cf70d5aa3923a0fa99100532123b8 /lib/object.c
parent7f7452c973a4f55f4d8ab6f8b36493a3b00a9397 (diff)
downloadlibnl-d23fb814998f7afd26e2eb678919b0e3a796a91f.zip
libnl-d23fb814998f7afd26e2eb678919b0e3a796a91f.tar.gz
libnl-d23fb814998f7afd26e2eb678919b0e3a796a91f.tar.bz2
lib: make nl_object_clone() out-of-memory safe
nl_object_clone() first does a shallow copy using memcpy(). That is useful, because it can correctly copy simple fields (like numbers). For pointer values, we need to implement oo_clone() to fixup the pointers and get the deep-copy correct. Now, oo_clone() must always follow through, to un-alias the copied pointer. In particular also in the error case. The oo_clone() implementations sometimes fail (with ENOMEM) and just return. In those cases, we must make sure that we don't leave the wrong pointers there. The pointers must be cleared first. Otherwise, any failure (which basically are ENOMEM) leave the object in an inconsistent state, and we double-free/use-after-free the pointers.
Diffstat (limited to 'lib/object.c')
-rw-r--r--lib/object.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/lib/object.c b/lib/object.c
index af775f1..bef0b6f 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -127,6 +127,11 @@ struct nl_object *nl_object_clone(struct nl_object *obj)
if (size)
memcpy((char *)new + doff, (char *)obj + doff, size);
+ /* Note that the base implementation already initializes @new via memcpy().
+ * That means, simple fields don't need to be handled via oo_clone().
+ * However, this is only a shallow-copy, so oo_clone() MUST fix all
+ * pointer values accordingly. */
+
if (ops->oo_clone) {
if (ops->oo_clone(new, obj) < 0) {
nl_object_free(new);