简体   繁体   中英

prevent overwriting to WRITE function for char driver linux

My driver must write from the user buffer to a char array called msg, which is in global scope

//global scope
...
#define SIZE 64;
char msg[SIZE];
...

So this is the write function.

static ssize_t  Dev_Write(struct file *flip, const char __user *buffer, size_t length, loff_t *offset)
    {

        copy_from_user(msg + *offset, buffer, length); //I hope *offset = 0 at the first call
        printk(KERN_INFO "message from UserSpace is: %s \n", msg);
        *offset += length;

        return length;
    }

When I invoke this function two times in sequence, it overwrites the first data in msg. I want it just to continue from the last position. I think I must do something with *offset

This is the user program:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <iostream>
using namespace std;

#define BUFFER_SIZE 64

int main (int argc, char ** argv)
{
    int fd;
    ssize_t read_bytes;
    ssize_t written_bytes;
    char buffer[BUFFER_SIZE] = "aaaaaa";
    char buffer1[BUFFER_SIZE] = "bbbbbb";
    char buffer2[BUFFER_SIZE];
    fd = open ("/dev/2", O_RDWR);
    if (fd < 0)
    {
        fprintf (stderr, "Cannot open file\n");
        exit (1);
    }   


    written_bytes = write (fd, buffer, BUFFER_SIZE);
    write (fd, buffer1, BUFFER_SIZE);
    read_bytes = read (fd, buffer2, BUFFER_SIZE);
    cout<<buffer<<endl;
    if(written_bytes < 0)
    {
        fprintf (stderr, "myread: Cannot write to file\n");
        exit (1);
    }
    if (read_bytes < 0)
    {
        fprintf (stderr, "myread: Cannot read from file\n");
        exit (1);
    }
    close (fd);
    exit (0);
}

Thank you.

While the root problem isn't entirely clear, you do have a bug that's pushing you into undefined behaviour. Your user space program is writing 64 bytes ( BUFFER_SIZE ) each time, but your kernel buffer is only 64 bytes long. The second write will cause an overflow.

To debug your problems, take the following steps. At the entry to your write function debug the length and offset of your message:

printk(KERN_INFO "Size from userspace is: %d offset %d\n", length, *offset);

Also, clamp your copy size so you don't overwrite the buffer:

if (*offset > SIZE)
    return -ENOSPC;
if (*offset + length > SIZE)
    length = SIZE - *offset;

After these tests you can carry out your copy_from_user . The tests are necessary, but I'm not sure that they are a sufficient fix. The debug line may reveal that something else is confounding the situation.

I think I must do something with *offset

Yes, you indeed ought to. That is to say, you can ignore setting the file position if your driver does not have a concept of file position (like a pipe or socket). And to be able to set this file position, offset is a pointer, so that you can modify the value such that it is visible outside. (You also need a lot more safety checks in your code to assure you don't write past the end of the buffer.) *offset += whatever is just right. Note that the file offset need not be measured in bytes, you can also count in "records" or whatever else floats your boats.

I resolved my problem.

I had to add to *offset the real length of data in buffer.

copy_from_user(msg + *offset, buffer, length); 
printk(KERN_INFO "message from UserSpace is: %s \n", msg);
*offset += strlen(buffer);

Thank You in advance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM