Use mmap to put content into an allocated memory region - c

I have tried to read documentation on mmap but I am still having a hard time understanding how to use it.
I want to take an argument from the command line and then allocate it to an executable memory region. Then I want to be able to execute from that code.
This is what I have so far:
int main(int argc, char const *argv[]) {
if (argc != 2) {
printf("Correct input was not provided\n");
exit(1);
}
char assembly_code[sizeof argv[1]];
const char *in_value = argv[1];
int x = sscanf(in_value, "%02hhx", assembly_code);
if (x != 1) {
printf("sscanf failed, exited\n");
exit(1);
}
void * map;
size_t ac_size = sizeof(assembly_code) / sizeof(assembly_code[0]);
map = mmap(NULL, ac_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS, -1, 0);
if (map == MAP_FAILED) {
printf("Mapping failed\n");
exit(1);
}
((void (*)(void))map)();
return 0;
}
This is the output/error I am getting: Mapping failed
I don't know if I am using mmap correctly. And if I am I don't believe I am executing it correctly.
For example if this file is run with an argument e8200000004889c64831c048ffc04889c74831d2b2040f054831c0b83c0000004831ff0f05e806000000584883c008c3ebf84869210a it should return Hi! and then terminate. I don't really know how to get this output after the map or how to "call/execute" a mmap.

int x = sscanf(read, "%02hhx", assembly_code);
This only converts a single byte. I don't think there is a standard library function to convert a whole string of hex bytes; you'll have to call sscanf in a loop, incrementing pointers within the input buffer read and the output buffer assembly_code as appropriate.
In your mmap call, if you don't want to map a file, you should use the flag MAP_ANONYMOUS instead of MAP_SHARED. You should also check its return value (it returns MAP_FAILED on error) and report any error. Also, the return value is in principle of type void * instead of int * (though this should make no difference on common Unix systems).
The mmap call (after being fixed) will return a pointer to a block of memory filled with zeros. There is no reason for it to contain your assembly_code, so you'll have to copy it there, perhaps with memcpy. Or you could move your loop and parse the hex bytes directly into the region allocated with mmap.
Your ((void (*)(void))map)(); to transfer control to the mapped address appears to be correct, so once you have the block correctly mapped and populated, it should execute your machine code. I haven't tried to disassemble the hex string you provided to see if it actually would do what you are expecting, but hopefully it does.
Also, read is not a very good name for a variable, since there is also a standard library function by that name. Your code will work, since the local variable shadows the global object, but it would be clearer to choose another name.
Oh, and char assembly_code[sizeof argv[1]]; isn't right. Think carefully about what sizeof does and doesn't do.

Related

Sending exec output from function to main method

I have a method I call from the main method called that executes ls-l on a certain directory, I want it to execute it and send the result as a string to the main method.
My current flawed code:
char *lsl(){
char *stringts=malloc(1024);
chdir("/Users/file/path");
char * lsargs[] = { "/bin/ls" , "-l", NULL};
stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
return stringts;
}
Currently I am only getting the exec output on the screen, I understand why this is happening(exec getting called before reaching return point). However I don't know how I could possibly do what I want and if it's actually doable.
I was thinking of using pipes and dup2() so I don't let the exec function use stdout but I don't know if it would be possible to put the output in a string.
As Jonathan Leffler already pointed out in comments, there is no '+' operator for concatenating strings in C.
A possibility to dynamically extends strings is to use realloc together with strcat.
For each number of bytes you read from the pipe, you could check the remaining capacity of the originally allocated memory for the string and, if this is not enough, reallocate twice the size.
You have to keep track of the size of the current string yourself. You could do this with a variable of type size_t.
If you combine this with the popen handling, it could look something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *fp;
if ((fp = popen("ls -l", "r")) == NULL) {
perror("popen failed");
return EXIT_FAILURE;
}
size_t str_size = 1024;
char *stringts = malloc(str_size);
if (!stringts) {
perror("stringts allocation failed");
return EXIT_FAILURE;
}
stringts[0] = '\0';
char buf[128];
size_t n;
while ((n = fread(buf, 1, sizeof(buf) - 1, fp)) > 0) {
buf[n] = '\0';
size_t capacity = str_size - strlen(stringts) - 1;
while (n > capacity) {
str_size *= 2;
stringts = realloc(stringts, str_size);
if (!stringts) {
perror("stringts realloation failed");
return EXIT_FAILURE;
}
capacity = str_size - strlen(stringts) - 1;
}
strcat(stringts, buf);
}
printf("%s\n", stringts);
free(stringts);
if (pclose(fp) != 0) {
perror("pclose failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
You have several flaws in your code:
char *lsl(){
char *stringts=malloc(1024);
chdir("/Users/file/path");
char * lsargs[] = { "/bin/ls" , "-l", NULL};
stringts="The result of ls-l in the created directory is:"+ execv(lsargs[0], lsargs);
return stringts;
}
If you malloc(3) a 1024 byte buffer into stringts pointer, but then you assign a different value to the pointer, making your buffer to be lost in the immensity of your RAM.
When you do execv(2) call, all the memory of your process is freed by the kernel and reloaded with an execution of the command ls -l, you'll get the output in the standard output of the process, and then you'll get the prompt of the shell. This makes the rest of your program unuseful, as once you exec, there's no way back, and your program is unloaded and freed.
You can add (+) to a pointer value (you indeed add to the address pointing to the string "The result of the ls -l..." and ---as the result of exec is nothing, as a new program is loaded--- you get nothing) If execv fails, then you get a pointer pointing to the previous char to that string, which is a valid expression in C, but makes your program to behave erratically in an Undefined Behaviour. Use strcpy(3), strcat(3), or snprintf(3), depending on the exact text you want to copy in the space of the buffer you allocated.
Your return an invalid address as a result. The problem here is that, if execv(2) works, it doesn't return. Only if it fails you get an invalid pointer that you cannot use (by the reason above), and of course ls -l has not been executed. Well, you don't say what you got as ouptut, so it is difficult for me to guess if you actually exec()d the program or not.
On other side, you have a popen(3) library function that allows you to execute a subprogram and allows you to read from a file descriptor its output (I recommend you not to chdir gratuitously in your program, as that is a global change in your program environment, IMHO it is better to pass ls(1) the directory you want to list as a parameter)
#include <stdio.h>
FILE *lsl() {
/* the call creates a FILE * descriptor that you can use as input and
* read the output of the ls command. It's bad resources use to try to
* read all in a string and return the string instead. Better read as
* much as you can/need and then pclose() the descriptor. */
return popen("/bin/ls -l /Users/file/path|", "rt");
}
and then you can read (as it can be very long output, you probably don't have enought buffer space to handle it all in memory if you have a huge directory)
FILE *dir = lsl();
if (dir) {
char buffer[1024];
while (fgets(buffer, sizeof buffer, dir)) {
process_line_of_lsl(buffer);
}
pclose(dir); /* you have to use pclose(3) with popen(3) */
}
If you don't want to use popen(3), then you cannot use execv(2) alone, and you have to fork(2) first, to create a new process, and exec() in the child process (after mounting the redirection yourself). Read a good introduction to fork()/exec() and how to redirect I/O between fork() and exec(), as it is far longer and detailed to put it here (again)

raw bin to coff conversion

I wonder if in such case i get a .bin file with the raw contents
of some procedure (x86-32) is it possible to convert this with some tool
(or if it is at all possible) to some linkable object file (like coff)
which i can link and use (for example with GCC)
Speciffically it seem to me that when converting i shoulf gabe some
export symbol name, dont know what with import symbol names,
also do not know if some reallocation table would be needed
to use this with such bonary or it is not needed and can be build
at the process of conversion, i dont manage to understand what is
going on with this realocation data
is it possible to convert data such way? could someone explain this?
Your best bet would be to write a normal C program that reads the contents of the .bin file, into memory that you've allocated as executable, and call it.
This (completely untested) program allocates read/write/execute -able memory with VirtualAlloc. A function pointer (func) that returns nothing and takes no parameters is pointed to the beginning of the buffer, and then called (just like a normal C function).
This assumes that your .bin starts (at offset 0) with a "normal" function that can be call'd.
#include <stdio.h>
#include <Windows.h>
int main(int argc, char** argv)
{
FILE* f;
int size;
// A function pointer to your binary blob.
// Change this prototype, depending on the function you're calling
void (*func)(void);
if (argc < 2) exit(1);
f = fopen(argv[1], "rb");
if (!f) exit(1);
// Get file size
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
// Allocate executable buffer
buf = VirtualAlloc(NULL,
size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
// Read the file into the buffer
if (fread(buf, 1, size, f) != size)
exit(1);
// Point your function pointer to the buffer
func = (void*)buf;
// ...and call it
func();
return 0;
}

Reading a large file using C (greater than 4GB) using read function, causing problems

I have to write C code for reading large files. The code is below:
int read_from_file_open(char *filename,long size)
{
long read1=0;
int result=1;
int fd;
int check=0;
long *buffer=(long*) malloc(size * sizeof(int));
fd = open(filename, O_RDONLY|O_LARGEFILE);
if (fd == -1)
{
printf("\nFile Open Unsuccessful\n");
exit (0);;
}
long chunk=0;
lseek(fd,0,SEEK_SET);
printf("\nCurrent Position%d\n",lseek(fd,size,SEEK_SET));
while ( chunk < size )
{
printf ("the size of chunk read is %d\n",chunk);
if ( read(fd,buffer,1048576) == -1 )
{
result=0;
}
if (result == 0)
{
printf("\nRead Unsuccessful\n");
close(fd);
return(result);
}
chunk=chunk+1048576;
lseek(fd,chunk,SEEK_SET);
free(buffer);
}
printf("\nRead Successful\n");
close(fd);
return(result);
}
The issue I am facing here is that as long as the argument passed (size parameter) is less than 264000000 bytes, it seems to be able to read. I am getting the increasing sizes of the chunk variable with each cycle.
When I pass 264000000 bytes or more, the read fails, i.e.: according to the check used read returns -1.
Can anyone point me to why this is happening? I am compiling using cc in normal mode, not using DD64.
In the first place, why do you need lseek() in your cycle? read() will advance the cursor in the file by the number of bytes read.
And, to the topic: long, and, respectively, chunk, have a maximum value of 2147483647, any number greater than that will actually become negative.
You want to use off_t to declare chunk: off_t chunk, and size as size_t.
That's the main reason why lseek() fails.
And, then again, as other people have noticed, you do not want to free() your buffer inside the cycle.
Note also that you will overwrite the data you have already read.
Additionally, read() will not necessarily read as much as you have asked it to, so it is better to advance chunk by the amount of the bytes actually read, rather than amount of bytes you want to read.
Taking everything in regards, the correct code should probably look something like this:
// Edited: note comments after the code
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
int read_from_file_open(char *filename,size_t size)
{
int fd;
long *buffer=(long*) malloc(size * sizeof(long));
fd = open(filename, O_RDONLY|O_LARGEFILE);
if (fd == -1)
{
printf("\nFile Open Unsuccessful\n");
exit (0);;
}
off_t chunk=0;
lseek(fd,0,SEEK_SET);
printf("\nCurrent Position%d\n",lseek(fd,size,SEEK_SET));
while ( chunk < size )
{
printf ("the size of chunk read is %d\n",chunk);
size_t readnow;
readnow=read(fd,((char *)buffer)+chunk,1048576);
if (readnow < 0 )
{
printf("\nRead Unsuccessful\n");
free (buffer);
close (fd);
return 0;
}
chunk=chunk+readnow;
}
printf("\nRead Successful\n");
free(buffer);
close(fd);
return 1;
}
I also took the liberty of removing result variable and all related logic since, I believe, it can be simplified.
Edit: I have noted that some systems (most notably, BSD) do not have O_LARGEFILE, since it is not needed there. So, I have added an #ifdef in the beginning, which would make the code more portable.
The lseek function may have difficulty in supporting big file sizes. Try using lseek64
Please check the link to see the associated macros which needs to be defined when you use lseek64 function.
If its 32 bit machine, it will cause some problem for reading a file of larger than 4gb. So if you are using gcc compiler try to use the macro -D_LARGEFILE_SOURCE=1 and -D_FILE_OFFSET_BITS=64.
Please check this link also
If you are using any other compiler check for similar types of compiler option.

Using MapViewOfFile, pointer eventually walks out of memory space

All,
I'm using MapViewOfFile to hold part of a file in memory. There is a stream that points to this file and writes to it, and then is rewound. I use the pointer to the beginning of the mapped file, and read until I get to the null char I write as the final character.
int fd;
yyout = tmpfile();
fd = fileno(yyout);
#ifdef WIN32
HANDLE fm;
HANDLE h = (HANDLE) _get_osfhandle (fd);
fm = CreateFileMapping(
h,
NULL,
PAGE_READWRITE|SEC_RESERVE,
0,
4096,
NULL);
if (fm == NULL) {
fprintf (stderr, "%s: Couldn't access memory space! %s\n", argv[0], strerror (GetLastError()));
exit(GetLastError());
}
bp = (char*)MapViewOfFile(
fm,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (bp == NULL) {
fprintf (stderr, "%s: Couldn't fill memory space! %s\n", argv[0], strerror (GetLastError()));
exit(GetLastError());
}
Data is sent to the yyout stream, until flushData() is called. This writes a null to the stream, flushes, and then rewinds the stream. Then I start from the beginning of the mapped memory, and read chars until I get to the null.
void flushData(void) {
/* write out data in the stream and reset */
fprintf(yyout, "%c%c%c", 13, 10, '\0');
fflush(yyout);
rewind(yyout);
if (faqLine == 1) {
faqLine = 0; /* don't print faq's to the data file */
}
else {
char * ps = bp;
while (*ps != '\0') {
fprintf(outstream, "%c%c", *ps, blank);
ps++;
}
fflush(outfile);
}
fflush(yyout);
rewind(yyout);
}
After flushing, more data is written to the stream, which should be set to the start of the memory area. As near as I can determine with gdb, the stream is not getting rewound, and eventually fills up the allocated space.
Since the stream points to the underlying file, this does not cause a problem initially. But, when I attempt to walk the memory, I never find the null. This leads to a SIGSEV. If you want more details of why I need this, see here.
Why am I not reusing the memory space as expected?
I think this line from the MSDN documentation for CreateFileMapping might be the clue.
A mapped file and a file that is accessed by using the input and output (I/O) functions (ReadFile and WriteFile) are not necessarily coherent.
You're not apparently using Read/WriteFile, but the documentation should be understood in terms of mapped views versus explicit I/O calls. In any case, the C RTL is surely implemented using the Win32 API.
In short, this approach is problematic.
I don't know why changing the view/file size helps; perhaps it just shifts the undefined behaviour in a direction that happens to be beneficial.
Well, after working on this for a while, I have a working solution. I don't know why this succeeds, so if someone comes up with something better, I'll be happy to accept their answer instead.
fm = CreateFileMapping(
h,
NULL,
PAGE_READWRITE|SEC_RESERVE,
0,
16384,
NULL);
As you can see, the only change is to the size declared from 4096 to 16384. Why this works when the total chars input at a time is no more than 1200, I don't know. If someone could provide details on this, I would appreciate it.
When you're done with the map, simply un-map it.
UnmapViewOfFile(bp);

Seg fault with open command when trying to open very large file

I'm taking a networking class at school and am using C/GDB for the first time. Our assignment is to make a webserver that communicates with a client browser. I am well underway and can open files and send them to the client. Everything goes great till I open a very large file and then I seg fault. I'm not a pro at C/GDB so I'm sorry if that is causing me to ask silly questions and not be able to see the solution myself but when I looked at the dumped core I see my seg fault comes here:
if (-1 == (openfd = open(path, O_RDONLY)))
Specifically we are tasked with opening the file and the sending it to the client browser. My Algorithm goes:
Open/Error catch
Read the file into a buffer/Error catch
Send the file
We were also tasked with making sure that the server doesn't crash when SENDING very large files. But my problem seems to be with opening them. I can send all my smaller files just fine. The file in question is 29.5MB.
The whole algorithm is:
ssize_t send_file(int conn, char *path, int len, int blksize, char *mime) {
int openfd; // File descriptor for file we open at path
int temp; // Counter for the size of the file that we send
char buffer[len]; // Buffer to read the file we are opening that is len big
// Open the file
if (-1 == (openfd = open(path, O_RDONLY))) {
send_head(conn, "", 400, strlen(ERROR_400));
(void) send(conn, ERROR_400, strlen(ERROR_400), 0);
logwrite(stdout, CANT_OPEN);
return -1;
}
// Read from file
if (-1 == read(openfd, buffer, len)) {
send_head(conn, "", 400, strlen(ERROR_400));
(void) send(conn, ERROR_400, strlen(ERROR_400), 0);
logwrite(stdout, CANT_OPEN);
return -1;
}
(void) close(openfd);
// Send the buffer now
logwrite(stdout, SUC_REQ);
send_head(conn, mime, 200, len);
send(conn, &buffer[0], len, 0);
return len;
}
I dunno if it is just a fact that a I am Unix/C novice. Sorry if it is. =( But you're help is much appreciated.
It's possible I'm just misunderstanding what you meant in your question, but I feel I should point out that in general, it's a bad idea to try to read the entire file at once, in case you deal with something that's just too big for your memory to handle.
It's smarter to allocate a buffer of a specific size, say 8192 bytes (well, that's what I tend to do a lot, anyway), and just always read and send that much, as much as necessary, until your read() operation returns 0 (and no errno set) for end of stream.
I suspect you have a stackoverflow (I should get bonus points for using that term on this site).
The problem is you are allocating the buffer for the entire file on the stack all at once. For larger files, this buffer is larger than the stack, and the next time you try to call a function (and thus put some parameters for it on the stack) the program crashes.
The crash appears at the open line because allocating the buffer on the stack doesn't actually write any memory, it just changes the stack pointer. When your call to open tries tow rite the parameters to the stack, the top of the stack is now overflown and this causes a crash.
The solution is as Platinum Azure or dreamlax suggest, read in the file little bits at a time or allocate your buffer on the heap will malloc or new.
Rather than using a variable length array, perhaps try allocated the memory using malloc.
char *buffer = malloc (len);
...
free (buffer);
I just did some simple tests on my system, and when I use variable length arrays of a big size (like the size you're having trouble with), I also get a SEGFAULT.
You're allocating the buffer on the stack, and it's way too big.
When you allocate storage on the stack, all the compiler does is decrease the stack pointer enough to make that much room (this keeps stack variable allocation to constant time). It does not try to touch any of this stacked memory. Then, when you call open(), it tries to put the parameters on the stack and discovers it has overflowed the stack and dies.
You need to either operate on the file in chunks, memory-map it (mmap()), or malloc() storage.
Also, path should be declared const char*.

Resources