drivers/char/mem.c: deny access in open operation when securelevel is set
Orabug:
26943864
There is still a secure hole left in mem.c driver -- when securelevel is set
userland application could access PCI configuration space via this driver.
--
Attempting to write via mmap() API using acc_test.
[root@ban92uut054 ~]# ./acc_test mmap 0x846000c4=0x1
Using mmap() API for access
mmap write wrote 0x1
[root@ban92uut054 ~]# setpci -s 46:00.0 0xc4.l
00000001
How, write 0x0 to offset 0xc4
[root@ban92uut054 ~]# ./acc_test mmap 0x846000c4=0x0
Using mmap() API for access
mmap write wrote 0x0
[root@ban92uut054 ~]# setpci -s 46:00.0 0xc4.l
00000000
--
source code of acc_test program:
main(int argc, char *argv[])
{
int fd;
int retval;
int val;
off_t addr;
char *tmp;
int operation = 0; //read
int access_type = -1;
off_t page_base = 0;
off_t page_offset = 0;
off_t pagesize = sysconf(_SC_PAGE_SIZE);
char *mem;
int prot;
if (argc < 3) {
printf("Insufficient args: acc_test rw|mmap <addr> [-w <val>]\n");
return -1;
}
if (strcmp("rw", argv[1]) == 0) {
access_type = 1;
printf("Using pread()/pwrite() API for access\n");
}
else if (strcmp("mmap", argv[1]) == 0) {
access_type = 2;
printf("Using mmap() API for access\n");
}
else {
printf("Illegal access type: must be rw or mmap\n");
return -1;
}
addr = strtoul(argv[2], &tmp, 16);
if ((tmp && (*tmp != '=')) &&
((*tmp != '\0') || (errno == EINVAL) ||
(addr == ULONG_MAX && errno == ERANGE))) {
fprintf(stderr, "Invalid address specified; must be hex based\n");
if (errno) perror("error : ");
exit(1);
}
else if (tmp && (*tmp == '=')) { // write case
tmp++;
val = strtoul(tmp, NULL, 16);
operation = 1;
}
//fd = open("/sys/bus/pci/devices/0000:46:00.0/config",O_RDWR | O_SYNC);
//retval = pread(fd, &val, 4, 0xc4);
if (operation == 1)
fd = open("/dev/mem",O_RDWR);
else
fd = open("/dev/mem",O_RDONLY);
if (fd < 0) {
perror("open failed");
exit(1);
}
switch (access_type) {
case 1 : // pread/pwrite API
if (!operation) {
if (pread(fd, &val, 4, addr) < 0) {
perror("pread failed");
return -1;
}
else
printf("pread returned 0x%x from 0x%x\n",val,addr);
}
else {
if (pwrite(fd, &val, 4, addr) < 0) {
perror ("pwrite failed");
return -1;
}
printf("pwrite() wrote 0x%x to 0x%x\n",val,addr);
}
break;
case 2 : // mmap API
page_base = (addr / pagesize) * pagesize;
page_offset = addr - page_base;
prot = PROT_READ;
if (operation)
prot |= PROT_WRITE;
mem = mmap(NULL, page_offset + 4, prot, MAP_SHARED,
fd, page_base);
if (mem == MAP_FAILED) {
perror("can't mmap");
return -1;
}
if (!operation)
printf("mmap read returned 0x%x\n",*(uint32_t *)&mem[page_offset]);
else {
*(uint32_t *)&mem[page_offset] = (uint32_t)val;
printf("mmap write wrote 0x%x\n",val);
}
break;
default :
printf("Illegal access mode\n");
return -1;
}
close(fd);
}
--
This patch is purposed to fix this hole when securelevel is set where one could write to
/dev/mem via the mmap() API. The fix to disallow opening /dev/mem or /dev/kmem
for access. The fix checks access at open rather than have get_securelevel() called at
the various write/read locations.
This issue is specific to UEK4 !
Signed-off-by: James Puthukattukaran <james.puthukattukaran@oracle.com>
Signed-off-by: Ethan Zhao <ethan.zhao@oracle.com>
Reviewed-by: Eric Snowberg <eric.snowberg@oracle.com>
Reviewed-by: Khalid Aziz <khalid.aziz@oracle>