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;
}