How to Test If an Address Is Readable in Linux Userspace App

How to test if an address is readable in linux userspace app

The canonical way is to use the write() system call to read from the page (writing to a dummy pipe() file descriptor). Instead of faulting, it will return -1 with errno == EFAULT if the buffer passed to write() is unreadable.

Testing whether memory is accessible in Linux

This a typical case of TOCTOU - you check at some point that the memory is writeable, then later on you try to write to it, and somehow (e.g. because the application deallocated it), the memory is no longer accessible.

There is only one valid way to actually do this, and that is, trap the fault you get from writing to it when you actually need to use it.

Of course, you can use tricks to try to figure out if the memory "may be writeable", but there is no way you can actually ensure it is writeable.

You may want to explain slightly more what you are actually trying to do, and maybe we can have some better ideas if you are more specific.

Checking if an address is writable in x86 assembly

If you have kernel privileges you could probably find that info in the MMU.

But if you don't, you simply do not have access to it and must use OS facilities.

If you mean not calling an OS function, then it is possible at least on Windows by using Structured Exception Handling. It is still OS specific of course, because you need to access the Windows TIB at the FS segment.

How to access physical addresses from user space in Linux?

You can map a device file to a user process memory using mmap(2) system call. Usually, device files are mappings of physical memory to the file system.
Otherwise, you have to write a kernel module which creates such a file or provides a way to map the needed memory to a user process.

Another way is remapping parts of /dev/mem to a user memory.

Edit:
Example of mmaping /dev/mem (this program must have access to /dev/mem, e.g. have root rights):

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Usage: %s <phys_addr> <offset>\n", argv[0]);
return 0;
}

off_t offset = strtoul(argv[1], NULL, 0);
size_t len = strtoul(argv[2], NULL, 0);

// Truncate offset to a multiple of the page size, or mmap will fail.
size_t pagesize = sysconf(_SC_PAGE_SIZE);
off_t page_base = (offset / pagesize) * pagesize;
off_t page_offset = offset - page_base;

int fd = open("/dev/mem", O_SYNC);
unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, page_base);
if (mem == MAP_FAILED) {
perror("Can't map memory");
return -1;
}

size_t i;
for (i = 0; i < len; ++i)
printf("%02x ", (int)mem[page_offset + i]);

return 0;
}

How to use the write() system call to read from the page (writing to a dummy pipe() file descriptor) in C/C++?

First, create a pipe pair to write the data to:

 int fd[2];
pipe(fd);

Then try to write some data from your address to the write side of the pipe:

 int result = write(fd[1], addr, 1);

If result is 1, the write succeeded, so the address was readable. If it's zero and errno == EFAULT, the address is not readable. If errno is something else, something else went wrong.

Make sure to close the pipes once you're done, of course:

 close(fd[0]);
close(fd[1]);

verify if the address being accessed is a part of a process memory in Assembly

There is no way to find out if a page is accessible other than by accessing the page and catching the signal or exception the OS sends you for accessing an invalid page.

This is because the paging mechanism of your operating system traps page faults and then determines if there is supposed to be memory at this page. If yes, it allocates memory and configures the page table to point to that memory. Then it restarts your program which accesses the newly allocated page as if it was there all along. As the hardware doesn't know that this is what the OS plans to do, it cannot tell you if a page is valid or not, even if it had a way to do so.

Consider looking into OS specific mechanisms for enumerating the memory map of your process. For example, on Linux you can check the proc file system to get a memory map. With this memory map, you could then detect if what address ranges are allocated to your process.

How to find all read-write memory address of a process in Linux/UNIX with C/C++ language?

Read the proc file like you read normal file.

eg.

  FILE *filep = fopen("/proc/9322/maps","r");
char ch;
while (ch != EOF){
ch = fgetc(filep);
printf("%c", ch);
}

IsBadReadPtr analogue on Unix

The usual way to do this on POSIX systems is to use the write() system call. It will return EFAULT in errno rather than raising a signal if the memory cannot be read:

int nullfd = open("/dev/random", O_WRONLY);

if (write(nullfd, pointer, size) < 0)
{
/* Not OK */
}
close(nullfd);

(/dev/random is a good device to use for this on Linux, because it can be written by any user and will actually try to read the memory given. On OSes without /dev/random or where it isn't writeable, try /dev/null). Another alternative would be an anonymous pipe, but if you want to test a large region you'll need to regularly clear the reading end of the pipe.

Convert physical address to virtual in Linux and read its content

You need a kernel driver to export the phyisical address to user-level.

Have a look at this driver: https://github.com/claudioscordino/mmap_alloc/blob/master/mmap_alloc.c



Related Topics



Leave a reply



Submit