I have just started learning about virtual memory and I don't understand if I can see the memory that I have allocated with mmap(). The 2 show_maps() print the same text. Shouldn't I also see the allocated memory from mmap() in the second show_maps() and if not is there a way to see it?
#define MAPS_PATH "/proc/self/maps"
#define LINELEN 256
void show_maps(void)
{
FILE *f;
char line[LINELEN];
f = fopen(MAPS_PATH, "r");
if (!f) {
printf("Cannot open " MAPS_PATH ": %s\n", strerror(errno));
return;
}
printf("\nVirtual Memory Map of process [%ld]:\n", (long)getpid());
while (fgets(line, LINELEN, f) != NULL) {
printf("%s", line);
}
printf("--------------------------------------------------------\n\n");
if (0 != fclose(f))
perror("fclose(" MAPS_PATH ")");
}
int main(void)
{
pid_t mypid;
int fd = -1;
uint64_t *pa;
mypid = getpid();
show_maps();
pa=mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
show_maps();
}
You did:
pa = mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
If you check the value of pa, you'll find that it is MAP_FAILED
So, the actual mapping did not occur.
This is because you called mmap with an fd value of -1. So, the call had no backing store/file.
To fix this, add MAP_ANONYMOUS:
pa = mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,fd,0);
Related
I am trying to initialize some variables in my struct, but I am getting a seg fault when assigning my front variable to equal zero. Specifically newBuff->front = 0;
typedef struct buffer{
pthread_mutex_t lock;
pthread_cond_t shout;
int front;
int rear;
char bytes[1024];
} buffer;
int main(int argc, char const *argv[]) {
FILE *file = fopen(argv[1], "r");
if (argc != 2){
printf("You must enter in a file name\n");
}
printf("%lu\n", sizeof(file));
int shmid;
char path[] = "~";
key_t key = ftok(path, 7);
shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL); //shared memory creation
buffer* newBuff = (buffer*) shmat(shmid, 0, 0);
newBuff->front = 0;
You're not checking the value of newBuff returned by shmat() to ensure that it is not invalid, e.g. (void*) -1 (per http://man7.org/linux/man-pages/man2/shmop.2.html). You also need to check the return value of shmget() to ensure that it succeeded in the first place.
Almost certainly, newBuff is -1, and trying to dereference that gives you a segfault.
several things I can see:
Wrong control of the arguments. You are checking them, but are you exiting your program? ;)
You are not checking the result when you invoke functions as shmat. Review the manual (man shmat).
Said the above, I can not see your whole code, but this is my recommendation:
typedef struct buffer{
pthread_mutex_t lock;
pthread_cond_t shout;
int front;
int rear;
char bytes[1024];
} buffer;
int main(int argc, char const *argv[]) {
int shmid = -1;
FILE *file = NULL;
if (argc != 2){
printf("You must enter in a file dumbass\n");
// And you must terminate here your program!
return 1;
}
file = fopen(argv[1], "r");
// Another check that you are not making and can raise a SIGVSEG
if (file == NULL) {
printf("The file '%s' can not be opened\n", argv[1]);
return 1;
}
printf("File size: %lu\n", sizeof(file));
char path[] = "~";
key_t key = ftok(path, 7);
// Another check
if (key == -1) {
fclose(f);
printf("The path '%s' does not exist or cannot be accessed\n", path);
return 1;
}
shmid = shmget(key, SIZE, 0666 | IPC_CREAT | IPC_EXCL);
// One more check
if (shmid == -1) {
fclose(f);
printf("An error happened getting shared memory identifier\n");
return 1;
}
buffer* newBuff = (buffer*)shmat(shmid, 0, 0);
// And finally! Another potential source that could raise a SIGVSEG
if (buffer == NULL) {
fclose(f);
printf("An error happened getting the shared memory area\n");
return 1;
}
newBuff->front = 0;
Please! Check every return of the functions! You can not imagine how many real problems happen because such returns are not checked properly because of bad practices.
I'm trying to create a simple XOR crypter / decrypter in C for .exe files. I'm still pretty new in C and don't understand everything yet, especially memory stuff. So I've been following an online tutorial on how to make a simple XOR string crypter which worked fine. Now I wanted to modify it so I can en/decrypt executable files and decided to utilize the fwrite() and fread() functions. This is what I've come up with:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // execve function
#define XOR_KEY 0xAA // key
#define JOB_CRYPT 1 // alter flow depending on the job
#define JOB_DECRYPT 2
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void xorFile (char *infile, char *outfile) {
FILE *nFile, *eFile;
long nFileSize; // store file size of the file we want to read
char *buffer; // buffer for reading
char *eBuffer; // buffer for storing encrypted data
size_t rResult;
size_t wResult;
///// READ FILE /////
nFile = fopen(infile, "rb");
if(nFile == NULL) {
fputs("Error opening file...", stderr);
exit(EXIT_FAILURE);
}
fseek(nFile, 0, SEEK_END);
nFileSize = ftell(nFile);
rewind(nFile);
buffer = (char *) malloc(sizeof(char) * nFileSize);
if(buffer == NULL) {
fputs("Error allocating memory...", stderr);
exit(EXIT_FAILURE);
}
rResult = fread(buffer, 1, nFileSize, nFile);
if(rResult != nFileSize) {
fputs("Error reading file...", stderr);
exit(EXIT_FAILURE);
}
fclose(nFile);
printf("File size is: %ld\n", nFileSize);
printf("Buffer size is (pointer): %u\n", sizeof(buffer));
printf("Reading result: %lu\n", rResult);
////// WRITE TO FILE //////
eFile = fopen(outfile, "wb");
if(eFile == NULL) {
fputs("Error creating file...", stderr);
exit(EXIT_FAILURE);
}
eBuffer = (char *) malloc(sizeof(char) * nFileSize);
if(eBuffer == NULL) {
fputs("Error allocating memory (2)...", stderr);
exit(EXIT_FAILURE);
}
// encrypt byte by byte and save to buffer
printf("Proceeding with encryption!\n");
for(int i = 0; buffer[i] != EOF; i++) {
eBuffer[i] = buffer[i] ^ XOR_KEY;
}
printf("Proceeding with fwrite()!\n");
wResult = fwrite(eBuffer, 1, nFileSize, eFile);
fclose(eFile);
printf("eBuffer size is (pointer)%u\n", sizeof(eBuffer));
printf("Writing result: %lu\n", wResult);
free(buffer); // free buffers in heap
free(eBuffer);
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
// checking if all parameters were given
if(argc < 4) {
fprintf(stderr, "Usage: %s [CRYPT | DECRYPT] [IN-FILE] [OUT-FILE]\n", argv[0]);
exit(EXIT_FAILURE);
}
int job;
// DOLOCIMO JOB
if(strcmp(argv[1], "CRYPT") == 0) {
job = JOB_CRYPT;
} else if (strcmp(argv[1], "DECRYPT") == 0) {
job = JOB_DECRYPT;
} else {
fprintf(stderr, "Please select [CRYPT | DECRYPT]!");
exit(EXIT_FAILURE);
}
// CRYPT/DECRYPT OUR FILE
xorFile(argv[2], argv[3]);
if(job == JOB_DECRYPT) {
char *args[] = {argv[3], NULL};
int errExec = execve(args[0], args, NULL);
if(errExec == -1) {
perror("Error executing file...");
exit(EXIT_FAILURE);
}
}
return 0;
}
I'm sorry for the ugly looking code but I first wanted to make it work and I'll refine it later.
Anyways, when I run it in command prompt, the encryption works fine, it generates an encrypted file, but when I run the decrpytion job, the program
crashes during the decryption process. Here's a picture of what happens so you can imagine it better.
Since I have less than 10 reputation, I'm not allowed to embedd pictures.
Here is a link to Imgur.
What's going wrong here? Am I creating a buffer overflow when I'm decrypting it?
Thank you!
Here's the problem:
for(int i = 0; buffer[i] != EOF; i++) {
eBuffer[i] = buffer[i] ^ XOR_KEY;
}
Binary files can contain bytes with any value. So the EOF value is valid and does not designate the end of the file. This means that if the file contains a byte with this value, the loop will quit early and you won't XOR all the bytes. If the file does not contain this byte, the loop will run past the end of the allocated memory which invokes undefined behavior which in this case manifests in a crash.
You know how many bytes you need to processes, so use that as your loop control:
for(int i = 0; i < nFileSize; i++) {
A few other minor corrections:
buffer = (char *) malloc(sizeof(char) * nFileSize);
if(buffer == NULL) {
fputs("Error allocating memory...", stderr);
exit(EXIT_FAILURE);
}
Don't cast the return value of malloc. Also, sizeof(char) is 1 by definition, so you can leave that out.
Also, if a system or library function fails, you should use perror to print the error message. This will print additional information regarding why the function failed.
buffer = malloc(nFileSize);
if(buffer == NULL) {
perror("Error allocating memory...");
exit(EXIT_FAILURE);
}
When i run the binary file of this code it throws an segmentation fault core dumped error. And the dmesg is:
segfault at 0 ip b7651747 sp bfb312d0 error 4 in libc-2.21.so[b75e9000+1b4000]
The code is for translation of virtual address to physical address.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
// ORIG_BUFFER will be placed in memory and will then be changed to NEW_BUFFER
// They must be the same length
#define ORIG_BUFFER "Hello, World!"
#define NEW_BUFFER "Hello, Linux!"
// The page frame shifted left by PAGE_SHIFT will give us the physcial address of the frame
// Note that this number is architecture dependent. For me on x86_64 with 4096 page sizes,
// it is defined as 12. If you're running something different, check the kernel source
// for what it is defined as.
#define PAGE_SHIFT 12
#define PAGEMAP_LENGTH 8
void* create_buffer(void);
unsigned long get_page_frame_number_of_address(void *addr);
int open_memory(void);
void seek_memory(int fd, unsigned long offset);
int main(void) {
// Create a buffer with some data in it
void *buffer = create_buffer();
// Get the page frame the buffer is on
unsigned int page_frame_number = get_page_frame_number_of_address(buffer);
printf("Page frame: 0x%x\n", page_frame_number);
// Find the difference from the buffer to the page boundary
unsigned int distance_from_page_boundary = (unsigned long)buffer %
getpagesize();
// Determine how far to seek into memory to find the buffer
uint64_t offset = (page_frame_number << PAGE_SHIFT) + distance_from_page_boundary;
// Open /dev/mem, seek the calculated offset, and
// map it into memory so we can manipulate it
// CONFIG_STRICT_DEVMEM must be disabled for this
int mem_fd = open_memory();
seek_memory(mem_fd, offset);
printf("Buffer: %s\n", buffer);
puts("Changing buffer through /dev/mem...");
// Change the contents of the buffer by writing into /dev/mem
// Note that since the strings are the same length, there's no purpose in
// copying the NUL terminator again
if(write(mem_fd, NEW_BUFFER, strlen(NEW_BUFFER)) == -1) {
fprintf(stderr, "Write failed: %s\n", strerror(errno));
}
printf("Buffer: %s\n", buffer);
// Clean up
free(buffer);
close(mem_fd);
return 0;
}
void* create_buffer(void) {
size_t buf_size = strlen(ORIG_BUFFER) + 1;
// Allocate some memory to manipulate
void *buffer = malloc(buf_size);
if(buffer == NULL) {
fprintf(stderr, "Failed to allocate memory for buffer\n");
exit(1);
}
// Lock the page in memory
// Do this before writing data to the buffer so that any copy-on-write
// mechanisms will give us our own page locked in memory
if(mlock(buffer, buf_size) == -1) {
fprintf(stderr, "Failed to lock page in memory: %s\n", strerror(errno));
exit(1);
}
// Add some data to the memory
strncpy(buffer, ORIG_BUFFER, strlen(ORIG_BUFFER));
return buffer;
}
unsigned long get_page_frame_number_of_address(void *addr) {
// Open the pagemap file for the current process
FILE *pagemap = fopen("/proc/self/pagemap", "rb");
// Seek to the page that the buffer is on
unsigned long offset = (unsigned long)addr / getpagesize() * PAGEMAP_LENGTH;
if(fseek(pagemap, (unsigned long)offset, SEEK_SET) != 0) {
fprintf(stderr, "Failed to seek pagemap to proper location\n");
exit(1);
}
// The page frame number is in bits 0-54 so read the first 7 bytes and clear the 55th bit
unsigned long page_frame_number = 0;
fread(&page_frame_number, 1, PAGEMAP_LENGTH-1, pagemap);
page_frame_number &= 0x7FFFFFFFFFFFFF;
fclose(pagemap);
return page_frame_number;
}
int open_memory(void) {
// Open the memory (must be root for this)
int fd = open("/dev/mem", O_RDWR);
if(fd == -1) {
fprintf(stderr, "Error opening /dev/mem: %s\n", strerror(errno));
exit(1);
}
return fd;
}
void seek_memory(int fd, unsigned long offset) {
unsigned pos = lseek(fd, offset, SEEK_SET);
if(pos == -1) {
fprintf(stderr, "Failed to seek /dev/mem: %s\n", strerror(errno));
exit(1);
}
}
In function get_page_frame_number_of_address.
Please confirm open file success.
FILE *pagemap = fopen("/proc/self/pagemap", "rb");
Check the pagemap is NULL or not.
Here is my code. I'm assuming this has something to do with improper use of pointers or maybe I'm not mapping and unmapping my memory correctly.
Could anyone please provide me with some insight into the issue?
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <ftw.h>
#include <sys/stat.h>
#include <string.h>
int size;
int map1, map2;
void *tar, *temp;
int callback(const char *filename,
const struct stat *sb2,
int filetype,
struct FTW *ftw)
{
printf("test");
if(sb2->st_size == sb1->st_size){
temp = mmap(NULL, sb2->st_size, PROT_NONE, 0, map2, 0);
int cmp = memcmp(tar, temp, sb2->st_size);
printf("%d\n", cmp);
if(cmp == 0){
printf("%s\n", filename);
}
if(munmap(temp,sb2->st_size) == -1){
fprintf(stderr, "Error in unmapping in callback function");
exit(EXIT_FAILURE);
}
}
return 0; //continue to walk the tree
}
int main(int argc, char *argv[])
{
//check for correct arguments
if (argc == 1 || argc > 3) {
fprintf(stderr, "Syntax: %s filename dirname\n", argv[0]);
exit(EXIT_FAILURE);
}
//use stat to get size of filename
struct stat sb1;
if(stat(argv[1],&sb1) != 0){
fprintf(stderr, "Error in stat().");
exit(EXIT_FAILURE);
}
size = sb1.st_size;
//fd = mmap filename
tar = mmap(NULL,sb1->st_size, PROT_WRITE, MAP_SHARED, map1, 0);
if(tar == 0){
fprintf(stderr, "Main() mmap failed");
exit(EXIT_FAILURE);
}
//walk through the directory with callback function
nftw(argv[2], callback, 20, 0);
// use munmap to clear fd
if (munmap(tar,sb1->st_size) == -1) {
fprintf(stderr, "Error in unmapping");
exit(EXIT_FAILURE);
}
}
EDIT
I now declare my struct stat sb1 right before I use the stat function. After doing that I receieved a segmentation error again. I then commented out my nftw() call and and printed out the size variable (which has a reasonable number so I believe that's working). The new error is:
Error in unmapping.
You declare:
struct stat *sb1;
You use:
stat(argv[1],sb1);
You crash and burn because sb1 is a null pointer (since the variable is defined at file scope, it is initialized with 0).
You need to declare (at file scope):
struct stat sb1;
And then in main() you can use:
if (stat(argv[1], &sb1) != 0)
...oops...
You'll have to review all uses of sb1 to fix the status change from pointer to object, adding an & where necessary, and changing -> to . where necessary.
mmap() by example
This is a mildly edited version of a function I wrote that uses mmap() to map a file into memory:
/* Map named file into memory and validate that it is a MSG file */
static int msg_mapfile(const char *file)
{
int fd;
void *vp;
struct stat sb;
if (file == 0)
return(MSG_NOMSGFILE);
if ((fd = open(file, O_RDONLY, 0)) < 0)
return(MSG_OPENFAIL);
if (fstat(fd, &sb) != 0)
{
close(fd);
return(MSG_STATFAIL);
}
vp = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if (vp == MAP_FAILED)
return(MSG_MMAPFAIL);
The MSG_xxxx constants are distinct error numbers applicable to the program it came from. It was only needing to read the file, hence the PROT_READ; I think you may be OK with that too.
if (argc == 1 || argc > 3) {
fprintf(stderr, "Syntax: %s filename dirname\n", argv[0]);
exit(EXIT_FAILURE);
}
/* ... */
nftw(argv[2], callback, 20, 0);
I see a possibility for argv[2] to be NULL. Perhaps you meant:
if (argc != 3) {
fprintf(stderr, "Syntax: %s filename dirname\n", argv[0]);
exit(EXIT_FAILURE);
}
Which book are you reading?
I am trying to write a file with data into my shared memory segment. However everything I have tried seems just to give the error Segmentation fault. I have been searching the internet for help for more then one day.
int main(int argc, char *argv[]).
{
int sm;
char *data;
int pid=atoi(argv[1]);
int key=atoi(argv[2]);
char (*d)[1025];
data=(char*) malloc(1025);
//put the data in the shared memory segment
FILE *file=fopen(argv[3], "r"); //r for read
if (file==0)
{printf("Could not open file");}
else
{
while(fgets(data, 1025, file)!=NULL)
{
fputs(data, file);
// puts(d);
}
fclose(file);
}
//access shared memory
//S_IWUSR gives owner the write permession
sm = shmget(key, 1024, S_IWUSR);
//create a pointer to the shared memory segment
d = shmat(sm, (void *)0, 0); //shared memory id, shmaddr, shmflg
//for (int j=0; j<100; j++)
strcpy(d[0], data);
shmdt(d); //detach the shared memory segment
//remove the shared memory segment
shmctl(sm, IPC_RMID, NULL);
}
Any help would be greatly appreciated
Thanks in advance
EDIT: added malloc
EDIT2: maybe I should rephrase my question, my problem is to get the data into my shared memory
+1 about rjayavrp answer
And I can add that data is not allocated... This is just a pointer and not a array of chars..
Moreover what are you trying to do with
char (*d)[1025];
A quick and dirty example :
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SIZE_SHARED_MEMORY 1024
int main(int argc, char *argv[])
{
int sm = -1;
char *d = NULL;
FILE *file = NULL;
key_t key = 0;
int ret = 0;
if (argc != 4)
{
return 1;
}
key = atoi(argv[2]);
//access shared memory
sm = shmget(key, SIZE_SHARED_MEMORY, IPC_CREAT | 0600);
if (sm == -1)
{
perror("shmget : Failed");
return 2;
}
//create a pointer to the shared memory segment
d = shmat(sm, (char *)0, 0);
if (d == (void *)-1)
{
perror("shmat : Failed");
return 3;
}
// Open the file
file = fopen(argv[3], "r");
if (file == NULL)
{
perror("fopen : Failed");
ret = 4;
}
else
{
if(fgets(d, SIZE_SHARED_MEMORY, file) == NULL)
{
perror("fgets : Failed");
ret = 5;
}
fclose(file);
}
shmdt(d); //detach the shared memory segment
// remove the shared memory segment ???
// Don't understand why you are doing this
shmctl(sm, IPC_RMID, NULL);
return ret;
}
File is opened in read mode only.
change it to rw+ which will open a file in read/write mode. If the file is not available, it will be created.
fputs(data, file); here file is opened in read-only mode but write is happening.
But Im not sure, why you trying to write the read data to same file. You should consider your design first. 2. char (*d)[1025]; is a pointer to an char array of size 1025. You are using it in strcpy(). 3. memory should be allocated for data either statically or dynamically.