diff options
-rw-r--r-- | arch/x86/lib/usercopy.c | 20 | ||||
-rw-r--r-- | fs/namei.c | 58 | ||||
-rw-r--r-- | fs/stat.c | 5 |
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 | } |
45 | EXPORT_SYMBOL_GPL(copy_from_user_nmi); | 45 | EXPORT_SYMBOL_GPL(copy_from_user_nmi); |
46 | 46 | ||
47 | static 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 | */ |
119 | static 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 | |||
141 | static char *getname_flags(const char __user *filename, int flags, int *empty) | 119 | static 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 | |||
147 | error: | ||
148 | __putname(result); | ||
149 | return err; | ||
160 | } | 150 | } |
161 | 151 | ||
162 | char *getname(const char __user * filename) | 152 | char *getname(const char __user * filename) |
@@ -57,12 +57,13 @@ EXPORT_SYMBOL(vfs_getattr); | |||
57 | 57 | ||
58 | int vfs_fstat(unsigned int fd, struct kstat *stat) | 58 | int 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 | } |