这段内容极其值得商榷,事实上,它非常危险。考虑到作者只是试图展示copy_from_user
和copy_to_user
的工作原理,因此我会给予作者信任,但他们确实应该提供更安全的示例。
特别是,因为书中对如何必须格外小心进行了赞美:
系统调用必须仔细验证所有参数,以确保它们是有效和合法的。系统调用在内核空间中运行,如果用户可以毫无限制地将无效输入传递到内核,那么系统的安全性和稳定性就会受到影响。
然后提供了一种让用户完全摧毁内核的方法 :-)
我手头的副本中写着:
让我们考虑一个使用copy_from_user()
和copy_to_user()
的系统调用的示例。这个系统调用叫做silly_copy()
,它毫无价值;它将数据从第一个参数复制到第二个参数中。这不够优化,因为它涉及一次中间和无用的拷贝到内核空间,没有任何好处。但这有助于说明这个调用的点。
SYSCALL_DEFINE3(silly_copy,
unsigned long *, src,
unsigned long *, dst,
unsigned long len)
{
unsigned long buf;
if (copy_from_user(&buf, src, len))
return -EFAULT;
if (copy_to_user(dst, &buf, len))
return -EFAULT;
return len;
}
除了没有检查参数的灾难性故障之外,我非常确定
SYSCALL_DEFINE3
的最后一个参数缺少逗号(虽然这只是一个笔误)。
一个更好的例子,而不需要分配任意内存,可能是这样的:
SYSCALL_DEFINE3(silly_copy,
unsigned long *, src,
unsigned long *, dst,
unsigned long, len)
{
unsigned long buf[64];
unsigned long lenleft = len;
unsigned long chunklen = sizeof(buf);
while (lenleft > 0) {
if (lenleft < chunklen) chunklen = lenleft;
if (copy_from_user(buf, src, chunklen)) return -EFAULT;
if (copy_to_user(dst, buf, chunklen)) return -EFAULT;
src += chunklen; dst += chunklen; lenleft -= chunklen;
}
return len;
}
任何试图实现该系统调用的人都最好避免使用书中的那个示例,虽然我想,至少它会给你一些很好的内核调试经验 :-)
sizeof(unsigned long)
而不是len
。我在我的回答中提供了更安全的版本。 - paxdiablo