由于我没有使用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
没有理由出现内核恐慌,因为在您的测试中,模块从可访问地址打印数据,直到找到空值为止(您应该使用数据的长度来限制 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 个空字符结尾\0
。因此,data[7]
以后将包含随机的未初始化数据。
当您在模块中执行此操作时printk("%s\n",buff)
,格式%s
将从 buff 打印字符,直到到达空字符,这可能很远。您应该将长度限制为中提供的长度
printk("%*s\n",len,buff);