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  */
strncpy_from_user(char * dst,const char __user * src,long count)20 long 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 	BUG_ON(count < 0);
27 
28 	p = dst;
29 
30 #ifndef CONFIG_MMU
31 	if ((unsigned long) src < memory_start)
32 		goto error;
33 #endif
34 
35 	if ((unsigned long) src >= get_addr_limit())
36 		goto error;
37 
38 	max = get_addr_limit() - (unsigned long) src;
39 	if ((unsigned long) count > max) {
40 		memset(dst + max, 0, count - max);
41 		count = max;
42 	}
43 
44 	err = 0;
45 	for (; count > 0; count--, p++, src++) {
46 		__get_user_asm(err, ch, src, "ub", "=r");
47 		if (err < 0)
48 			goto error;
49 		if (!ch)
50 			break;
51 		*p = ch;
52 	}
53 
54 	err = p - dst; /* return length excluding NUL */
55 
56  error:
57 	if (count > 0)
58 		memset(p, 0, count); /* clear remainder of buffer [security] */
59 
60 	return err;
61 
62 } /* end strncpy_from_user() */
63 
64 EXPORT_SYMBOL(strncpy_from_user);
65 
66 /*****************************************************************************/
67 /*
68  * Return the size of a string (including the ending 0)
69  *
70  * Return 0 on exception, a value greater than N if too long
71  */
strnlen_user(const char __user * src,long count)72 long strnlen_user(const char __user *src, long count)
73 {
74 	const char __user *p;
75 	long err = 0;
76 	char ch;
77 
78 	BUG_ON(count < 0);
79 
80 #ifndef CONFIG_MMU
81 	if ((unsigned long) src < memory_start)
82 		return 0;
83 #endif
84 
85 	if ((unsigned long) src >= get_addr_limit())
86 		return 0;
87 
88 	for (p = src; count > 0; count--, p++) {
89 		__get_user_asm(err, ch, p, "ub", "=r");
90 		if (err < 0)
91 			return 0;
92 		if (!ch)
93 			break;
94 	}
95 
96 	return p - src + 1; /* return length including NUL */
97 
98 } /* end strnlen_user() */
99 
100 EXPORT_SYMBOL(strnlen_user);
101