Nanos supports page permissions but one user pointed out that we didn't have prot_none support so calling mprotect with it meant what you thought you were denying access to resulted in a nop.
PROT_NONE essentially makes a region of memory completely in-accessible - so what's the actual use case for it if you can't ... use it?
One use case is for guard pages. These pages of memory can be placed around stacks and so forth so that if a buffer is overflowed you can hit a page you're not supposed to access and it crashes.
For example if we look at this little program - we first map some memory that we can read and write to.
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
int main(void) {
long size = sysconf(_SC_PAGESIZE);
if (size <= 0) return 2;
unsigned char *p = mmap(NULL, (size_t)size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) {
perror("mmap");
return 2;
}
*(volatile unsigned char *)p = 42;
if (mprotect(p, (size_t)size, PROT_NONE) != 0) {
perror("mprotect");
return 2;
}
unsigned value = *(volatile unsigned char *)p;
printf("Unexpected successful read: %u\n", value);
return 1;
}
However, if we try to run this you can see we get a segfault:
eyberg@venus:~/pr$ ops run main --nanos-version=9fe2ab3
running local instance
booting /home/eyberg/.ops/images/main ...
[0.060338] vtbln failed to attach: (status:failed to find free MSI-X
slot)
[0.088546] en1: assigned 10.0.2.15
*** signal 11 received by tid 2, errno 0, code 2
fault address 0x2de4915000
*** Thread context:
lastvector: 000000000000000e (Page fault)
frame: ffffc00002a02000
type: thread
active_cpu: 00000000ffffffff
stack top: 0000000000000000
error code: 0000000000000005
address: 0000002de4915000
Another related change that we made in addition to this was to exclude virtual memory in coredumps that had no read permissions, which was another side-affect of not having PROT_NONE.
At least in x86 land page table entries actually dont have a flag to disable reading of it so instead you set it to not be "present". There is a R/W flag that determines if you can write to it as well as read. There is also a flag 'execute disable (XD)' - more commonly known as NX or no execute. That's why we don't support executing off the stack or heap by default nor on rodata. Similarly, you don't want to be able to write to the text segment (which is where code lives). RISC-V is a little bit different and actually does have a read bit you can unset.
Other use cases for PROT_NONE show up in both garbage collectors and even when the JVM boots up as it reserves a large chunk of memory so it's not just a security feature but can be used for other purposes as well.
Stop Deploying 50 Year Old Systems
Introducing the future cloud.
Ready for the future cloud?
Ready for the revolution in operating systems we've all been waiting for?
Schedule a Demo
