提交 762a3af6 编写于 作者: C Christoph Hellwig 提交者: Linus Torvalds

exec: open code copy_string_kernel

Currently copy_string_kernel is just a wrapper around copy_strings that
simplifies the calling conventions and uses set_fs to allow passing a
kernel pointer.  But due to the fact the we only need to handle a single
kernel argument pointer, the logic can be sigificantly simplified while
getting rid of the set_fs.
Signed-off-by: NChristoph Hellwig <hch@lst.de>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Link: http://lkml.kernel.org/r/20200501104105.2621149-3-hch@lst.deSigned-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 986db2d1
......@@ -592,17 +592,42 @@ static int copy_strings(int argc, struct user_arg_ptr argv,
*/
int copy_string_kernel(const char *arg, struct linux_binprm *bprm)
{
int r;
mm_segment_t oldfs = get_fs();
struct user_arg_ptr argv = {
.ptr.native = (const char __user *const __user *)&arg,
};
int len = strnlen(arg, MAX_ARG_STRLEN) + 1 /* terminating NUL */;
unsigned long pos = bprm->p;
if (len == 0)
return -EFAULT;
if (!valid_arg_len(bprm, len))
return -E2BIG;
/* We're going to work our way backwards. */
arg += len;
bprm->p -= len;
if (IS_ENABLED(CONFIG_MMU) && bprm->p < bprm->argmin)
return -E2BIG;
while (len > 0) {
unsigned int bytes_to_copy = min_t(unsigned int, len,
min_not_zero(offset_in_page(pos), PAGE_SIZE));
struct page *page;
char *kaddr;
set_fs(KERNEL_DS);
r = copy_strings(1, argv, bprm);
set_fs(oldfs);
pos -= bytes_to_copy;
arg -= bytes_to_copy;
len -= bytes_to_copy;
return r;
page = get_arg_page(bprm, pos, 1);
if (!page)
return -E2BIG;
kaddr = kmap_atomic(page);
flush_arg_page(bprm, pos & PAGE_MASK, page);
memcpy(kaddr + offset_in_page(pos), arg, bytes_to_copy);
flush_kernel_dcache_page(page);
kunmap_atomic(kaddr);
put_arg_page(page);
}
return 0;
}
EXPORT_SYMBOL(copy_string_kernel);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册