Page 1 of 1

CONFIG_GRKERNSEC_KMEM and mcelog/dmidecode problem

PostPosted: Sun Dec 14, 2014 7:29 pm
by jorgus
Hello!

I have a problem with CONFIG_GRKERNSEC_KMEM (using grsecurity-3.0-3.2.64-201411051959) on one of my machines. I can see in the code that it allows access to regions between ebda_start and ebda_end. I guess that's why it lets mcelog and dmidecode mmap some parts of /dev/mem between 0xf0000 and 0xfffff. It works fine on quite a few of my machines. In mcelog's trace I see that it first looks for SMBIOS entry point at 0xf0000-0xfffff and then it usually finds it at 0xfc000-0xfdfff, which is mmapped separately, obviously with success.

On one machine though SMBIOS entry point happens to be found at 0x9d000-0x9dfff, which CONFIG_GRKERNSEC_KMEM refuses to map. I have no idea why it is there and whether it has any legitimate reasons for being there. I just wonder if there is a chance to detect this region and exempt it from the ban. I could probably write an ugly hack hardcoding the whitelisted range, but maybe there is a more generic solution for that?

The mcelog code searching the SMBIOS looks like this by the way (a snippet from dmi.c):

Code: Select all
legacy:
        /*
         * On non-EFI systems, the SMBIOS Entry Point structure can be located
         * by searching for the anchor-string on paragraph (16-byte) boundaries
         * within the physical memory address range 000F0000h to 000FFFFFh
         */
        length = segsize - 1;
        abase = mmap(NULL, length, PROT_READ, MAP_SHARED, memfd, 0xf0000);

        if (abase == (struct anchor *)-1) {
                Eprintf("Cannot mmap 0xf0000 for legacy mode: %s",
                        strerror(errno));
                goto out;
        }

        for (p = abase, q = p + segsize; p < q; p += 0x10) {
                if (!memcmp(p, "_SM_", 4) &&
                    (checksum(p, ((struct anchor *)p)->entry_length) == 0))
                        break;
        }

        if (p >= q) {
                Eprintf("Cannot find SMBIOS DMI tables");
                goto out;
        }

        a = p;

fill_entries:
        if (verbose)
                printf("DMI tables at %x, %u bytes, %u entries\n",
                        a->table, a->length, a->numentries);
        corr = a->table - round_down(a->table, pagesize);
        entrieslen = round_up(a->table + a->length, pagesize) -
                round_down(a->table, pagesize);
        entries = mmap(NULL, entrieslen,
                        PROT_READ, MAP_SHARED, memfd,
                        round_down(a->table, pagesize));
        if (entries == (struct dmi_entry *)-1) {
                Eprintf("Cannot mmap SMBIOS tables at %x", a->table);
                entries = NULL;
                goto out_mmap;
        }

Re: CONFIG_GRKERNSEC_KMEM and mcelog/dmidecode problem

PostPosted: Sun Dec 14, 2014 7:45 pm
by PaX Team
the problem is that this area is RAM and so cannot be given access to in general (at least when you want the kmem restrictions).

Re: CONFIG_GRKERNSEC_KMEM and mcelog/dmidecode problem

PostPosted: Sun Dec 14, 2014 8:39 pm
by jorgus
Is that really so? 0x9d000-0x9dfff is in the reserved range just as 0xf0000-0xfffff is. Sorry if my idea of kernel memory management is completely wrong (which probably is), but this range does not look like a regular RAM to me.

Dec 14 22:50:42 myhost kernel: BIOS-provided physical RAM map:
Dec 14 22:50:42 myhost kernel: BIOS-e820: 0000000000000000 - 0000000000099000 (usable)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 0000000000099000 - 00000000000a0000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000000e6000 - 0000000000100000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 0000000000100000 - 00000000bf740000 (usable)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000bf74e000 - 00000000bf750000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000bf750000 - 00000000bf75e000 (ACPI data)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000bf75e000 - 00000000bf7d0000 (ACPI NVS)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000bf7d0000 - 00000000bf7e0000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000bf7ec000 - 00000000c0000000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000e0000000 - 00000000f0000000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 00000000ffc00000 - 0000000100000000 (reserved)
Dec 14 22:50:42 myhost kernel: BIOS-e820: 0000000100000000 - 0000000640000000 (usable)

myhost:~# head /proc/iomem
00000000-0000ffff : reserved
00010000-00098fff : System RAM
00099000-0009ffff : reserved
000a0000-000bffff : PCI Bus 0000:00
000c0000-000c7fff : Video ROM
000c8000-000ce7ff : Adapter ROM
000d0000-000dffff : PCI Bus 0000:00
000e6000-000fffff : reserved
000f0000-000fffff : System ROM
00100000-bf73ffff : System RAM

Re: CONFIG_GRKERNSEC_KMEM and mcelog/dmidecode problem

PostPosted: Sun Dec 14, 2014 9:17 pm
by PaX Team
yes, it's RAM, it's part of the first 640k left over from the old PC/DOS days. some of it can be claimed by the BIOS, hence the 'reserved' designation but nevertheless it's RAM and writable and allocatable on other systems where it's not reserved.

Re: CONFIG_GRKERNSEC_KMEM and mcelog/dmidecode problem

PostPosted: Sun Dec 14, 2014 10:28 pm
by jorgus
Well, whatever that is, since it's reserved and not used by the kernel, and contains SMBIOS table (in case of that particular system), it should be accessible for read for programs such as mcelog and dmidecode. If you allow 0xf0000-0xfffff to be mmapped, why not allow another region when there is a legitimate reason for that? How could blocking access to SMBIOS when it happens to be outside 0xf0000-0xfffff possibly improve security?

Re: CONFIG_GRKERNSEC_KMEM and mcelog/dmidecode problem

PostPosted: Sun Dec 14, 2014 10:50 pm
by PaX Team
jorgus wrote:If you allow 0xf0000-0xfffff to be mmapped, why not allow another region when there is a legitimate reason for that?
because that region is universally the same on all PC machines whereas your SMBIOS region is specific to your one machine so it'd require extra kernel-side parsing to tell if it's safe to give userland access to it. but hey, it's spender's code, if you can sell him the idea (or better, provide a patch), by all means do so ;).

Re: CONFIG_GRKERNSEC_KMEM and mcelog/dmidecode problem

PostPosted: Mon Dec 15, 2014 5:33 am
by jorgus
PaX Team wrote:]because that region is universally the same on all PC machines


Still, it's not hard-coded but I guess determined by calling get_bios_ebda() ? Another exception for reserved regions in the first 640k (based on the e820 info) or at least in its upper part would do the trick for me. But since there is no agreement on that, I don't think I'll take the trouble of implementing that, given my zero experience of kernel programing (simple hacks don't count). It's more likely I'll end up with an ugly hard-coded region or changing the "if (pagenr <= 256)" condition :-) By the way this condition (coming from vanilla kernel) looks odd compared to all other places using << >> and PAGE_SIZE... I mean this code in arch/x86/mm/init.c:

Code: Select all
+#ifdef CONFIG_GRKERNSEC_KMEM
+   /* throw out everything else below 1MB */
    if (pagenr <= 256)
-      return 1;
+      return 0;
+#endif
    if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
       return 0;