Can I map a structure into a shared memory file? - c

I am trying to open a shared memory segment in my main process. My terminology may be incorrect in the question but this is what I am trying to achieve:
I collect information from 7 sensors and from that I evaluate the state. I made a structure senStruct. I want to share the 7 sensor and state information to other processes with use of shared memory. In code I am opening the senfile, mapping the senStruct into it. Now I simply want to store something into state and it gives me an error.
Here is the code:
#include <fcntl.h> /* Defines O_* constants */
#include <sys/stat.h> /* Defines mode constants */
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct senStruct {
int sensor[7];
int state;
}senStruct;
int main()
{
int fd;
size_t size = sizeof(senStruct);
senStruct *p;
fd = shm_open( "senfile" , O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR );
ftruncate (fd, size);
printf("Before mapping...p points to %p\n",p);
p =(senStruct *) mmap (NULL , size, PROT_READ | PROT_WRITE,MAP_SHARED , fd, 0);
printf("After mapping...p points to %p\n",p);
p->state=1;
return 0;
}
Output is:
Before mapping...p points to (nil)
After mapping...p points to 0xffffffffffffffff
Segmentation fault (core dumped)
Address of p after p seems doubtful to me. Looking into gdb indicates segmentation fault at p->state = 1. Is my procedure incorrect or did I miss anything?

Related

allocation error when trying to do shmat

when trying to do shmat i get allocation error, telling me i cannot accsess the memory, it did not happen to me before and i really dont know what to do.
this is the error :
0xffffffffffffffff error: Cannot access memory at address 0xffffffffffffffff
and the wiered thing is that vecBoard is allocated in the process mapped area and only get crazy when shmat is triggered. thank you all!
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define SHM_SIZE 4096
#define FLAGS IPC_CREAT
#define COLUMNS 8
#define ROWS 8
key_t key;
int main()
{
char* vecBoard;
// Creating shared memory :
if ((key = ftok("ex31.c",'k')) == -1)
{
perror("ftok");
exit(1);
}
int shm_id;
shm_id=shmget(key,SHM_SIZE,FLAGS);
if(shm_id==-1)
{
printf("error creating shared memory\n");
exit(0);
}
printf("the shared memory segment ID is: %d\n",shm_id);
vecBoard = (char *)shmat(shm_id,0,0);
if((vecBoard = (char *)shmat(shm_id,0,0)) == (char*)-1)
{
printf("error in attaching to the shared memory\n");
exit(0);
}
}
The shown code calls shmat() twice, for the same memory segment.
That's obviously wrong.
Looking at errno would help diagnose the problem (i.e. call perror on failure instead of just printf). The OS gives you information when a system call fails; don't ignore it!
If you carefully read the man page for shmget, the third argument (flags) is supposed to contain, in its low 9 bits, the permissions desired for the shared memory segment. If you just pass IPC_CREAT here, those bits are cleared to 0, so you create a segment for which nobody has either read or write permissions. Thus shmat fails (with EACCES because you are (implicitly) asking to both read and write that segment, and you don't have permission to do either.
You probably want to change it to something like IPC_CREAT | 0600, if you want the current user to be able to access the segment.
Note that before testing this again, you'll probably have to remove the existing shared memory segment with the erroneous permissions. Use the ipcs and ipcrm tools for this.

SIGSEGV, after mmapping area

I am trying to revive process from core dump after SIGQUIT.
I really want that piece of virtual memory, yet I get SIGSEGV when I try to map it.
EDIT: This area isn't free: 0xf75d2000 - 0xf7774000, but still i want to have it.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ucontext.h>
#include <elf.h>
#include <sys/procfs.h>
#include <sys/user.h>
#include <linux/unistd.h>
#include <linux/unistd.h>
#include <asm/ldt.h>
#include <signal.h>
bool flag = false;
int argc2;
char ** argv2;
int main2(){
FILE * file = fopen("/proc/self/maps", "r");
if (file) {
char c;
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
fflush(stdout);
void* res = mmap((void*)(0xf75d2000), 0x001a5000, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
return 0;
}
int main(int argc, char ** argv){
argc2 = argc;
argv2 = argv;
ucontext_t cont;
getcontext (&cont);
if(!flag){
void* a = mmap((void*)0x34B000, 81920, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if(a == MAP_FAILED){
printf("mmapfail");
return 1;
}
cont.uc_mcontext.gregs[REG_ESP] = 0x355000;
flag = true;
setcontext(&cont);
} else{
exit(main2());
}
}
I'm compiling it with:
gcc -static -Wl,-Ttext=0x4A9480,--build-idone,-Tdata=0x639480,--section-start=.plt=0x3B9480,--section-start=.rel.plt=0x3AF480,--section-start=.note.ABI-tag=0x39B480 main.c -o main -m32
The address you are trying to map (0xf75d2000) is above the userspace/kernel split in virtual memory. If your kernel is configured with CONFIG_VMSPLIT_3G, you can't map arbitrary addresses above 0xc0000000.
The existing mappings were setup in kernel to expose the vDSO space (to assist with system calls).
Of course you get a SEGV. You map things with MAP_FIXED into some address that doesn't belong to you, then you pull the stack from under your feet. You cannot do this.
The address space is not yours to mess around in. MAP_FIXED is only safe for overwriting earlier mappings. You can possibly play around in it in a single experiment where you'll throw away the program afterwards, but any other use is just not going to work.
Right now your call to setcontext will crash because it doesn't know where to return. Do you even know how function calls and the stack interact? Your call to setcontext saves the return address on the stack, then setcontext changes the stack pointer then it tries to return and dies because it reads 0 as the return address (or setcontext maybe saves the old stack pointer in some other register and will restore it from that register before it returns and what crashes is your other mmap that overwrites the real stack). Please don't do this. Your only chance to reliably change stacks without being the operating system is to set up a signal handler with sigaltstack, catch that signal and never return from the signal handler.
But since you're mapping the memory for your new stack with MAP_FIXED into some random address you'll probably overwrite some other important data structure and it still won't work.
The address space needs to be claimed before other areas are claimed, therefore it needs to be claimed in the executable's metadata.
Create an section in assembly language, then specify it's address in a command line argument to the linker.
For example:
#include <stdio.h>
extern char mem[];
asm (R"(
.section fixed, "aw", #nobits
.global mem
mem:
.zero 0x20000000
)");
int main() {
printf("mem = %p\n", mem);
}
Compile and link with:
gcc -O2 -Wl,--section-start=fixed=0x40000000 -fno-pie -no-pie test.c
Unfortunately using GCC's __attribute__((Section("fixed"))) on a variable definition GCC results in a executable bloated with zeros.

How do I directly access reserved memory with a kernel module?

I'm trying to limit the OS (Ubuntu Server 15.04) to a certain memory usage and reserve the rest but write a kernel module to read/write to the reserved memory. I figured out how to limit the usage/reserve memory using the kernel parameters "mem=4G memmap=4G#0 memmap=4G$4G" (4GB for OS and 4GB reserved, split at 4GB point) but I don't know how DMA to reserved memory works with kernel modules. I was thinking just create a proc file but I'm not sure if you can create one outside of the OS's allocated memory.
Any suggestions? Thanks!
Edit: This is for research so it doesn't need to be "nice"
Update:
Maybe I don't need to write a kernel module. I just found this and I'm going to give it a shot:
http://elinux.org/Memory_Management#Reserving_.28and_accessing.29_the_top_of_memory_on_startup
Update:
I tried the link above but I segfault whenever I try to write. Here's my code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mann.h>
#define RESERVED_MEMORY_SIZE 0x100000000
int main() {
int fd;
char *reserved_memory;
fd = open("/dev/mem", O_RDWR | O_SYNC);
reserved_memory = (char *) mmap(0, RESERVED_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096);
reserved_memory[0] = 'a';
return 0;
}
dmesg shows:
a.out[1167]: segfault at ffffffffffffffff ip 00000000004005d7 sp 00007ffeffccbd80 error 7 in a.out[400000+1000]
For kicks I tried reserved_memory[1]:
a.out[1180]: segfault at 0 ip 00000000004005db sp 00007ffc388d77b0 error 6 in a.out[400000+1000]
I'll look into the format of those messages so I can figure out what it's telling me.
Update:
I found this question by somebody with the same issue as me however the only solution appears to be a kernel rebuild. I'm going to try to avoid this so maybe my best option is a custom kernel module again.
accessing mmaped /dev/mem?
Ok, so I think I solved it. Turns out I just didn't understand how mmap works and I guess the kernel has no restriction on writing/reading /dev/mem if it's in reserved memory. Below are two programs that will write to my reserved spot in memory and read from it.
Write "Hello World!":
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define RESERVED_MEMORY_OFFSET 0x100000000 /* Offset is 4GB */
int main() {
int fd;
char *reserved_memory;
char *buffer = "Hello World!";
fd = open("/dev/mem", O_RDWR | O_SYNC):
/* Returns a pointer to the 4GB point in /dev/mem - the start of my reserved memory. Only mapping 4096 bytes. */
reserved_memory = (char *) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, RESERVED_MEMORY_OFFSET);
if (reserved_memory == MAP_FAILED) {
printf("Failed to creating mapping.\n");
printf("ERRNO: %s\n", strerror(errno));
return -1;
}
sprintf(reserved_memory, "%s", buffer);
return 0;
}
Read from beginning of reserved memory:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define RESERVED_MEMORY_OFFSET 0x100000000 /* Offset is 4GB */
int main() {
int fd;
char *reserved_memory;
char buffer[13];
fd = open("/dev/mem", O_RDWR | O_SYNC):
/* Returns a pointer to the 4GB point in /dev/mem - the start of my reserved memory. Only mapping 4096 bytes. */
reserved_memory = (char *) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, RESERVED_MEMORY_OFFSET);
if (reserved_memory == MAP_FAILED) {
printf("Failed to creating mapping.\n");
printf("ERRNO: %s\n", strerror(errno));
return -1;
}
snprintf(buffer, 13, "%s", reserved_memory);
printf("%s\n", buffer);
return 0;
}
Special thanks to #knm241!

OSX and shared memory needing sudo

I recently found out after updating the OSX software on our server that I am unable to run one of my programs without getting Segmentation Fault 11. It is a simple program which tries to allocate shared memory and then free it. It works fine when i compile and run my file using sudo. Any help would be much appreciated!
Source Code:
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <stddef.h>
#include <sys/un.h>
#include <unistd.h>
int main(){
double *shared;
int arrsize, shmid;
arrsize = 10;
shmid = shmget(IPC_PRIVATE, arrsize * sizeof(double), IPC_CREAT | 666);
shared = (double*) shmat(shmid, NULL, 0);
shared[2] = 3.0; //source of Segmentation Fault
shmdt( (void*) shared );
shmctl(shmid, IPC_RMID, NULL);
printf("Success!");
return 0;
}
System:
ProductName: Mac OS X
ProductVersion: 10.9.1
BuildVersion: 13B42
You are not setting your permissions correctly for the shared memory. You have to use the macros in sys/stat.h to pass the right permissions. Consult man 2 chmod:
shmid = shmget(IPC_PRIVATE, arrsize * sizeof(double), S_IRUSR | S_IWUSR );
Will do the trick.
Your shmget call may be failing when running as a normal user because your literal value 666 is being parsed as a decimal literal. You need a leading 0 for it to be recognized as octal as intended.

Unix/C: put a file into shared memory

Have a problem.
I have a file which contents look like number:error_description.
Now i need to put this file to shared memory (POSIX). If any contents are modified it should be saved to the base-file.
There is a need to search in the content in the shared memory (results will be sent to a client over a message queue).
How do I implement all this? First I thought I have to open (fopen("my_file", "r")) and then I have to create shared memory and mmap the file.
Can someone help me?
edit:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
/*
* \ /tmp/errors -> Error File
*/
#define MSGQ_HANDLER "/error_handler"
#define PATH_TO_FILE "/tmp/errors"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(void) {
int fd = open(PATH_TO_FILE, O_RDWR);
struct stat file_stat;
fstat(fd, &file_stat);
printf("File size: %zd\n", file_stat.st_size);
char *byte_ptr = mmap(NULL, file_stat.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if(byte_ptr == MAP_FAILED){
perror("error:");
}
while(1){
printf("%s\n", byte_ptr);
if(byte_ptr)
exit(1);
}
return EXIT_SUCCESS;
}
So far it is what I have now.
Read a line works.
How do I change the content?
Don't use fopen and forget about shared memory (the sh* API I mean). mmap is all that's needed.
Open your file with open and the right options (read/write). Then use mmap with the option MAP_SHARED. All changes in the file will be reflected directly and visible to all processes that map the same file. On Linux and Solaris (on other systems I don't know, but it is not guaranteed by POSIX or any standard) you can even access the file concurrently with read/write. It is a bad idea though.
Concurrent memory accesses from different processes will, of course, need synchronisation (mutex, semaphores etc.).

Resources