When I tried to access the address mmap returned, a Bus error is occured.
My code is below:
ftruncate(fd, shared_size);
addr = mmap(shared_start, shared_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
shared_size == 256*1024*1024
shared_start == 401000000000 (I used flag MAP_FIXED)
ftruncate the file to 256M.
-rw-r--r-- 1 root 0 256.0M Mar 4 03:47 mem.alloc
There is nothing wrong when calling mmap, and not all of address range is not allowed to access.
From the gdb information below, we can see, the address 0x40100f11ff00 is not allowed, but address 0x40100fe00000 is allowed:
(gdb) p *((char *)addr+0xf11ff00)
Cannot access memory at address 0x40100f11ff00
(gdb) p *((char *)addr+0xfe1ff00)
Cannot access memory at address 0x40100fe1ff00
(gdb) p *((char *)addr+0xfe00000)
$17 = 0 '\000'
From maps information below, we can see the addresses I accessed above are all within the range of mmap address:
0x401000000000 0x401010000000 0x10000000 0x0 /dev/mem.alloc
However, when writing these inaccessible addresses, a bus error occurs:
Program received signal SIGBUS, Bus error.
PS.When reducing shared_size from 256M to 128M, there is no issue.
I have fixed it. This is a problem that can be easily overlooked. The space mount for dev is too small...so....you known....
Related
In mallinfo structure there are two fields hblks and hblkhd. The man documentation says that they are responsible for the number of blocks allocated by mmap and the total number of bytes. But when I run next code
void * ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
*(int *) ptr = 10;
Fields hblks and hblkhd are also zero. While the total number of free bytes in the blocks decreases. Could you please explain why this behavior is observed?
I also tried to allocate all free space and use mmap after it. But in this situation fields also equal to zero
Compiler: gcc 9.4.0
OS: Ubuntu 20.04.1
I did some experiments and they led me to the conclusion that this field is filled only when mmap occurred when calling malloc. A normal mmap call doesn't show up in this statistic, which is logical, because this is a system call, and the statistic is collected in user-space
I ran a simple program written in assembly that under strace that simply executes SYS_exit.
_start:
mov rax, 0x3C
mov rdi, 0x0
syscall
And noticed that there were nothing like mmap memory for the stack:
alrorp#dmspc:~$ strace ./bin
execve("./bin", ["./bin"], 0x7ffd591eda80 /* 65 vars */) = 0
exit(0) = ?
+++ exited with 0 +++
So I tried to do mmap with MAP_FIXED to the stack page-aligned address as follows:
int main(void){
int a = 1;
void *ptr = &a;
void *page_aligned_ptr = (void *)((intptr_t) ptr & -4096);
mmap(page_aligned_ptr, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
}
The thing is it segfaults after the call to mmap succeeds (i.e. it returns the requested address instead of MAP_FAILED).
mmap(0x7ffdf50db000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffdf50db000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault
Can you give any hint about this behavior? Core dump seems to be (almost) useless in that case with stack corrupted.
Does something like create a custom mapping for stack even make sense?
Replacing the stack page containing your return address with a new anonymous page of zero bytes obvious leads to a segfault as soon as main returns, and pops 0 into RIP.
Note the si_addr=NULL, IIRC that's the code address where the fault happened. So RIP=0 after running a ret with RSP pointing at a 0. (The ret itself won't fault, but code-fetch from address 0 will.)
Or actually the segfault will be inside the libc wrapper for mmap, which itself has to ret.
Use a debugger to single-step the asm the C compiler created for you.
I have a program that mmaps memory at higher addresses using MAP_FIXED at TASK_SIZE - PAGE_SIZE.
This program runs fine if I execute it, but if I run it with gdb, it segfaults just after the mmap. Also at this point, the gdb state seems to be completely corrupted and it appears that the execution reaches an address range filled with 0's (could be from the new mappings just created).
Does gdb use this address range in the running process? Have I cleared out some of gdb's state? Is this address range documented somewhere?
Following is my call to mmap and the address calculation -
#define TASK_SIZE64 (0x800000000000UL - 4096)
#define TASK_SIZE TASK_SIZE64
#define PAGE_OFFSET (void*)TASK_SIZE
...
char *load_address = PAGE_OFFSET - file_size_aligned;
if(load_address != mmap(load_address, file_size_aligned, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)){
err("Failed to allocate memory for raw_binary with: %d\n", errno);
return -1;
}
file_size_aligned comes to a PAGE_SIZE. This is one of the allocations. There is one more that starts from load_address and allocates few more pages backwards (with PROT_READ and PROT_WRITE only).
Does gdb use this address range in the running process?
No.
Have I cleared out some of gdb's state?
No.
Is this address range documented somewhere?
Possibly in kernel sources.
Your program makes invalid assumptions about available address space, and "blows itself up" when run with ASLR turned off (which GDB does by default).
You can confirm this by running your program outside GDB, but with ASLR disabled. It should also crash. Try one of these:
# echo 0 > /proc/sys/kernel/randomize_va_space
or
setarch $(uname -m) -R /path/to/exe
You can also confirm that your program will run under GDB if you enable ASLR:
gdb /path/to/exe
(gdb) set disable-randomization off
(gdb) run
I am trying to access physical address through the /dev/mem without success. I can access the address space reserved for PCI devices but when I try to map my memory I get error. (I have mapped the virtual to physical through the pagemap interface).
I have added the nopat to the kernel command line and I am running my program as root.
virtual address: 0x7f925a266000
physical address: 0x1d3a66000
I have also tried aligning it to huge page boundaries without success.
Using the following code, mmap returns -1.
int *addr;
if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0 ) {
printf("Error opening file. \n");
close(fd);
return (-1);
}
addr = (int *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0x1d3a66000);
//error message: Operation not permitted, no logs with dmesg
printf("addr: %p \n",addr);
printf("addr: %d \n",*addr); /* CRASH. */
Any ideas on how I can make it work, or if it's not possible through /dev/mem is there other way to map physical addresses? I am running Ubuntu with the latest kernel version.
Edit:
I have recompiled the kernel without the strict_devmem as #yano suggested and the problem is fixed.
I'm currently experimenting with KVM, and trying to get US (userspace) I/O working. Currently, output (i.e. out dx, eax) works, and the US code can see the written value, but input (in eax, dx) does not seem to work - the VM doesn't receive the value written by the US code.
if (run->io.port == 0xface && run->io.direction == KVM_EXIT_IO_IN)
{
printf("Port 0xface read\n");
*(volatile uint32_t *)((uintptr_t)run + run->io.data_offset) = 0xdeadbeefu;
continue;
}
run is a pointer to a struct kvm_run that was mmaped earlier and has enough space (i.e. run->io.data_offset is a valid offset from the pointer). The continue statement eventually causes the VM to restart, and the code continues normally. However, when I try to get the VM's rax register (which should be 0xdeadbeef), I get zero. From what I read in the docs (kvm/Documentation/api.txt), this is how I should be doing it. Am I missing something?
On a semi-related note, if I precede the continue statement with run->io.count = run->io.count;, the I/O is triggered again (even though count isn't changed). Is this expected behavior? Or am I triggering undefined behavior?
The issue is with the actual mmap call:
run = mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, vcpuID, 0);
The flags parameter should be MAP_SHARED instead of MAP_PRIVATE:
run = mmap(NULL, mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, vcpuID, 0);
^^^^^^^^^^
The virtual machine will see the updated values when KVM_RUN is issued to restart it.