copy_from_user function prints junk values - c

I am trying to print the content of the user space buffer in the kernel space, but I am getting some junk characters and I am not sure where I am going wrong.
SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
unsigned, flags, struct sockaddr __user *, addr,
int, addr_len) {
char *messageRead = kmalloc(len,GFP_KERNEL);
unsigned long bytesNotCopied = copy_from_user(messageRead,(char*)buff,len);
printk("The messageRead Read is %s \n",messageRead);
.....
.....
}
The bytesNotCopied returns 0, so I was able to confirm that the content was copied. but when I tried to print the messageRead value, it is returning me some junk values.

A return value of 0 indicates a successful copy.
Why do you want to print the buffer as string i.e using %s in printk(). Is buff a character string in the user process?. If not try dumping this way
for(i=0; i<len; i++) /*make sure you declare i */
{
printk("%x ",messageRead[i]);
}

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.

Which placeholder for fscanf?

I have a file that I open which has a bunch of lines with data like this:
0x804ae1c: W 0x0000000c
I'm trying to extract the 3 different strings into 3 different variables but I'm having problems getting values from the 2nd and third token.
Here is how I'm trying to do it:
unsigned long address;
unsigned long address2;
char* readWrite;
fscanf(traceFile, "%lx %s %lx\n", &address, line, &address2)
I get the pointer for the first line. i.e:
804ae1c
but after that the other 2 variables do not get the proper things assigned to them. I tried changing line to a char but to no avail. How should I proceed fixing this issue?
Thanks!
First, you need to allocate storage, rather than just declaring a char*. If you are reading only a single character, a simple char is sufficient.
As BLUEPIXY's comment mentions, you need to account for the extra : character in your string. Here is a test program that shows this (reads from stdin).
#include <stdio.h>
int main(){
unsigned long address;
unsigned long address2;
char readWrite;
int retVal;
retVal = scanf("%lx: %c %lx", &address, &readWrite, &address2);
if (retVal == 3) {
printf("%lu: %lu %c\n", address, address2, readWrite);
} else {
fprintf(stderr, "Parsing error\n");
}
}

Modify buffer passed as a pointer

I'm trying to read into a buffer passed as a pointer to this function. memcpy() works fine and the data is stored correctly in buffer, but when I access buffer outside of the function it is null. There's some pointer issue I'm not getting here.
Here's the code, I took out most of it, I know it copies the data correctly, but it doesn't pass it to the buffer pointer. Ideas?
int read(file file, char *buffer , int maxlen) {
int bytes_read;
// copy data to file buffer
bytes_read = min(maxlen, file->file_size - file->cursor);
buffer = (char*) malloc(bytes_read);
memcpy(buffer , file->buffer + file->cursor, bytes_read);
return bytes_read;
}
The problem is pretty simple: you are modifying the variable "buffer". Since it is passed by value and not by reference, the calling function doesn't see the change. In order to make the change to buffer visible, you need to pass in a pointer to buffer.
Your function would then look like this:
int read(file file, char **buffer , int maxlen) {
int bytes_read;
// copy data to file buffer
bytes_read = min(maxlen, file->file_size - file->cursor);
*buffer = (char*) malloc(bytes_read);
memcpy(*buffer , file->buffer + file->cursor, bytes_read);
return bytes_read;
}
to call the function:
rv = read(file, &buffer, maxlen);
You cannot modify buffer directly because C uses pass by value with parameters. Therefore it is a copy of the pointer you are modifying. To change the pointer you need to change your function prototype to take a char** and allocate to the first level of indirection on that.
As a crude example of this:
void read(char** buffer , int byte_size) {
*buffer = (char*) malloc(byte_size);
}
and use where required with something like
char* buffer;
read(&buffer,10); /* now buffer points to dynamically allocated array of 10 chars */

C: A safer way to check buffer in function and append to it?

I have a function of which I need to return the time for another logging function, and it looks like this:
//put time in to buf, format 00:00:00\0
void gettimestr(char buf[9]) {
if(strlen(buf) != 9) { //experimental error checking
fprintf(stderr, "Buf appears to be %d bytes and not 9!\n", strlen( buf ));
}
time_t cur_time;
time(&cur_time);
struct tm *ts = localtime(&cur_time);
sprintf(buf, "%02d:%02d:%02d",
ts->tm_hour,
ts->tm_min,
ts->tm_sec );
strncat(buf, "\0", 1);
}
Now I guess the main problem is checking if the buffer is long enough, sizeof() returns a pointer size and strlen seems to randomly return 0 or something such as 12 on two different calls.
My first question is, how would I be able to detect the size of the buffer safely, is it possible?
My other question is, is accepting buf[9] a favourable method or should I accept a pointer to a buffer, and use strcat() instead of sprintf() to append the time to it? sprintf makes it easier for padding zeros to the time values, although it seems to only accept a character array and not a pointer.
Your function assumes that the buffer being passed in already contains a null-terminated string with 9 characters. That doesn't make sense.
The proper way would be to request the size as an argument:
void gettimestr(char *buf, int bufferSize) {
and use snprintf:
snprintf(buf, bufferSize, "%02dx....", ....);<sub>*</sub>
And terminate the string since snprintf won't do that if you exceed the limit:
buf[bufferSize-1] = 0;
You can call your function like this:
char buffer[16];
gettimestr(buffer, sizeof(buffer));
There is no other way to determine the size. This isn't Java where an array knows its size. Passing a char * will simply send a pointer down to the function with no further information, so your only way to get the size of the buffer is by requiring the caller to specify it.
(EDIT: snprintf should always terminate the string properly, as pointed out in the comments.)
#EboMike is right. Just to complement his answer, you could check the buffer with:
void gettimestr(char *buf, int bufferSize) {
if (!buf) {
fprintf(stderr, "Null buffer\n");
return;
}
// rest of the code
}

Resources