How to convert size_t to char* in kernel C? - 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.

Related

Am I correctly implementing copy_from_user?

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.

Passing a char buffer to function

I have some problems with a pointer. My idea was to pass a buffer to a function in order to store the return data in this buffer. But, I do not know if it will work.
void main()
{
char *buf = malloc(sizeof(char) *buf);
memset(buf, 0x00, BUF_SIZE);
sendCommand(buf);
}
sendCommand(char *buf)
{
write(fd, "some commands", strlen("some commands"));
readResponse(buf);
}
readResponse(char *buf)
{
read(fd, buf, nbytes);
}
I know there is no error handling up to now. And some variables are not well defined. It just depends on the passing buffer. Will I see the data that I get in readResponse() in my main function?
As in readResponse() as you read nbytes into buffer pointed by buf ,so you will get that data in main .
Some improvements to be done -
1. void main() -> int main(void) or int main(int argc, char *argv[])
2. char *buf = malloc(sizeof(char) *buf); -> char *buf = malloc(BUF_SIZE); // sizeof(char)=1 or maybe something you desire (not sure though what you want ??)
Note - remember to free allocated memory.
You have a remarkable number of significant problems in the code you presented, considering how short it is. Other answers have addressed those, though, and your question is not actually about any of them:
Will I see the data I get in readResponse() in my main function?
Yes, provided that argument buf is a pointer to an array large enough to accommodate nbytes bytes, and that the read() call in fact successfully reads any bytes, those bytes will afterward be visible in main() via the pointer it passed to readResponse(). More generally, if you pass a pointer as a function argument, the called function may manipulate the pointed-to object, including by modifying those parts of it that are not const. That's how the read() function itself is able to store the bytes it reads into your buffer, after all.
This won't do what you think it does:
char *buf = malloc(sizeof(char) *buf);
Did you mean to multiply with BUF_SIZE?

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 */

What to use instead of sizeof(void)?

I'm trying to copy a file. I'm using a borrowed code snippet, and there's a line of it which errors which confuses me.
int fileread = open("original.txt", O_RDONLY);
void *buffer;
buffer = malloc(sizeof(void) * size); /*This line gives "Incomplete type not allowed."*/
int nread = read(fileread,buffer,size);
int filewrite = open("original.txt.backup",O_CREAT | O_RDWR, 0644);
write(filewrite,buffer,size);
close(filewrite);
close(fileread);
What should I be using instead? I was thinking char*, but I want to make sure I'm understanding the process going on here.
If you want to allocate a buffer of size bytes, and have buffer point to the beginning of it:
void *buffer = malloc(size);
if (buffer == NULL) {
/* allocation failed */
}
/* ... */
But if you want to do something with the data in the buffer, it will need to have a valid type. An array of unsigned char is a common way to manage buffers of arbitrary contents:
unsigned char *buffer = malloc(size);
/* as above */
sizeof() returns the size of your type. Honestly I think you should just change it to
char *buffer;
buffer = malloc(sizeof(char) * size);
Sizeof(void) makes zero sense

C - how to correctly use malloc'ed array with C getline function?

I want to use previously malloc'ed array with a C getline function:
ssize_t getline(char **restrict, size_t *restrict, FILE *restrict)
The following code gives me EXC_BAD_ACCESS (code=1, address=0x400) :
FILE *in; if ((in=fopen(inpath, "r+w"))==NULL) exit(1);
char * buf = (char *) malloc (BUFSIZ); // BUFSIZ is constant, equal to 1024
if (getline(&buf, (size_t *)BUFSIZ, in)<0) return 1; // <--- EXC_BAD_ACCESS
How should I modify the code to make it working?
What you are doing now essentially tells getline there's a pointer to the address 1024 and you really want it to dereference it. Pass a real address as the second argument, don't cast an int and hope for the best.
size_t size = BUFSIZ;
getline(&buf, &size, in);

Resources