Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong type for return value of mmap leads to UB #2543

Open
Evian-Zhang opened this issue Nov 19, 2024 · 4 comments
Open

Wrong type for return value of mmap leads to UB #2543

Evian-Zhang opened this issue Nov 19, 2024 · 4 comments

Comments

@Evian-Zhang
Copy link

From the VERSIONS section in mmap man page:

If the MAP_FIXED flag is specified, and addr is 0 (NULL), then the mapped address will be 0 (NULL).

In this case, the kernel does allocate the requested memory at zero address (and dereferencing the NULL pointer will be OK since then). However, the return type of mmap and mmap_anonymous is designed as NonNull, which will then become UB for evident reasons.

The documentation of such functions refers SAFATY as to "See the mmap(2) man page for detailed requirements", while such man page does not impose any safety requirements on the above case.

So there are two ways to solve this:

  • Change the return type of mmap and mmap_anonymous from NonNull<c_void> to usize (we cannot use *mut c_void since Rust requires pointers to be non-null), which would however lose the provenance.
  • Add documentation to mmap and mmap_anonymous to add the above usage as a UB.
@SteveLauC
Copy link
Member

Hi, thanks for catching this!

I tried to reproduce this but got EPERM, could you please provide an example code that can reproduce the issue, not necessarily in Rust, C is ok. And I kinda guess this behavior is Linux-only?

@Evian-Zhang
Copy link
Author

Thank you for your quick response :)

#include <sys/mman.h>
#include <stdio.h>

int main() {
	void *res = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
	printf("res is %p\n", res);
	return 0;
}

If EPERM is returned, just sudo it :)

@SteveLauC
Copy link
Member

SteveLauC commented Nov 19, 2024

Hi, I actually tried sudo and run the binary with the root account, still got EPERM:

$ bat repr.c
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: repr.c
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ #include <sys/mman.h>
   2   │ #include <stdio.h>
   3   │
   4   │ int main() {
   5   │     void *res = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
   6   │     printf("res is %p\n", res);
   7   │     return 0;
   8   │ }
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

$ gcc repr.c -o repr && ./repr
res is 0xffffffffffffffff

$ vim repr.c # check res and call perror()

$ gcc repr.c -o repr && ./repr
mmap: Operation not permitted

$ sudo ./repr
[sudo] password for steve:
mmap: Permission denied

$ sudo su -
root@fedora ~# cd workspace
root@fedora workspace# ./repr
mmap: Permission denied

My env:

$ uname -r
6.10.9-100.fc39.x86_64

$ gcc --version
gcc (GCC) 13.3.1 20240522 (Red Hat 13.3.1-1)

@Evian-Zhang
Copy link
Author

Hmmmm, I tested it in Ubuntu 24.04 and it returns nil indeed.

My env:

$ uname -r
6.8.0-47-generic

$ clang --version
Ubuntu clang version 14.0.0-1ubuntu1.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

As a supplement, some real-world programs do use this feature. For example, this paper (which is in IEEE S&P '20, which is one of the top conferences in security area) uses this feature to avoid crashes in forced execution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants