2017-04-21 22:35:36

by Kees Cook

[permalink] [raw]
Subject: [PATCH v2 0/2] module: Add module name to modinfo

The mod structure is accessed for the "name" field prior to validating
sanity in check_modstruct_version(). This becomes very obvious once
struct layout randomization is happening, so instead add the module
name to modinfo and use that until the mod struct has been sanity-checked.

-Kees

v2:
- adjusted for more odd name load failure cases; jeyu


2017-04-21 22:35:33

by Kees Cook

[permalink] [raw]
Subject: [PATCH v2 1/2] module: Pass struct load_info into symbol checks

Since we're already using values from struct load_info, just pass this
pointer in directly and use what's needed as we need it. This allows us
to access future fields in struct load_info too.

Signed-off-by: Kees Cook <[email protected]>
---
kernel/module.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/kernel/module.c b/kernel/module.c
index 7eba6dea4f41..ed6cf2367217 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1257,12 +1257,13 @@ static u32 resolve_rel_crc(const s32 *crc)
return *(u32 *)((void *)crc + *crc);
}

-static int check_version(Elf_Shdr *sechdrs,
- unsigned int versindex,
+static int check_version(const struct load_info *info,
const char *symname,
struct module *mod,
const s32 *crc)
{
+ Elf_Shdr *sechdrs = info->sechdrs;
+ unsigned int versindex = info->index.vers;
unsigned int i, num_versions;
struct modversion_info *versions;

@@ -1305,8 +1306,7 @@ static int check_version(Elf_Shdr *sechdrs,
return 0;
}

-static inline int check_modstruct_version(Elf_Shdr *sechdrs,
- unsigned int versindex,
+static inline int check_modstruct_version(const struct load_info *info,
struct module *mod)
{
const s32 *crc;
@@ -1322,8 +1322,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
BUG();
}
preempt_enable();
- return check_version(sechdrs, versindex,
- VMLINUX_SYMBOL_STR(module_layout), mod, crc);
+ return check_version(info, VMLINUX_SYMBOL_STR(module_layout),
+ mod, crc);
}

/* First part is kernel version, which we ignore if module has crcs. */
@@ -1337,8 +1337,7 @@ static inline int same_magic(const char *amagic, const char *bmagic,
return strcmp(amagic, bmagic) == 0;
}
#else
-static inline int check_version(Elf_Shdr *sechdrs,
- unsigned int versindex,
+static inline int check_version(const struct load_info *info,
const char *symname,
struct module *mod,
const s32 *crc)
@@ -1346,8 +1345,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
return 1;
}

-static inline int check_modstruct_version(Elf_Shdr *sechdrs,
- unsigned int versindex,
+static inline int check_modstruct_version(const struct load_info *info,
struct module *mod)
{
return 1;
@@ -1383,7 +1381,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
if (!sym)
goto unlock;

- if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
+ if (!check_version(info, name, mod, crc)) {
sym = ERR_PTR(-EINVAL);
goto getname;
}
@@ -2950,7 +2948,7 @@ static struct module *setup_load_info(struct load_info *info, int flags)
info->index.pcpu = find_pcpusec(info);

/* Check module struct version now, before we try to use module. */
- if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
+ if (!check_modstruct_version(info, mod))
return ERR_PTR(-ENOEXEC);

return mod;
--
2.7.4

2017-04-21 22:35:39

by Kees Cook

[permalink] [raw]
Subject: [PATCH v2 2/2] module: Add module name to modinfo

Accessing the mod structure (e.g. for mod->name) prior to having completed
check_modstruct_version() can result in writing garbage to the error logs
if the layout of the mod structure loaded from disk doesn't match the
running kernel's mod structure layout. This kind of mismatch will become
much more likely if a kernel is built with different randomization seed
for the struct layout randomization plugin.

Instead, add and use a new modinfo string for logging the module name.

Signed-off-by: Kees Cook <[email protected]>
---
kernel/module.c | 29 ++++++++++++++++++++++-------
scripts/mod/modpost.c | 1 +
2 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/kernel/module.c b/kernel/module.c
index ed6cf2367217..29a4a77b6849 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -299,6 +299,7 @@ int unregister_module_notifier(struct notifier_block *nb)
EXPORT_SYMBOL(unregister_module_notifier);

struct load_info {
+ char *name;
Elf_Ehdr *hdr;
unsigned long len;
Elf_Shdr *sechdrs;
@@ -1297,12 +1298,12 @@ static int check_version(const struct load_info *info,
}

/* Broken toolchain. Warn once, then let it go.. */
- pr_warn_once("%s: no symbol version for %s\n", mod->name, symname);
+ pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
return 1;

bad_version:
pr_warn("%s: disagrees about version of symbol %s\n",
- mod->name, symname);
+ info->name, symname);
return 0;
}

@@ -2892,9 +2893,15 @@ static int rewrite_section_headers(struct load_info *info, int flags)
info->index.vers = 0; /* Pretend no __versions section! */
else
info->index.vers = find_sec(info, "__versions");
+ info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
+
info->index.info = find_sec(info, ".modinfo");
+ if (!info->index.info)
+ info->name = "(missing .modinfo section)";
+ else
+ info->name = get_modinfo(info, "name");
info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
- info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
+
return 0;
}

@@ -2934,14 +2941,22 @@ static struct module *setup_load_info(struct load_info *info, int flags)

info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
if (!info->index.mod) {
- pr_warn("No module found in object\n");
+ pr_warn("%s: No module found in object\n",
+ info->name ?: "(missing .modinfo name field)");
return ERR_PTR(-ENOEXEC);
}
/* This is temporary: point mod into copy of data. */
mod = (void *)info->sechdrs[info->index.mod].sh_addr;

+ /*
+ * If we didn't load the .modinfo 'name' field, fall back to
+ * on-disk struct mod 'name' field.
+ */
+ if (!info->name)
+ info->name = mod->name;
+
if (info->index.sym == 0) {
- pr_warn("%s: module has no symbols (stripped?)\n", mod->name);
+ pr_warn("%s: module has no symbols (stripped?)\n", info->name);
return ERR_PTR(-ENOEXEC);
}

@@ -2969,7 +2984,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
return err;
} else if (!same_magic(modmagic, vermagic, info->index.vers)) {
pr_err("%s: version magic '%s' should be '%s'\n",
- mod->name, modmagic, vermagic);
+ info->name, modmagic, vermagic);
return -ENOEXEC;
}

@@ -3249,7 +3264,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
if (IS_ERR(mod))
return mod;

- if (blacklisted(mod->name))
+ if (blacklisted(info->name))
return ERR_PTR(-EPERM);

err = check_modinfo(mod, info, flags);
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 30d752a4a6a6..48397feb08fb 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -2126,6 +2126,7 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "#include <linux/compiler.h>\n");
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+ buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
buf_printf(b, "\n");
buf_printf(b, "__visible struct module __this_module\n");
buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
--
2.7.4

2017-04-25 07:00:54

by Jon Masters

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] module: Add module name to modinfo

On 04/21/2017 06:35 PM, Kees Cook wrote:

> Accessing the mod structure (e.g. for mod->name) prior to having completed
> check_modstruct_version() can result in writing garbage to the error logs
> if the layout of the mod structure loaded from disk doesn't match the
> running kernel's mod structure layout. This kind of mismatch will become
> much more likely if a kernel is built with different randomization seed
> for the struct layout randomization plugin.
>
> Instead, add and use a new modinfo string for logging the module name.

+Lucas - probably something that the modinfo kmod utility should track.

Jon.

2017-04-25 07:04:12

by Jon Masters

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] module: Add module name to modinfo

Nevermind. Missread the patch as doing something different on first pass.

--
Computer Architect | Sent from my 64-bit #ARM Powered phone

> On Apr 25, 2017, at 03:00, Jon Masters <[email protected]> wrote:
>
>> On 04/21/2017 06:35 PM, Kees Cook wrote:
>>
>> Accessing the mod structure (e.g. for mod->name) prior to having completed
>> check_modstruct_version() can result in writing garbage to the error logs
>> if the layout of the mod structure loaded from disk doesn't match the
>> running kernel's mod structure layout. This kind of mismatch will become
>> much more likely if a kernel is built with different randomization seed
>> for the struct layout randomization plugin.
>>
>> Instead, add and use a new modinfo string for logging the module name.
>
> +Lucas - probably something that the modinfo kmod utility should track.
>
> Jon.
>

2017-04-26 02:32:16

by Jessica Yu

[permalink] [raw]
Subject: Re: [PATCH v2 0/2] module: Add module name to modinfo

+++ Kees Cook [21/04/17 15:35 -0700]:
>The mod structure is accessed for the "name" field prior to validating
>sanity in check_modstruct_version(). This becomes very obvious once
>struct layout randomization is happening, so instead add the module
>name to modinfo and use that until the mod struct has been sanity-checked.
>
>-Kees
>
>v2:
>- adjusted for more odd name load failure cases; jeyu

Hi Kees!

These patches look fine to me, would you mind if I held on to them
until after the upcoming merge window? (Since we're at -rc8, and I'd
still like for them to sit in -next for a while)

Thanks,

Jessica

2017-04-26 02:58:16

by Jessica Yu

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] module: Add module name to modinfo

+++ Jon Masters [25/04/17 03:04 -0400]:
>Nevermind. Missread the patch as doing something different on first pass.

It's good to give the kmod folks a heads up anyway (as name would be
visible in modinfo), thanks Jon!

>> On Apr 25, 2017, at 03:00, Jon Masters <[email protected]> wrote:
>>
>>> On 04/21/2017 06:35 PM, Kees Cook wrote:
>>>
>>> Accessing the mod structure (e.g. for mod->name) prior to having completed
>>> check_modstruct_version() can result in writing garbage to the error logs
>>> if the layout of the mod structure loaded from disk doesn't match the
>>> running kernel's mod structure layout. This kind of mismatch will become
>>> much more likely if a kernel is built with different randomization seed
>>> for the struct layout randomization plugin.
>>>
>>> Instead, add and use a new modinfo string for logging the module name.
>>
>> +Lucas - probably something that the modinfo kmod utility should track.
>>
>> Jon.
>>

2017-04-26 04:43:58

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v2 0/2] module: Add module name to modinfo

On Tue, Apr 25, 2017 at 7:32 PM, Jessica Yu <[email protected]> wrote:
> +++ Kees Cook [21/04/17 15:35 -0700]:
>
>> The mod structure is accessed for the "name" field prior to validating
>> sanity in check_modstruct_version(). This becomes very obvious once
>> struct layout randomization is happening, so instead add the module
>> name to modinfo and use that until the mod struct has been sanity-checked.
>>
>> -Kees
>>
>> v2:
>> - adjusted for more odd name load failure cases; jeyu
>
>
> Hi Kees!
>
> These patches look fine to me, would you mind if I held on to them
> until after the upcoming merge window? (Since we're at -rc8, and I'd
> still like for them to sit in -next for a while)

Sure thing; I'm in no rush. :)

Thanks!

-Kees

--
Kees Cook
Pixel Security