aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/base.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index b6572944efc3..aaffc0c30216 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -235,6 +235,10 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
235 if (env_start != arg_end || env_start >= env_end) 235 if (env_start != arg_end || env_start >= env_end)
236 env_start = env_end = arg_end; 236 env_start = env_end = arg_end;
237 237
238 /* .. and limit it to a maximum of one page of slop */
239 if (env_end >= arg_end + PAGE_SIZE)
240 env_end = arg_end + PAGE_SIZE - 1;
241
238 /* We're not going to care if "*ppos" has high bits set */ 242 /* We're not going to care if "*ppos" has high bits set */
239 pos = arg_start + *ppos; 243 pos = arg_start + *ppos;
240 244
@@ -254,10 +258,19 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
254 while (count) { 258 while (count) {
255 int got; 259 int got;
256 size_t size = min_t(size_t, PAGE_SIZE, count); 260 size_t size = min_t(size_t, PAGE_SIZE, count);
261 long offset;
257 262
258 got = access_remote_vm(mm, pos, page, size, FOLL_ANON); 263 /*
259 if (got <= 0) 264 * Are we already starting past the official end?
265 * We always include the last byte that is *supposed*
266 * to be NUL
267 */
268 offset = (pos >= arg_end) ? pos - arg_end + 1 : 0;
269
270 got = access_remote_vm(mm, pos - offset, page, size + offset, FOLL_ANON);
271 if (got <= offset)
260 break; 272 break;
273 got -= offset;
261 274
262 /* Don't walk past a NUL character once you hit arg_end */ 275 /* Don't walk past a NUL character once you hit arg_end */
263 if (pos + got >= arg_end) { 276 if (pos + got >= arg_end) {
@@ -276,12 +289,17 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
276 n = arg_end - pos - 1; 289 n = arg_end - pos - 1;
277 290
278 /* Cut off at first NUL after 'n' */ 291 /* Cut off at first NUL after 'n' */
279 got = n + strnlen(page+n, got-n); 292 got = n + strnlen(page+n, offset+got-n);
280 if (!got) 293 if (got < offset)
281 break; 294 break;
295 got -= offset;
296
297 /* Include the NUL if it existed */
298 if (got < size)
299 got++;
282 } 300 }
283 301
284 got -= copy_to_user(buf, page, got); 302 got -= copy_to_user(buf, page+offset, got);
285 if (unlikely(!got)) { 303 if (unlikely(!got)) {
286 if (!len) 304 if (!len)
287 len = -EFAULT; 305 len = -EFAULT;