1/* uaccess.c: userspace access functions
2 *
3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/mm.h>
13#include <linux/module.h>
14#include <asm/uaccess.h>
15
16/*****************************************************************************/
17/*
18 * copy a null terminated string from userspace
19 */
20long strncpy_from_user(char *dst, const char __user *src, long count)
21{
22	unsigned long max;
23	char *p, ch;
24	long err = -EFAULT;
25
26	if (count < 0)
27		BUG();
28
29	p = dst;
30
31#ifndef CONFIG_MMU
32	if ((unsigned long) src < memory_start)
33		goto error;
34#endif
35
36	if ((unsigned long) src >= get_addr_limit())
37		goto error;
38
39	max = get_addr_limit() - (unsigned long) src;
40	if ((unsigned long) count > max) {
41		memset(dst + max, 0, count - max);
42		count = max;
43	}
44
45	err = 0;
46	for (; count > 0; count--, p++, src++) {
47		__get_user_asm(err, ch, src, "ub", "=r");
48		if (err < 0)
49			goto error;
50		if (!ch)
51			break;
52		*p = ch;
53	}
54
55	err = p - dst; /* return length excluding NUL */
56
57 error:
58	if (count > 0)
59		memset(p, 0, count); /* clear remainder of buffer [security] */
60
61	return err;
62
63} /* end strncpy_from_user() */
64
65EXPORT_SYMBOL(strncpy_from_user);
66
67/*****************************************************************************/
68/*
69 * Return the size of a string (including the ending 0)
70 *
71 * Return 0 on exception, a value greater than N if too long
72 */
73long strnlen_user(const char __user *src, long count)
74{
75	const char __user *p;
76	long err = 0;
77	char ch;
78
79	if (count < 0)
80		BUG();
81
82#ifndef CONFIG_MMU
83	if ((unsigned long) src < memory_start)
84		return 0;
85#endif
86
87	if ((unsigned long) src >= get_addr_limit())
88		return 0;
89
90	for (p = src; count > 0; count--, p++) {
91		__get_user_asm(err, ch, p, "ub", "=r");
92		if (err < 0)
93			return 0;
94		if (!ch)
95			break;
96	}
97
98	return p - src + 1; /* return length including NUL */
99
100} /* end strnlen_user() */
101
102EXPORT_SYMBOL(strnlen_user);
103