aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/lib/usercopy.c20
-rw-r--r--fs/namei.c58
-rw-r--r--fs/stat.c5
3 files changed, 35 insertions, 48 deletions
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
index d6ae30bbd7b..2e4e4b02c37 100644
--- a/arch/x86/lib/usercopy.c
+++ b/arch/x86/lib/usercopy.c
@@ -44,13 +44,6 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
44} 44}
45EXPORT_SYMBOL_GPL(copy_from_user_nmi); 45EXPORT_SYMBOL_GPL(copy_from_user_nmi);
46 46
47static inline unsigned long count_bytes(unsigned long mask)
48{
49 mask = (mask - 1) & ~mask;
50 mask >>= 7;
51 return count_masked_bytes(mask);
52}
53
54/* 47/*
55 * Do a strncpy, return length of string without final '\0'. 48 * Do a strncpy, return length of string without final '\0'.
56 * 'count' is the user-supplied count (return 'count' if we 49 * 'count' is the user-supplied count (return 'count' if we
@@ -69,16 +62,19 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long
69 max = count; 62 max = count;
70 63
71 while (max >= sizeof(unsigned long)) { 64 while (max >= sizeof(unsigned long)) {
72 unsigned long c; 65 unsigned long c, mask;
73 66
74 /* Fall back to byte-at-a-time if we get a page fault */ 67 /* Fall back to byte-at-a-time if we get a page fault */
75 if (unlikely(__get_user(c,(unsigned long __user *)(src+res)))) 68 if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
76 break; 69 break;
77 /* This can write a few bytes past the NUL character, but that's ok */ 70 mask = has_zero(c);
71 if (mask) {
72 mask = (mask - 1) & ~mask;
73 mask >>= 7;
74 *(unsigned long *)(dst+res) = c & mask;
75 return res + count_masked_bytes(mask);
76 }
78 *(unsigned long *)(dst+res) = c; 77 *(unsigned long *)(dst+res) = c;
79 c = has_zero(c);
80 if (c)
81 return res + count_bytes(c);
82 res += sizeof(unsigned long); 78 res += sizeof(unsigned long);
83 max -= sizeof(unsigned long); 79 max -= sizeof(unsigned long);
84 } 80 }
diff --git a/fs/namei.c b/fs/namei.c
index c42791914f8..709fb2c17b5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -116,47 +116,37 @@
116 * POSIX.1 2.4: an empty pathname is invalid (ENOENT). 116 * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
117 * PATH_MAX includes the nul terminator --RR. 117 * PATH_MAX includes the nul terminator --RR.
118 */ 118 */
119static int do_getname(const char __user *filename, char *page)
120{
121 int retval;
122 unsigned long len = PATH_MAX;
123
124 if (!segment_eq(get_fs(), KERNEL_DS)) {
125 if ((unsigned long) filename >= TASK_SIZE)
126 return -EFAULT;
127 if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
128 len = TASK_SIZE - (unsigned long) filename;
129 }
130
131 retval = strncpy_from_user(page, filename, len);
132 if (retval > 0) {
133 if (retval < len)
134 return 0;
135 return -ENAMETOOLONG;
136 } else if (!retval)
137 retval = -ENOENT;
138 return retval;
139}
140
141static char *getname_flags(const char __user *filename, int flags, int *empty) 119static char *getname_flags(const char __user *filename, int flags, int *empty)
142{ 120{
143 char *result = __getname(); 121 char *result = __getname(), *err;
144 int retval; 122 int len;
145 123
146 if (!result) 124 if (unlikely(!result))
147 return ERR_PTR(-ENOMEM); 125 return ERR_PTR(-ENOMEM);
148 126
149 retval = do_getname(filename, result); 127 len = strncpy_from_user(result, filename, PATH_MAX);
150 if (retval < 0) { 128 err = ERR_PTR(len);
151 if (retval == -ENOENT && empty) 129 if (unlikely(len < 0))
130 goto error;
131
132 /* The empty path is special. */
133 if (unlikely(!len)) {
134 if (empty)
152 *empty = 1; 135 *empty = 1;
153 if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { 136 err = ERR_PTR(-ENOENT);
154 __putname(result); 137 if (!(flags & LOOKUP_EMPTY))
155 return ERR_PTR(retval); 138 goto error;
156 }
157 } 139 }
158 audit_getname(result); 140
159 return result; 141 err = ERR_PTR(-ENAMETOOLONG);
142 if (likely(len < PATH_MAX)) {
143 audit_getname(result);
144 return result;
145 }
146
147error:
148 __putname(result);
149 return err;
160} 150}
161 151
162char *getname(const char __user * filename) 152char *getname(const char __user * filename)
diff --git a/fs/stat.c b/fs/stat.c
index b30ac60291e..0cef3366a91 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -57,12 +57,13 @@ EXPORT_SYMBOL(vfs_getattr);
57 57
58int vfs_fstat(unsigned int fd, struct kstat *stat) 58int vfs_fstat(unsigned int fd, struct kstat *stat)
59{ 59{
60 struct file *f = fget(fd); 60 int fput_needed;
61 struct file *f = fget_light(fd, &fput_needed);
61 int error = -EBADF; 62 int error = -EBADF;
62 63
63 if (f) { 64 if (f) {
64 error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat); 65 error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
65 fput(f); 66 fput_light(f, fput_needed);
66 } 67 }
67 return error; 68 return error;
68} 69}