커널 패닉 메시지가 표시되지 않는 이유는 무엇입니까?

커널 패닉 메시지가 표시되지 않는 이유는 무엇입니까?

copy_to_user및 기능을 사용하지 않기 때문에 copy_from _user다음 커널 모듈은 커널에 긴급 메시지를 발행해야 합니다. 그러나 나는 올바른 결과를 얻습니다. 아키텍처는 ubuntu 14.04 LTE의 x86입니다.

$ sudo mknod /dev/mem_char c 61 0
$ sudo chmod 777 /dev/char
$ echo 123asa >/dev/mem_char

dmesg 출력:

[  494.821648] mem_driver: module license 'unspecified' taints kernel.
[  494.821653] Disabling lock debugging due to kernel taint
[  494.821678] mem_driver: module verification failed: signature and/or  required key missing - tainting kernel
[  573.581104] data from user : 123asa
[  573.581104]  tushar!!
[  573.581104] eload
[  573.581104] t
[  573.581104] /bin/grub-script-check
[  573.581104] bkdf2
[  573.581104] e

모듈 코드:

#include<linux/module.h>
#include<linux/fs.h>
#include<linux/init.h>

ssize_t mem_read (struct file *, char __user *,size_t, loff_t *);
ssize_t mem_write (struct file *, const char __user *, size_t, loff_t *);
int mem_open (struct inode *, struct file *);
int mem_release (struct inode *, struct file *);

int major_no=61;    //if major no=0 then dynamic mean kernel alocate it 

struct file_operations fops={
    .open=mem_open,
    .read=mem_read,
    .write=mem_write,
    .release=mem_release,
};

ssize_t mem_read (struct file *fp, char __user *buff,size_t len,  loff_t *off)
{
    printk("buffer :%s \n",buff);
    return 0;
}
ssize_t mem_write (struct file *fp, const char __user *buff, size_t len, loff_t *off)
{
    //  char kbuff;
    //  printk("Function name : %s \n",__func__);
    printk("data from user : %s\n",buff);
    //    kmalloc();      
    return len;
}
int mem_open (struct inode *ip, struct file *fp)
{
    // printk("Function name : %s \n",__func__);
    return 0;
}
int mem_release (struct inode *ip, struct file *fp)
{
    // printk("Function name : %s \n",__func__);
    return 0;
}
static int mem_init(void)
{
    int ret;
    //        printk("mem_init\n");
    ret =register_chrdev(major_no,"mem_driver",&fops);
    if(ret<0)
    {
        //       printk("registetation fails with major no : %d",major_no);
        return ret; 
    }
    // printk("mem_driver register with major no %d\n",major_no);      
    return 0;
}
static void mem_exit(void)
{
    //  printk("exit\n");
    unregister_chrdev(major_no,"mem_driver");   
}
module_init(mem_init);
module_exit(mem_exit);

답변1

테스트에서 모듈은 null 값이 발견될 때까지 액세스 가능한 주소에서 데이터를 인쇄하므로 커널 패닉이 발생할 이유가 없습니다(printk를 데이터 길이로 제한해야 함).

하지만,동일한 테스트를 다시 시도할 수도 있지만 프로그램(echo)이 메모리에서 호출되었기 때문에 패닉이 발생할 것입니다! 이 경우 데이터에 액세스하면 페이지 오류가 발생합니다. 이는 데이터를 메모리로 다시 페이징하는 일반적인 방법이지만 이를 사용하지 않기 때문에 copy_from_user()커널은 페이지 오류가 프로그래밍 오류로 간주되어 패닉이 발생합니다.

이는 많은 아키텍처에서 사용되는 기본 값입니다 copy_from_user(). 이는 이 코드 조각을 잠재적으로 "합법적인" 페이지 오류를 생성하는 것으로 표시하며, 이는 일반적으로 데이터 페이징 요청(사용자 공간에서 발생할 때)으로 처리되어야 합니다. 그렇지 않으면 단지 최적화일 뿐입니다 memcpy().

이 기능은 주소의 유효성에 대한 몇 가지 예비 검사도 수행합니다. 바라보다이 설명.


개념적으로는 echo 123asa다음과 같은 코드로 사용자 공간에 구현됩니다.

char data[1024];
memcpy(data,"123asa\n",7);
write(1,data,7);

복사된 문자열의 data길이는 7자이며 8번째 null 문자로 끝날 이유가 없습니다 \0. 따라서 data[7]초기화되지 않은 임의의 데이터는 나중에 포함됩니다.

모듈에서 이 작업을 수행하면 printk("%s\n",buff)형식은 %snull 문자에 도달할 때까지 buff에서 문자를 인쇄합니다. 이는 상당히 멀 수 있습니다. 길이는 다음에 제공된 길이로 제한해야 합니다.

printk("%*s\n",len,buff);

관련 정보