backports: fix the extack backport for dumps
authorJohannes Berg <johannes.berg@intel.com>
Thu, 26 Oct 2017 08:22:53 +0000 (10:22 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 26 Oct 2017 08:22:53 +0000 (10:22 +0200)
I also never seem to have really tested unload after dumps,
and using the family->attrbuf was causing memory corruption
in the copied family.

Fix this by keeping track of the family copies separately
and actually copying the attrbuf over so the family can use
it from there.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
backport/compat/backport-4.12.c

index 382a3af444bcdf5f2634d1eb1554686694fe14ba..767ecb986d882b1aac54288db2a11fd3fe9f587b 100644 (file)
@@ -19,10 +19,14 @@ enum nlmsgerr_attrs {
 struct bp_extack_genl_family {
        struct genl_family family;
        struct genl_family *real_family;
+       struct list_head list;
 
        struct genl_ops ops[];
 };
 
+static LIST_HEAD(copies_list);
+static DEFINE_MUTEX(copies_mutex);
+
 static const struct nla_policy extack_dummy_policy[1] = {};
 
 static struct bp_extack_genl_family *get_copy(__genl_const struct genl_ops *op)
@@ -212,25 +216,39 @@ int bp_extack_genl_register_family(struct genl_family *family)
        copy->family.pre_doit = extack_pre_doit;
        copy->family.post_doit = extack_post_doit;
 
-       /*
-        * store in attrbuf, so that even if we re-register the family
-        * the data will be overwritten and we don't overwrite data
-        * that's used again later...
-        */
-       family->attrbuf = (void *)copy;
-
        err = __real_bp_extack_genl_register_family(&copy->family);
-       if (err)
+       if (err) {
                kfree(copy);
-       return err;
+               return err;
+       }
+
+       /* copy this since the family might access it directly */
+       family->attrbuf = copy->family.attrbuf;
+
+       mutex_lock(&copies_mutex);
+       list_add_tail(&copy->list, &copies_list);
+       mutex_unlock(&copies_mutex);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(bp_extack_genl_register_family);
 
 int bp_extack_genl_unregister_family(struct genl_family *family)
 {
-       struct bp_extack_genl_family *copy = (void *)family->attrbuf;
+       struct bp_extack_genl_family *tmp, *copy = NULL;
        int err;
 
+       mutex_lock(&copies_mutex);
+       list_for_each_entry(tmp, &copies_list, list) {
+               if (tmp->real_family == family) {
+                       copy = tmp;
+                       break;
+               }
+       }
+       if (copy)
+               list_del(&copy->list);
+       mutex_unlock(&copies_mutex);
+
        if (!copy)
                return -ENOENT;