Am I correctly implementing copy_from_user? - c

I am implementing the write file operation for my module, and I want to know if I'm correctly implementing the copy_from_user function. The module is a tictactoe game, so I take an input from the user. Inputs will be strings in the forms, "01 X" or "21 O" where the numbers represent columns and rows and the letters are their pieces. My write function is as follows:
ssize_t tictactoe_write(struct file *pfile, char __user *buffer, size_t length, loff_t *offset){
char* data = kmalloc(sizeof(buffer), GFP_KERNEL);
size_t unread = copy_from_user(data, buffer, sizeof(buffer));
printk(KERN_NOTICE "Written");
//Return number of bytes not read
return unread;
}
With this implementation would the data pointer be initialized with the user input? Which I can then manipulate through the rest of the module? Any help is appreciated.

To elucidate what #Tarracon meant:
ssize_t tictactoe_write(struct file *pfile, char __user *buffer, size_t length, loff_t *offset){
char* data = kmalloc(length, GFP_KERNEL);
size_t unread = copy_from_user(data, buffer, length);
printk(KERN_NOTICE "Written");
//Return number of bytes not read
return unread;
}
Also, you aren't implementing copy_from_user, you are invoking it. Big difference.

Related

Problem to create char based on buffer and length in kernel module

I try to get strings from userspace within the kernel module. Till I set my char size manually it seems working properly. However, I need to make it dynamic so if I use len parameter it shows weird symbols on the end of char.
static ssize_t msecurity_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
char chars[12];
if(copy_from_user(chars,buffer,len)){
return -EFAULT;
}
printk(KERN_ALERT "Output> %s", chars);
printk(KERN_ALERT "lengh> %i", len);
return len;
}
First output is for char[len] secound has been set manualy char[12]. Even if you print len it shows value of 12.
C strings are terminated by a null character. This character is not included in any string length calculation but must be included.
Thus a string of length 12 will need 13 bytes with the last byte equal to 0.

How to convert size_t to char* in kernel C?

I use a size_t variable in my kernel module. when I want to write it to a file it must be cast to char* according to vfs_write signature:
extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
I use this function that uses vfs_write (I found it on internet):
int file_write(struct file *file, unsigned long long offset, unsigned
char *data, unsigned int size)
{
mm_segment_t oldfs;
int ret;
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_write(file, data, size, &offset);
set_fs(oldfs);
return ret;
}
the nbytes variable is size_t I try (char *) cast for convert nbytes to char* but the kernel immediately crashes. here is my code.
index_filename = "/home/rocket/Desktop/index_pool";
index_file = file_open(index_filename,O_WRONLY | O_CREAT, 0644);
if(index_file == NULL)
printk(KERN_ALERT "index_file open error !!.\n");
else{
// file_write(index_file, 0, nbytes, nbytes); => this crashs also
file_write(index_file, 0, (char*) nbytes, 100);
file_close(index_file);
}
Is there a way to safely convert size_t type to char * one in Kernel ?
Of course it would crash - you're trying to write 100 bytes of whatever memory location nbytes is pointing at. Which because it isn't a pointer is extremely unlikely to be a valid area of memory. And even if it was, it might not be 100 bytes in size.
What you want to be passing instead to vfs_write is a pointer to nbytes. And the size of that would be sizeof(nbytes). So you'd call your wrapper function like this
file_write(index_file, 0, (char*) &nbytes, sizeof(nbytes));
That will write out the how ever many bytes that a size_t is at the memory location of nbytes
If you want to write out the value of nbytes, which is different to what you appear to be asking in the question, you need to store it in a string and pass that to your function like this:
char temp_string[20];
sprintf(temp_string,"%zu",nbytes);
file_write(index_file, 0, temp_string, strlen(temp_string));
Is there a way to safely convert size_t type to char * one in Kernel ?
yes there is.
you should use sprintf function in linux/kernel.h library
so you should do something like this:
sprintf(destination_char_star, "%zu", your_s_size_var);
be carefull you should allocate memory to char star if needed.

Trouble with character device driver

I'm a little bit confused about character device driver. I wrote a simple character device driver and it works with strings and simple things. Now I have to implement it and modify the write function to receive an integer N.
Since I have to receive an integer I thought to modify the write function and instead of a char* buffer receive an int* number but when I try to map file_operations with "my_write" terminal gives me an error saying "incompatible array types".
My question is what I have to modify in order to receive an integer with the write function insted of a string
These are my functions:
static ssize_t my_write
(struct file *filp, const char __user *buf, size_t length, loff_t *offset)
{
int nc = 0;
if (length > BUF_LEN)
return BUF_LEN-length;
nc = copy_from_user(msg,buf,length);
msg_ptr = msg;
return length - nc;
}

C Fread Split Textfile into Chunks

i've got a Textfile of Unknown Size and have to send it via Sockets from my Server to the Client in Chunks of a certain (variable Size).
How can i use Fread for that Task? I read alot about Fread but im Struggeling with the kind of Pointer i should pass that function in my Case?
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
How can i use fread for that task?
Simply keep sending chunks (of fixed size) from the Server to the Client, until there is nothing else to be sent by the Serve.
What kind of pointer I should pass that function in my case?
Anything.
Check fread()'s example, where the buffer that is passed in fread() is of type char, and fread() simply allows for it, since the first argument of that function is:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
So just pass the array you are using to store the data (the chunks) to the function.
To read file as chunks and send them to socket you'll have to decide a size of the chunk.
For example: 4096 is perfect size that's not too big or not too small!
Example
We choose 4096 bytes as the chunk size. It's btw customizable.
Send the chunk data to the Client when received from file.
#include <stdio.h>
int main(ssize_t argc, char** argv)
{
// We're going to use "rb" because in (WINDOWS) you need it!
FILE* fp = fopen(argv[1], "rb");
char byte_buffer[4096];
size_t bytes_read = 0;
while(( bytes_read = fread(&byte_buffer, 4096, 1, fp) )> 0)
send_data_chunk_to_client_somehow(/* your parameters here */);
}
The text file should be read in chunks and send them to the Client.
fread(3) ― Binary stream I/O
fread(3) is compatible with both text and binary streams, it's a part of ANSI C. The POSIX read(3) is a equivalent to the function and faster than it.
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp);

How send a binary file in segments over network in C?

I am a bit puzzled over how to send a file from an http server to a client(web-browser).
First I send the header and my next task is to send the file content. However I want to send it in segments of say 512 bytes instead of the whole file at once as I ran into some problems.
I am a bit lost on how to achieve that. Here is what I want
read file1;
while (seg=get_next_segment(file1)){
do
send(seg)
until (seg_is_sent)
}
However I can't seem to find the appropriate functions to achieve that. fread and fseek crossed through my mind but the first one reads the whole file at once and with fseek I don't see a way to just grab a portion from a file(instead of reading from the file pointer until the end of the file).
freaddoes not read a whole file to the end. It reads exactly how much you tell it to read.
size_t
fread(void *restrict ptr, size_t size, size_t nitems,
FILE *restrict stream);
size_t
fwrite(const void *restrict ptr, size_t size, size_t nitems,
FILE *restrict stream);
Both functions take a size and nitems. You could set the size to 512, and the number of items to 1 (or vice versa) and read just that portion of the file.
From the man page:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
The function fread() reads nmemb elements of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.
As you can see, you don't have to read the whole file with fread, you can read it in nmemb size chunks.
If you are writing your own web-server in C, you may want to have a look at libmicrohttpd, which is a web-server in C for embedding into other applications, it can handle streaming a file for you.
I'm feeling kind... How about something like this:
for (;;)
{
char buffer[512];
size_t nread = fread(buffer, sizeof(char), 512, fp);
if (nread > 0)
send_to_socket(buffer, nread);
if (nread < 512)
{
if (feof(fp))
printf("End of file\n");
if (ferror(fp))
printf("Error reading\n");
break;
}
}

Resources