防止覆盖到char驱动程序linux的WRITE函数

时间:2012-02-23 10:20:47

标签: linux linux-kernel linux-device-driver

我的驱动程序必须从用户缓冲区写入名为msg的char数组,该数组在全局范围内

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

所以这是写函数。

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;
    }

当我按顺序调用此函数两次时,它会覆盖msg中的第一个数据。我希望它只是从最后一个位置继续。 我想我必须用 * offset

做点什么

这是用户程序:

#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);
}

谢谢。

3 个答案:

答案 0 :(得分:2)

虽然根本问题并不完全清楚,但你确实有一个错误,它将你推入未定义的行为。您的用户空间程序每次写入64个字节(BUFFER_SIZE),但您的内核缓冲区只有64个字节长。第二次写入会导致溢出。

要调试问题,请执行以下步骤。在写入函数的入口处调试消息的长度和偏移量:

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

另外,请缩小您的副本大小,以免覆盖缓冲区:

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

完成这些测试后,您可以执行copy_from_user。测试是必要的,但我不确定它们是否足够。调试行可能会发现其他东西混淆了这种情况。

答案 1 :(得分:1)

  

我想我必须用* offset

做点什么

是的,你确实应该这样做。也就是说,如果驱动程序没有文件位置的概念(如管道或套接字),则可以忽略设置文件位置。并且为了能够设置此文件位置,offset是一个指针,因此您可以修改该值以使其在外部可见。 (您还需要在代码中进行更多安全检查,以确保不要写入缓冲区的末尾。)*offset += whatever是正确的。请注意,文件偏移量不需要以字节为单位进行测量,您也可以计入“记录”或其他任何浮动您的船只。

答案 2 :(得分:0)

我解决了我的问题。

我必须添加*偏移缓冲区中实际的数据长度。

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

提前谢谢你。