Re: [PATCH v3] kernel/module: Fix mem leak in module_add_modinfo_attrs

From: Yuehaibing
Date: Tue Jun 11 2019 - 10:35:36 EST


On 2019/6/11 21:33, Jessica Yu wrote:
> +++ YueHaibing [03/06/19 22:45 +0800]:
>> In module_add_modinfo_attrs if sysfs_create_file
>> fails, we forget to free allocated modinfo_attrs
>> and roll back the sysfs files.
>>
>> Fixes: 03e88ae1b13d ("[PATCH] fix module sysfs files reference counting")
>> Signed-off-by: YueHaibing <yuehaibing@xxxxxxxxxx>
>> ---
>> v3: reuse module_remove_modinfo_attrs
>> v2: free from '--i' instead of 'i--'
>> ---
>> kernel/module.c | 21 ++++++++++++++++-----
>> 1 file changed, 16 insertions(+), 5 deletions(-)
>>
>> diff --git a/kernel/module.c b/kernel/module.c
>> index 80c7c09..c6b8912 100644
>> --- a/kernel/module.c
>> +++ b/kernel/module.c
>> @@ -1697,6 +1697,8 @@ static int add_usage_links(struct module *mod)
>> return ret;
>> }
>>
>> +static void module_remove_modinfo_attrs(struct module *mod, int end);
>> +
>> static int module_add_modinfo_attrs(struct module *mod)
>> {
>> struct module_attribute *attr;
>> @@ -1711,24 +1713,33 @@ static int module_add_modinfo_attrs(struct module *mod)
>> return -ENOMEM;
>>
>> temp_attr = mod->modinfo_attrs;
>> - for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
>> + for (i = 0; (attr = modinfo_attrs[i]); i++) {
>> if (!attr->test || attr->test(mod)) {
>> memcpy(temp_attr, attr, sizeof(*temp_attr));
>> sysfs_attr_init(&temp_attr->attr);
>> error = sysfs_create_file(&mod->mkobj.kobj,
>> &temp_attr->attr);
>> + if (error)
>> + goto error_out;
>> ++temp_attr;
>> }
>> }
>> +
>> + return 0;
>> +
>> +error_out:
>> + module_remove_modinfo_attrs(mod, --i);
>
> Gah, I think there is another issue here - if sysfs_create_file()
> fails on the first iteration of the loop (so i = 0), then we will go
> to error_out and end up calling module_remove_modinfo_attrs(mod, -1),
> which, for i = 0, will call sysfs_remove_file() since attr->attr.name
> had already been set before the failed call to sysfs_create_file().
> Perhaps we need to check that i > 0 before calling
> module_remove_modinfo_attrs() under error_out?

Indeed, this should be checked, thanks!

>
>> return error;
>> }
>>
>> -static void module_remove_modinfo_attrs(struct module *mod)
>> +static void module_remove_modinfo_attrs(struct module *mod, int end)
>> {
>> struct module_attribute *attr;
>> int i;
>>
>> for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
>> + if (end >= 0 && i > end)
>> + break;
>> /* pick a field to test for end of list */
>> if (!attr->attr.name)
>> break;
>> @@ -1816,7 +1827,7 @@ static int mod_sysfs_setup(struct module *mod,
>> return 0;
>>
>> out_unreg_modinfo_attrs:
>> - module_remove_modinfo_attrs(mod);
>> + module_remove_modinfo_attrs(mod, -1);
>> out_unreg_param:
>> module_param_sysfs_remove(mod);
>> out_unreg_holders:
>> @@ -1852,7 +1863,7 @@ static void mod_sysfs_fini(struct module *mod)
>> {
>> }
>>
>> -static void module_remove_modinfo_attrs(struct module *mod)
>> +static void module_remove_modinfo_attrs(struct module *mod, int end)
>> {
>> }
>>
>> @@ -1868,7 +1879,7 @@ static void init_param_lock(struct module *mod)
>> static void mod_sysfs_teardown(struct module *mod)
>> {
>> del_usage_links(mod);
>> - module_remove_modinfo_attrs(mod);
>> + module_remove_modinfo_attrs(mod, -1);
>> module_param_sysfs_remove(mod);
>> kobject_put(mod->mkobj.drivers_dir);
>> kobject_put(mod->holders_dir);
>> --
>> 1.8.3.1
>>
>>
>
> .
>