bus error when memcopy to uio mmap device - c

I currently try to access UIO shared memory via memcopy.
My approach is:
open the corresponding device
map the memory via mmap with the offset speciality N*getpagesize()
memcopy / memset to the pointer that is returned from mmap
I tried also with ftruncate after Step 2 resulting in an error.
The memcopy / memset causes a bus error which is normaly a sign of writing out of the files boundaries.
Via cat /proc/'pid'/maps I'm able to see that there is a mapping for /dev/uioX
Also /sys/class/uio/uioX/maps/ has two map directories, of which I try to access the second one (map1 therefore N = 1)
Am I missing out something?
Would I have to mmap the full size of the memory specified in /sys/class/uio/uioX/maps/map1/size ?
I could not find any example for accessing the memory via memcopy, is there something that prevents memcopy on UIO mmaped memory?
Sources
unsigned char* GetMemPtr(const char *name, unsigned long Size)
{
long fd;
long truncret;
void* MemPtr;
unsigned long offst;
printf("Opening: %s with size %u\n" , name, Size);
fd = open(name, O_RDWR);
if (fd < 0) {
printf("Error: open : %u : %s\n", fd, strerror(errno));
}
offst = 1 * getpagesize();
/*truncret = ftruncate(fd, offst + Size);
if (truncret < 0)
{
printf("Error: ftruncate : %s : %d\n", strerror(errno), truncret);
}*/
MemPtr = mmap(0, Size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offst);
if (MemPtr == MAP_FAILED)
{
printf("Error: mmap : %p : %s\n", MemPtr, strerror(errno));
}
//MemPtr = MemPtr + offst;
printf("Mem pointer is %p\n", MemPtr);
memset(MemPtr, 0, Size);
printf("Pointer is : %p\n" , MemPtr);
return (unsigned char*) MemPtr;
}
Results in the output:
Opening: /dev/uio0 with size 4096
Mem pointer is 0xffff89232000
Bus error (core dumped)

Related

Reading memory of another process in C without ptrace in linux

I am trying to read memory of another process and print whatever is in the memory (Heap and/or stack). I have got the range of memory addresses using /proc
I have extracted address range like this. Now I want to read the memory range of the other process like as defined.
5569032d2000-5569032f3000 rw-p 00000000 00:00 0 [heap]
I am stuck on how to access those memory addresses. I tried something like shown below , but doesn't help much.
int main(int argc, char *argv[]) {
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("%x ", (int)mem[page_offset + i]);
//size_t i;
return 0;}
Thanks.
I am making like a debug tool for my embedded system. I can't use ptrace() as it halts the running process while trying to peek into the device memory.
I figured out to read the process of another process, I can use process_vm_readv() function as follow:
pid_t pid; // Put value of pid in this
void *remotePtr; // Put starting address
size_t bufferLength; // Put size of buffer in this, aka size to read
// Build iovec structs
struct iovec local[1];
local[0].iov_base = calloc(bufferLength, sizeof(char));
local[0].iov_len = bufferLength;
struct iovec remote[1];
remote[0].iov_base = remotePtr;
remote[0].iov_len = bufferLength;
/*Nread will contain amount of bytes of data read*/
nread = process_vm_readv(pid, local, 2, remote, 1, 0);
if (nread < 0) {
switch (errno) {
case EINVAL:
printf("ERROR: INVALID ARGUMENTS.\n");
break;
case EFAULT:
printf
("ERROR: UNABLE TO ACCESS TARGET MEMORY ADDRESS.\n");
break;
case ENOMEM:
printf("ERROR: UNABLE TO ALLOCATE MEMORY.\n");
break;
case EPERM:
printf
("ERROR: INSUFFICIENT PRIVILEGES TO TARGET PROCESS.\n");
break;
case ESRCH:
printf("ERROR: PROCESS DOES NOT EXIST.\n");
break;
default:
printf("ERROR: AN UNKNOWN ERROR HAS OCCURRED.\n");
}
return -1;
}
/* To print the read data */
printf("The read text is \n %s\n", local[0].iov_base);

shared memory in c, question about the output

I tried to realize shared memory with C, but I came up with a problem with my output.
I tried to make a thread called TA put the grade into a shared memory space and make "student" thread output the grade.
In the TA thread:
const int SIZE = 4096;
const char *name_ta = "Students_Information_ta";
int studentGrade = (int)((random() % (100 - 80 + 1)) + 80); // TA gives out a grade to a student
char *grade = (char *)&studentGrade;
/* shared memory file descriptor */
int shm_fd_ta;
/* pointer to shared memory object */
void *ptr_ta;
/* create the shared memory segment of ta */
shm_fd_ta = shm_open(name_ta, O_CREAT | O_RDWR, 0666);
/* configure the size of the shared memory segment of ta*/
ftruncate(shm_fd_ta, SIZE);
/* map the shared memory segment of ta in the address space of the process */
ptr_ta = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd_ta, 0);
if (ptr_ta == MAP_FAILED)
{
printf("Map failed\n");
return -1;
}
/* write to the shared memory region */
sprintf(ptr_ta, "%d", grade);
ptr_ta += strlen(grade);
And here is the output sentences in student thread:
/* name of shared memory object */
const char *name_ta = "Students_Information_ta";
/* size of shared memory object in bytes */
const int SIZE = 4096;
int shm_fd_ta;
void *ptr_ta;
/* open the shared memory segment of ta */
shm_fd_ta = shm_open(name_ta, O_RDWR, 0666);
if (shm_fd_ta == -1)
{
printf("shared memory failed\n");
exit(-1);
}
/* map the shared memory segment of ta in the address space of the process */
ptr_ta = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd_ta, 0);
if (ptr_ta == MAP_FAILED)
{
printf("Map failed\n");
exit(-1);
}
printf("The grade assigned by the TA is %d\n", ptr_ta); // student receives a grade
I thought it should gave me the grades which are numbers between 80 and 100, but in fact the output is some very large numbers like 251142144. Perhaps it has output the address. What can I do to fix this mistake?
char *grade = (char *)&studentGrade;
Okay, so grade is of type pointer to character but is pointing to an integer. Not sure why you'd want to do that, but okay.
sprintf(ptr_ta, "%d", grade);
You told sprintf to print an integer but you passed it a pointer to a character that points to an integer. The sprintf function certainly has no idea what to do with such a mismatched pointer, especially when you told it you were going to pass it an integer.
Why not:
sprintf(ptr_ta, "%d", studentGrade);
If you tell it you're going to give it an integer, maybe give it an integer.
--
ptr_ta = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd_ta, 0);
if (ptr_ta == MAP_FAILED)
{
printf("Map failed\n");
exit(-1);
}
Now, ptr_ta is a pointer to the string you printed.
printf("The grade assigned by the TA is %d\n", ptr_ta); // student receives a grade
You told printf you were going to pass it an integer, but instead you passed it a pointer to a string. How is that supposed to work?
I'd change a lot of things, but this is a start:
printf("The grade assigned by the TA is %s\n", (char *) ptr_ta); // student receives a grade

Allocate N size array inside a Shared memory

I have a structure
struct {
int size;
char *data;
}tmp_buf;
Now i want to allocate memory to the structure in shared memory (mmap-ed location)
i have a pointer "tp" of type "tmp_buf" in my main()
When i try to use strncpy() something at location "tp->data" it gives a segmentation fault.
I have mmap-ed shared memory of size (sizeof(struct tmp_buf) + length_of_data)
This is the code i'm running:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/mman.h>
void * create_shared_memory(char *name, int size) {
int *ptr;
int ret;
int fd = shm_open (name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror ("shm_open error!");
exit (1);
}
ret = ftruncate (fd, sizeof (size));
if (ret == -1) {
perror ("ftruncate error!");
exit (2);
}
ptr = mmap(0, sizeof (size), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
perror ("shm-mmap error!");
exit (3);
}
return ptr;
}
typedef struct {
int size;
char *data;
}tmp_buf;
int main (int argc, char **argv)
{
tmp_buf *buf_ptr;
if(argc != 2)
{
perror("Error: Incorrect number of arguments passed\n");
exit(EXIT_FAILURE);
}
int max_buffers = atoi(argv[1]);
buf_ptr = (struct tmp_buf*)create_shared_memory("my_shm_buffer",sizeof(tmp_buf) + max_buffers*1024);
printf("Shared Memory Location: %p\n", buf_ptr);
printf("Shared Memory size: %d\n", buf_ptr->size);
printf("Shared Memory data: %s\n", buf_ptr->data);
buf_ptr->size =1;
printf("Shared Memory size: %d\n", buf_ptr->size);
printf("SIZEOF(int) =%d SIZEOF(char*) = %d\n",sizeof(int), sizeof(char*));
printf("Shared Memory size address: %p\n", (void*)&(buf_ptr->size));
printf("Shared Memory data address: %p\n", (void*)&(buf_ptr->data));
strncpy(buf_ptr->data,"Hello\n", 6);
printf("Shared Memory data: %s\n", buf_ptr->data);
return 0;
}
Output i am seeing is something like this :
Shared Memory Location: 0x7ffff7ff6000
Shared Memory size: 0
Shared Memory data: (null)
Shared Memory size: 1 (After t->size = 1)
Shared Memory size address: 0x7ffff7ff6000
Shared Memory data address: 0x7ffff7ff6008
Segmentation fault (core dumped) (After strncpy("Hello\n",tp->data, 6))
Have you tried
strncpy(buf_ptr->data, "Hello\n\0", 7);
You should use strncpy with (dest, src, len) and not (src, dest, len)
The C library function char *strncpy(char *dest, const char *src, size_t n) copies up to n characters from the string pointed to, by src to dest. In a case where the length of src is less than that of n, the remainder of dest will be padded with null bytes.
The most obvious problem is demonstrated with this line:
ret = ftruncate (fd, sizeof (size));
sizeof(size) is not going to be very much as it'll be whatever sizeof(int) gives you. To make it the size you want you just pass in size as is like so...
ret = ftruncate (fd, size);
You then repeat the same problem with this line which should also have size instead of sizeof(size)
ptr = mmap(0, sizeof (size), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
It's probably worth changing the function declaration to make size be of type size_t and have it return a tmp_buf *. Casting the void * returned won't automagically cause it to populate buf_ptr with valid values. End result should look like
tmp_buf* create_shared_memory(char *name, size_t size) {
tmp_buf *ptr;
int ret;
int fd = shm_open (name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror ("shm_open error!");
exit (1);
}
ret = ftruncate (fd, size);
if (ret == -1) {
perror ("ftruncate error!");
exit (2);
}
ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
perror ("shm-mmap error!");
exit (3);
}
ptr->size = size;
ptr->data = ((char *) ptr) + sizeof(ptr->size);
return ptr;
}

Issues mmaping the same file twice

I'm using a Raspberry Pi B+, and I'm trying to mmap two different sections of /dev/mem - the first to be able to set two pins' functions from location 0x2020 0004 (0x04 bytes long), the other to manipulate the BSC Slave functions on the BCM2835 chip on the Pi from location 0x2021 4000 (0x1C bytes long).
static uint32_t * initMapMem(int fd, uint32_t addr, uint32_t len)
{
return (uint32_t *) mmap((void*)0x0, len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_SHARED|MAP_LOCKED,
fd, addr);
}
int initialise(void) {
int fd;
fd = open("/dev/mem", O_RDWR | O_SYNC) ;
if (fd < 0)
{
fprintf(stderr, "This program needs root privileges. Try using sudo.\n");
return 1;
}
pinReg = initMapMem(fd, 0x20200004, 0x4);
bscReg = initMapMem(fd, 0x20214000, 0x1C);
close(fd);
if (bscReg == MAP_FAILED)
{
fprintf(stderr, "Bad, mmap failed.\n");
return 1;
}
if (pinReg == MAP_FAILED)
{
fprintf(stderr, "Bad, mmap failed.\n");
return 1;
}
return 0;
}
initialise() is called out of main(). Stepping through the program with gdb I find that bscReg gets positioned right, but pinReg returns as MAP_FAILED (aka 0xFFFFFFFF) with errno set to EINVAL. Doesn't matter which way it's done, either - pinReg always finds itself as MAP_FAILED when mmaped first or second.
How do I get pinReg to a valid value?
The first mmap() is failing because the offset you're trying to map (0x20200004) isn't page-aligned. Create a mapping at 0x20200000 with a size of at least 8, then write to it at an offset of 0x4.

strcpy to mmap address retuns bus error

I created a process which calls mmap with MAP_SHARED flag set,when i attempt to copy a string to that address i receive Bus error core dumped,could some one please explain the reason behind it and how to fix it. Following is my code
int main()
{
int fd=0;
char* ret = NULL;
void *map_addr = NULL;
fd = open("./shared_file.txt", O_RDWR, S_IRUSR | S_IWUSR);
if(fd == -1) {
printf("errno = %d\n",errno);
printf("Aborting process1###########\n");
abort();
}
map_addr = mmap(NULL, 5*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(map_addr == MAP_FAILED) {
printf("mmap failed error no =%d\n",errno);
close(fd);
return -1;
}
printf("map_addr = %p#################\n",(int*)map_addr);
printf("processid = %d#################\n",(int)getpid());
ret = strcpy((char*)map_addr,"Stack Overflow");
if(ret == (char*)map_addr)
printf("strcpy success\n");
/*if(msync(map_addr, sizeof(int), MS_SYNC))
printf("msync failed errno = %d\n",errno);*/
close(fd);
sleep(120);
return (0);
}
The cause of a bus error is usually an attempt to dereference a pointer that has not been initialized properly and contains junk data that are not accessible in a multiple of 4 or 1 or as related to datatype sizes.
First you should check if the shared_file.txt file size is >= 20 bytes(assuming sizeof int is 4 bytes) as specified in the mmap() length argument(where you put 5*(sizeof(int))) in the line below:
map_addr = mmap(NULL, 5*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
If file size is less than 20 bytes, you could use fallocate call to pre allocate the memory.
If shared_file.txt file size is <= 20 bytes and then you ask mmap to map 20 bytes, it could cause a bus error when you write beyond the actual no. of bytes available in file, because that would be access to an undefined portion of a memory. MMAP_FAILED will not be returned in this case, during memory initialization.
A quick check is to see if you can write a single character in the mmap char* pointer. If you can't( you will get a SIGBUS), that means file size is zero.

Resources