Срив при опит за достъп до 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: буфер = 0000000002172408 alk, не извиквам функцията dev_write. Извиква се от ядрото. Следователно предполагам, че ядрото трябва да гарантира, че за този параметър е разпределена подходяща памет.   -  person ameyazing    schedule 31.08.2017
comment
и каква е стойността на len?   -  person Serve Laurijssen    schedule 31.08.2017
comment
printk(%zu\n, len); дава 5 в лог файла, когато се тества като ехо asdf › /dev/hvacchar   -  person ameyazing    schedule 31.08.2017
comment
Още една подробност, не знам дали ще е полезно. Правя ехото от основната обвивка (#). Когато командата се изпълни, root shell се излиза автоматично и се връщам към нормалната потребителска подкана ($)   -  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