Сбой при попытке доступа к буферу const char*

Я пытаюсь написать модуль ядра Linux. В этом я зарегистрировал функции открытия, чтения, записи, выпуска, как показано ниже:

static struct file_operations fops =
{
   .open = dev_open,
   .read = dev_read,
   .write = dev_write,
   .release = dev_release,
};

Драйвер создает символьное устройство как /dev/hvacchar. Эта часть работает нормально.

Для проверки пишу драйверу так:

cat > /dev/hvacchar
asdf1234

Вызывающий процесс немедленно уничтожается.

Я удалил все из моего dev_write и оставил только один printk(). Вот код:

static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
   printk(KERN_INFO "HVACCHAR: Entered dev_write()\n");
   printk(KERN_INFO "HVACChar: b4 sprintf(): buffer=%c\n", buffer[0]);
   return len;
}

tail -f /var/log/kern.log показывает первую инструкцию printk, но не вторую. Я предполагаю, что он падает, когда пытается получить доступ к переменной буфера. Насколько я понимаю, он предоставляется системой и должен иметь правильное распределение памяти. Что я делаю неправильно?

Вот весь дамп из kern.log

Aug 31 15:17:28 app-ThinkCentre-M900 kernel: [873016.888579] HVACChar: Device has been opened 1 time(s)
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.627170] HVACCHAR: Entered dev_write()
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.627203] BUG: unable to handle kernel paging request at 00000000015c9004
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.630465] IP: [<ffffffffc08f7070>] dev_write+0x20/0x40 [hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.633714] PGD 51364067 PUD 374d3067 PMD 374f6067 PTE 80000000ac7de867
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.637075] Oops: 0001 [#36] SMP
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.640346] Modules linked in: hvacchar(OE) binfmt_misc btrfs xor raid6_pq ufs qnx4 hfsplus hfs minix ntfs msdos jfs xfs libcrc32c uas usb_storage ebbchar(OE) rfcomm bnep intel_rapl x86_pkg_temp_thermal input_leds intel_powerclamp coretemp snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec i915_bpo snd_hda_core snd_hwdep snd_pcm kvm_intel snd_seq_midi kvm snd_seq_midi_event snd_rawmidi snd_seq hci_uart irqbypass btbcm btqca snd_seq_device btintel snd_timer crct10dif_pclmul intel_ips drm_kms_helper bluetooth drm crc32_pclmul ghash_clmulni_intel aesni_intel snd aes_x86_64 lrw gf128mul mei_me glue_helper ablk_helper serio_raw cryptd i2c_algo_bit fb_sys_fops syscopyarea sysfillrect sysimgblt soundcore mei video acpi_pad 8250_fintek wmi intel_lpss_acpi intel_lpss pinctrl_sunrisepoint pinctrl_intel acpi_als kfifo_buf i2c_hid industrialio mac_hid parport_pc ppdev lp parport hid_generic usbhid hid e1000e psmouse ptp ahci pps_core libahci fjes [last unloaded: hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.660535] CPU: 1 PID: 31522 Comm: cat Tainted: G      D    OE   4.4.0-92-generic #115~14.04.1-Ubuntu
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.662854] Hardware name: LENOVO 10FLS13501/30D0, BIOS FWKT5AA   09/23/2016
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.664735] task: ffff88010759e900 ti: ffff8800374e0000 task.ti: ffff8800374e0000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.666473] RIP: 0010:[<ffffffffc08f7070>]  [<ffffffffc08f7070>] dev_write+0x20/0x40 [hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.668233] RSP: 0018:ffff8800374e3ea8  EFLAGS: 00010282
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.669703] RAX: 000000000000001d RBX: 00000000015c9000 RCX: 0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.671127] RDX: 0000000000000001 RSI: ffff88023dc8dd98 RDI: ffff88023dc8dd98
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.672547] RBP: ffff8800374e3eb8 R08: 000000000000000a R09: 0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.673890] R10: 0000000000000000 R11: 00000000000009bc R12: 0000000000000009
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.675080] R13: 0000000000000009 R14: ffff8800374e3f20 R15: 0000000000000009
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.676237] FS:  00007f92c016d740(0000) GS:ffff88023dc80000(0000) knlGS:0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.677373] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.678484] CR2: 00000000015c9004 CR3: 000000008fbd5000 CR4: 00000000003406e0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.679420] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.680331] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.681209] Stack:
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.682065]  ffff880139bf6300 00000000015c9000 ffff8800374e3ec8 ffffffff812010c8
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.682936]  ffff8800374e3f08 ffffffff812016e2 ffffffff8120161c ffff880139bf6300
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.683789]  ffff880139bf6300 00000000015c9000 0000000000000009 0000000000000009
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.684640] Call Trace:
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.685436]  [<ffffffff812010c8>] __vfs_write+0x18/0x40
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.686232]  [<ffffffff812016e2>] vfs_write+0xa2/0x1a0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.687028]  [<ffffffff8120161c>] ? vfs_read+0x10c/0x130
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.687818]  [<ffffffff81202406>] SyS_write+0x46/0xa0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.688604]  [<ffffffff8180cd36>] entry_SYSCALL_64_fastpath+0x16/0x75
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.689391] Code: c0 31 c0 5d c3 66 0f 1f 44 00 00 0f 1f 44 00 00 55 48 c7 c7 80 80 8f c0 31 c0 48 89 e5 41 54 49 89 d4 53 48 89 f3 e8 ff cb 88 c0 <0f> be 53 04 0f be 33 48 c7 c7 a8 80 8f c0 31 c0 e8 ea cb 88 c0
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.691080] RIP  [<ffffffffc08f7070>] dev_write+0x20/0x40 [hvacchar]
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.691905]  RSP <ffff8800374e3ea8>
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.692728] CR2: 00000000015c9004
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.693552] ---[ end trace eee0478c7200f93f ]---
Aug 31 15:17:31 app-ThinkCentre-M900 kernel: [873020.693962] HVACChar: Device successfully closed

Я новичок в Linux и драйверах устройств. Пожалуйста, будьте нежны :)


person ameyazing    schedule 31.08.2017    source источник
comment
сначала проверьте, на что указывает буфер, с помощью printk(%p\n, (void*)buffer)   -  person Serve Laurijssen    schedule 31.08.2017
comment
Как определяется и инициализируется то, что вы передаете как buffer?   -  person alk    schedule 31.08.2017
comment
@Brouwrijssen Вот вывод предложенного вами printk HVACCHAR: buffer = 0000000002172408 Алк, я не вызываю функцию dev_write. Он вызывается ядром. Следовательно, я предполагаю, что ядро ​​должно обеспечить выделение соответствующей памяти для этого параметра.   -  person ameyazing    schedule 31.08.2017
comment
и каково значение len?   -  person Serve Laurijssen    schedule 31.08.2017
comment
printk(%zu\n, длина); дает 5 в лог-файле при тестировании как echo asdf › /dev/hvacchar   -  person ameyazing    schedule 31.08.2017
comment
Еще одна деталь, я не знаю, будет ли это полезно. Я делаю эхо из корневой оболочки (#). Когда команда выполняется, корневая оболочка автоматически закрывается, и я возвращаюсь к обычному пользовательскому приглашению ($)   -  person ameyazing    schedule 31.08.2017


Ответы (1)


Что ж, причина проста. Ваш код выполняется в контексте ядра, в то время как буфер с данными поступает из пользовательского пространства. Одной из главных целей любого ядра является обеспечение защиты памяти, поэтому для ядра и пользовательского пространства используются разные области памяти. Если вам нужно получить некоторые данные из пользовательского пространства, скопируйте их в память ядра с помощью copy_from_user(). Если вы не будете следовать схеме и просто попытаетесь получить доступ к данным напрямую, это приведет к нарушению доступа к памяти, и ядро ​​​​сообщит об этом (как в вашем выводе журнала): «невозможно обработать запрос на подкачку ядра».

Итак, правильное решение (на основе вашего кода) будет выглядеть примерно так:

#include <linux/slab.h>

static ssize_t dev_write(struct file *filep, const char __user *buffer, size_t len, loff_t *offset) {
    char *buf_internal;

    buf_internal = kmalloc(len, GFP_KERNEL);
    if (buf_internal == NULL)
        return -ENOMEM;

    if (copy_from_user(buf_internal, buffer, len)) {
        kfree(buf_internal);
        return -EFAULT;
    }

    buf_internal[len - 1] = '\0';

    printk(KERN_INFO "HVACCHAR: Entered dev_write()\n");
    printk(KERN_INFO "HVACChar: b4 sprintf(): buffer=%c\n", buf_internal[0]);

    kfree(buf_internal);

    return len;
}

Пожалуйста, найдите квалификатор __user, добавленный в прототип функции, чтобы выделить природу буфера. Я не тестировал код, но надеюсь, что идея понятна :)

person Community    schedule 01.09.2017
comment
Спасибо. Работал как шарм. Могу ли я предложить вам добавить одно небольшое редактирование, #include‹linux/slab.h›, чтобы помочь новичкам, которые попадут в эту тему в будущем. - person ameyazing; 05.09.2017
comment
Спасибо, я только что добавил это. Я также добавил в пример kfree(), так как очевидно, что нам нужно освободить буфер в тот момент, когда он нам больше не нужен. - person ; 05.09.2017