diff options
| -rw-r--r-- | fs/proc/base.c | 28 |
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; |
