Как отключить чтение или запись в файле proc?

Я создаю файл proc (/proc/key), в который пользователь может записать свой decryption_key, а затем этот ключ будет использоваться для расшифровки содержимого буфера, хранящегося внутри модуля ядра. Кроме того, у меня есть еще одна запись proc (/proc/decrypted), которая будет использоваться для чтения содержимого буфера, в котором хранится расшифрованный текст.

Проблема в том, что я не хочу, чтобы пользователь мог что-либо записывать в файл (/proc/decrypted), и я не хочу, чтобы он читал что-либо из (/proc/key). Как это можно реализовать?

Я указал соответствующие функции внутри структуры file_operations на NULL, но очевидно, что это приведет к ошибкам сегментации, как только пользователь их попробует.

Как я могу предотвратить чтение или запись из procfs? Должен ли я просто создавать функции, у которых нет тела, и при необходимости указывать на них структуру file_operations?

static ssize_t key_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    char temp[128];
    memset(temp, 0, 128);
    int c; 
    c = copy_from_user(temp, buf, count);
 return count;
}


static const struct file_operations Proc_key_fops = {
 .owner = THIS_MODULE,
 .open = hello_proc_open,
 .read = NULL,
 .write = key_proc_write,
 .llseek = seq_lseek,
 .release = single_release,
};  

person Mina Ashraf    schedule 16.04.2021    source источник
comment
Укажите им функцию, которая возвращает код ошибки, например EPERM.   -  person Barmar    schedule 17.04.2021
comment
Также функция open() может проверять, указывают ли они O_RDONLY, O_WRONLY или O_RDWR, и возвращать ошибку для неверного направления.   -  person Barmar    schedule 17.04.2021
comment
@Barmar, как я могу указать им на эти функции? можете привести пример? также как я могу установить разрешения только для чтения, как вы предложили? это будет делать именно так, как я хочу   -  person Mina Ashraf    schedule 17.04.2021
comment
Что ты имеешь в виду? Просто напишите функцию key_proc_read, которая возвращает ошибку, и используйте .read = key_proc_read   -  person Barmar    schedule 17.04.2021
comment
Напишите функцию key_proc_open, которая проверяет открытый режим.   -  person Barmar    schedule 17.04.2021
comment
@Barmar О, теперь я понял. Я думал, что есть некоторые предопределенные функции, которые я мог бы использовать.   -  person Mina Ashraf    schedule 17.04.2021
comment
@Barmar Еще один небольшой вопрос. Как вы думаете, правильно ли я записываю ключ в буфер?   -  person Mina Ashraf    schedule 17.04.2021
comment
Вы копируете в локальную переменную, которая исчезает, как только функция возвращается. Вам нужно сохранить ключ где-нибудь на постоянной основе. Я не очень разбираюсь в драйверах устройств, но я думаю, что с каждым открытым файлом должен быть связан блок данных, вот где вам нужно его сохранить.   -  person Barmar    schedule 17.04.2021


Ответы (1)


Если вы хотите запретить чтение, вы можете просто пропустить явную настройку поля .read для struct file_operation. Если структура определена как static и, следовательно, инициализирована как 0, все поля, которые явно не переопределены, по умолчанию будут иметь значение NULL, а ядро ​​просто ничего не сделает и вернет ошибку (я полагаю, -EINVAL) всякий раз, когда пользовательский код пытается вызвать read на ваш открытый файл.

В качестве альтернативы, если вы хотите вернуть пользовательскую ошибку, вы можете определить фиктивную функцию, которая возвращает только ошибку (например, return -EFAULT;).

Как вы думаете, правильно ли я записываю ключ в буфер?

Это неправильно по нескольким причинам.

Во-первых, ваш copy_from_user() слепо доверяет пользователю count, так что это приводит к переполнению буфера ядра для переменной temp, что довольно плохо. Сначала вам нужно проверить и/или ограничить размер. Вы также не проверяете возвращаемое значение copy_from_user(), которое вам следует (и это не int, а скорее unsigned long).

static ssize_t key_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    char temp[128];
    memset(temp, 0, 128);

    if (count > 128)
        count = 128; // or alternatively return -EINVAL or another error

    if (copy_from_user(temp, buf, count))
        return -EFAULT;

    return count;
}

Теперь код имеет больше смысла, однако переменная temp определена только локально внутри функции, и поэтому будет потеряна после возврата из функции, вы не сможете использовать ее в других функциях работы с файлами. Если вы хотите сделать это, вы можете использовать filp->private_data, поле struct file, предназначенное именно для этой цели.

Вы должны создать и инициализировать буфер на open, а затем освободить его в своей функции release примерно так:

static int hello_proc_open(struct inode *ino, struct file *filp) 
{
    void *buf = kmalloc(128, GFP_KERNEL);
    if (!buf)
        return -ENOMEM;

    filp->private_data = buf;

    // ... whatever else you need to do

    return 0;
}

static int hello_proc_release(struct inode *ino, struct file *filp) 
{
    kfree(filp->private_data);

    // ... whatever else you need to do

    return 0;
}

Затем в вашем write вы можете напрямую использовать буфер после приведения его к правильному типу:

static ssize_t key_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    char *temp = filp->private_data;
    memset(temp, 0, 128);

    if (count > 128)
        count = 128; // or alternatively return -EINVAL or another error

    if (copy_from_user(temp, buf, count))
        return -EFAULT;

    return count;
}

Наконец, я вижу, что вы используете:

 .llseek = seq_lseek,
 .release = single_release,

Не делайте этого. Вам не нужно использовать предопределенные операции. Не смешивайте пользовательские функции, созданные вами, с другими каноническими функциями, такими как, например, используемые для файлов последовательности. Файлы последовательности предполагают выполнение некоторой инициализации и демонтажа, либо вы используете все операции с файлами семейства seq_, либо делаете это вручную самостоятельно ИЛИ не используете функции. В вашем случае подходит последний вариант.

Вы можете просто установить .release на hello_proc_release(), показанное выше, и оставить .llseek не установленным (по умолчанию NULL).

person Marco Bonelli    schedule 16.04.2021