Как я могу выделить память в ядре Linux для символа* строка типа?

Я пытаюсь выделить некоторую память для символа* следующим образом.

static ssize_t memo_write(struct file *filp, const char __user *buf, 
   size_t count, loff_t *f_pos){
    ssize_t retval = -ENOMEM;
    printk("write function\n");

    if((data = kmalloc(strlen(buf), GFP_KERNEL)) == NULL)
        printk("kmalloc fail\n");

    if(copy_from_user(data, buf, strlen(buf))){
        retval = -EFAULT;
        goto out;
    }
    *f_pos += strlen(buf);
    retval = strlen(buf);

    out:
        return retval;
}

'данные' объявляются в заголовочном файле как

char *data;

Когда я вызываю функцию записи, 'kmalloc сбой' строка не достигнута, который приводит меня верить kmalloc, за которым следуют, однако данные не отображены, когда я пытаюсь читать из переменной 'данных' снова.

Более смутно, если я избавляюсь от бита kmalloc в целом, данные могут быть считаны с драйвера. Хотя проблема затем - это, сопровождается загрузкой других данных, потому что у меня нет возможности к memset () им.

Я использую kmalloc правильно? По-видимому, нет. Как я должен делать это?

Кроме того, моя функция чтения следующие.

static ssize_t memo_read(struct file *f, char __user *buf, 
    size_t count, loff_t *f_pos){
    ssize_t retval = 0;

    printk("read function\n");
    printk("data = %s\n", data);

    if(*f_pos >= strlen(data)){
        printk("EOF\n");
        goto out;
    }

    if(copy_to_user(buf, data, strlen(data))){
        retval = -EFAULT;
        goto out;
    }
    printk("copy_to_user success\n");
    *f_pos += strlen(data);
    retval = strlen(data);
    out:
        return retval;
}

Спасибо.

9
задан Sagar Jain 4 April 2014 в 11:24
поделиться

2 ответа

Вы должны использовать strlen_user () на указателе пользователей, вместо strlen () - и вы должны позвонить только один раз, и сохранить Результат вокруг (в противном случае у вас есть потенциальная эксплуатация ядра, потому что вторая нить пользователя может изменить буфер, пока вы работаете над этим).

В качестве альтернативы вы можете использовать STRNCPY_FROM_USER () .

Помимо этого KMALLOC выглядит нормально.


(Но на самом деле, как Ephemient говорит, что вы должны переосмыслить весь ваш подход и использовать аргумент , вместо того, чтобы лечить вход в виде строки).


Поскольку вы не можете полагаться на данные, записанные в файл, являющиеся Nul-завершающимися строками, вам нужно будет сохранить параметр длины data_Len рядом с данными . Тогда ваш прочитал / Написать Реализации будет вдоль этих строк:

static char *data = NULL;
static size_t data_len;
static DEFINE_MUTEX(data_mutex);

static ssize_t memo_read(struct file *f, char __user *buf, size_t count, loff_t *f_pos
{
    ssize_t retval = 0;
    char *start;

    mutex_lock(&data_mutex);

    if (!data)
    {
        retval = -EINVAL; /* Or whatever you want to do here... */
        goto out;
    }

    if (*f_pos >= data_len)
        goto out; /* EOF */

    start = data + *f_pos;
    retval = data_len - *f_pos;

    if (retval > count)
        retval = count;

    if (copy_to_user(buf, start, retval))
    {
        retval = -EFAULT;
        goto out;
    }

    *f_pos += retval;

out:
    mutex_unlock(&data_mutex);
    return retval;
}

static ssize_t memo_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    ssize_t retval = -ENOMEM;

    mutex_lock(&data_mutex);

    if (data)
        kfree(data);

    data = kmalloc(count, GFP_KERNEL);

    if (!data)
        goto out;

    if (copy_from_user(data, buf, count))
    {
        kfree(data);
        retval = -EFAULT;
        goto out;
    }

    *f_pos = count;
    retval = count;
    data_len = count;

out:
    mutex_unlock(&data_mutex);
    return retval;
}
11
ответ дан 4 December 2019 в 13:01
поделиться

Как насчет карты / словаря? Последний я проверил, это выступление (1).

-121--3702273-

Не забывайте KFREE (данные) в ваших случаях ошибок ...

в любом случае BUF является указателем на Пользовательская память, так что не звоните Стрелок (BUF) . Вы должны copy_from_user сначала. Почему нет

data = kmalloc(count);
copy_from_user(data, buf, count);

?


Ваш обработчик чтения предполагает, что данные представляют собой строку NUL. Когда вы использовали массив, это, возможно, было верно случайно, но вы никогда не убедитесь, что это в вашем обработчике записи. Я предполагаю, что copy_to_user не удается.

Вот рабочий пример модуля «Memo», который я записал только сейчас, используя kmalloc :

#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/uaccess.h>

static char *data;
static size_t len;

static ssize_t
memo_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
        ssize_t copy_len = min(len - min(len, *ppos), count);
        ssize_t retval;

        if (copy_to_user(buf, data + *ppos, copy_len)) {
                retval = -EFAULT;
                goto out;
        }

        *ppos += copy_len;
        retval = copy_len;

out:
        return retval;
}

static ssize_t
memo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
        ssize_t retval;
        char *newdata;

        newdata = kmalloc(count, GFP_KERNEL);
        if (!newdata) {
                retval = -ENOMEM;
                goto out;
        }

        if (copy_from_user(newdata, buf, count)) {
                retval = -EFAULT;
                goto out;
        }

        kfree(data);
        data = newdata;
        newdata = NULL;
        retval = len = count;

out:
        kfree(newdata);
        return retval;
}

static const struct file_operations memo_fops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
        .read = memo_read,
        .write = memo_write,
};

static struct miscdevice memo_misc = { MISC_DYNAMIC_MINOR, "memo", &memo_fops };

static int __init memo_init(void)
{
        int result;

        result = misc_register(&memo_misc);
        if (result < 0)
                return -ENODEV;

        return 0;
}

static void __exit memo_exit(void)
{
        misc_deregister(&memo_misc);
        kfree(data);
        return;
}

module_init(memo_init);
module_exit(memo_exit);
MODULE_AUTHOR("ephemient");
MODULE_LICENSE("GPL");

Конечно, это отсутствует блокировка и другие меры предосторожности, но я надеюсь, что это поможет.

5
ответ дан 4 December 2019 в 13:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: