It must be verified that the symbol name offsets point into the
string table, not outside of it.

Signed-off-by: Tobias Stoeckmann <tob...@stoeckmann.org>
---
Proof of Concept:

1. Create "poc.sh"

```
cat > poc.sh << EOF
#!/bin/sh
# Sets an illegal symbol name offset in supplied uncompressed module
# usage: ./poc file.ko

MODULE="$1"
BASE=$(readelf -S $MODULE | grep '\.symtab' | awk '{ print $5 }')
if [ $(getconf LONG_BIT) = '64' ]
then
        OFF=24
else
        OFF=16
fi
ADDR=$(python -c "print(int(0x$BASE) + $OFF)")
echo -n 'AAAA' | dd bs=1 count=4 of=$MODULE seek=$ADDR conv=notrunc
echo $ADDR
EOF
```

2. Choose a module which works for your system (adjust if compressed)

```
cp $(find /lib/modules/$(uname -r) |grep ko$ | head -n 1) poc.ko
```

3. Modify module

```
sh poc.sh poc.ko
```

4. Try to insert

```
insmod poc.ko
```

In dmesg, you can see lines like:

```
BUG: unable to handle page fault for address: ffff9802022d6f81
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 100000067 P4D 100000067 PUD 0
---
 kernel/module/main.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 9c5b373a7..c926960ae 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1688,6 +1688,7 @@ static int elf_validity_cache_copy(struct load_info 
*info, int flags)
 {
        unsigned int i;
        Elf_Shdr *shdr, *strhdr;
+       Elf_Sym *sym;
        int err;
        unsigned int num_mod_secs = 0, mod_idx;
        unsigned int num_info_secs = 0, info_idx;
@@ -1859,6 +1860,17 @@ static int elf_validity_cache_copy(struct load_info 
*info, int flags)
                goto no_exec;
        }

+       /* Symbol names must point into string table. */
+       shdr = &info->sechdrs[info->index.sym];
+       sym = (void *)info->hdr + shdr->sh_offset;
+       for (i = 1; i < shdr->sh_size / sizeof(Elf_Sym); i++) {
+               if (sym[i].st_name >= strhdr->sh_size) {
+                       pr_err("module %s: illegal symbol name offset 
encountered\n",
+                              info->name ?: "(missing .modinfo section or name 
field)");
+                       goto no_exec;
+               }
+       }
+
        /*
         * The ".gnu.linkonce.this_module" ELF section is special. It is
         * what modpost uses to refer to __this_module and let's use rely
--
2.47.0


Reply via email to