“Linux内核编程”中的源代码示例

正在阅读Robert Love的书,第5章关于系统调用,并发现这个简单的例子有点可疑:

asmlinkage long sys_silly_copy(unsigned long *src, unsigned long *dst, unsigned long len) { unsigned long buf; if (copy_from_user(&buf, src, len)) return -EFAULT; ... } 

我们看到’buf’是’unsigned long’类型的对象,并在内核堆栈上定义,即它的初始值很可能是垃圾。 无论如何,在buf所在的堆栈中复制’len’字节是有效的,即它可以覆盖有用的东西吗? 也许这只适用于这个特定的例子?

这是非常值得怀疑的。 事实上,这是非常危险的。 我会在这里给作者带来疑问,因为他们只是试图展示copy_from_usercopy_to_user如何工作的,但他们确实应该提供一个不那么危险的例子。

特别是因为这本书对你如何必须格外小心抒情:

系统调用必须仔细validation其所有参数,以确保它们有效且合法。系统调用在内核空间中运行,如果用户可以无限制地将无效输入传递到内核,系统的安全性和稳定性会受到影响。

然后为用户提供了一种完全消灭内核的方法:-)


我的副本中的文字说明:

让我们考虑一个使用copy_from_user()copy_to_user()的示例系统调用。这个系统调用, silly_copy()完全没用; 它将数据从其第一个参数复制到第二个参数中。这是次优的,因为它涉及到内核空间的中间和无关副本,无法获得。 但它有助于说明这一点。

 /* * silly_copy - pointless syscall that copies the len bytes from * 'src' to 'dst' using the kernel as an intermediary in the copy. * Intended as an example of copying to and from the kernel. */ SYSCALL_DEFINE3(silly_copy, unsigned long *, src, unsigned long *, dst, unsigned long len) { unsigned long buf; /* copy src, which is in the user's address space, into buf */ if (copy_from_user(&buf, src, len)) return -EFAULT; /* copy buf into dst, which is in the user's address space */ if (copy_to_user(dst, &buf, len)) return -EFAULT; /* return amount of data copied */ return len; } 

除了没有检查参数的灾难性故障之外,我很确定SYSCALL_DEFINE3的最后一个参数缺少一个逗号(虽然这只是一个错字)。

一个更好的例子,不必分配任意内存,将是:

 SYSCALL_DEFINE3(silly_copy, unsigned long *, src, unsigned long *, dst, unsigned long, len) { unsigned long buf[64]; /* Buffer for chunks */ unsigned long lenleft = len; /* Remaining size */ unsigned long chunklen = sizeof(buf); /* Initial chunk length */ /* Loop handling chunk sizes */ while (lenleft > 0) { /* Change chunk length on last chunk */ if (lenleft < chunklen) chunklen = lenleft; /* copy src(user) to buf(kernel) then dst(user) */ if (copy_from_user(buf, src, chunklen)) return -EFAULT; if (copy_to_user(dst, buf, chunklen)) return -EFAULT; /* Adjust pointers and remaining size */ src += chunklen; dst += chunklen; lenleft -= chunklen; } /* return amount of data copied */ return len; } 

任何试图实现该系统调用的人都会建议远离书中的特定样本,尽管我认为,至少它会给你一些很好的内核调试经验:-)

 int init_module(void) { mempool_t *mempool; struct kmem_cache *kmem_cache; void *p0 , *p1; kmem_cache = kmem_cache_create("Ashrama" ,100 , 0 ,SLAB_PANIC ,NULL); mempool = mempool_create(4 , mempool_alloc_slab , mempool_free_slab , kmem_cache); p0 = mempool_alloc(mempool, SLAB_PANIC); p1 = mempool_alloc(mempool , SLAB_PANIC); strcpy(p0 , "Ranjan.BM"); strcpy(p1 , "Mithun.V"); mempool_free( p0 , mempool); printk(KERN_ALERT"%s",p0); printk(KERN_ALERT"%s",p1); }