diff options
| -rw-r--r-- | fs/proc/base.c | 81 |
1 files changed, 77 insertions, 4 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 8040f9d1cf07..8fbab527bd24 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -209,12 +209,53 @@ static int proc_root_link(struct dentry *dentry, struct path *path) | |||
| 209 | return result; | 209 | return result; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | /* | ||
| 213 | * If the user used setproctitle(), we just get the string from | ||
| 214 | * user space at arg_start, and limit it to a maximum of one page. | ||
| 215 | */ | ||
| 216 | static ssize_t get_mm_proctitle(struct mm_struct *mm, char __user *buf, | ||
| 217 | size_t count, unsigned long pos, | ||
| 218 | unsigned long arg_start) | ||
| 219 | { | ||
| 220 | char *page; | ||
| 221 | int ret, got; | ||
| 222 | |||
| 223 | if (pos >= PAGE_SIZE) | ||
| 224 | return 0; | ||
| 225 | |||
| 226 | page = (char *)__get_free_page(GFP_KERNEL); | ||
| 227 | if (!page) | ||
| 228 | return -ENOMEM; | ||
| 229 | |||
| 230 | ret = 0; | ||
| 231 | got = access_remote_vm(mm, arg_start, page, PAGE_SIZE, FOLL_ANON); | ||
| 232 | if (got > 0) { | ||
| 233 | int len = strnlen(page, got); | ||
| 234 | |||
| 235 | /* Include the NUL character if it was found */ | ||
| 236 | if (len < got) | ||
| 237 | len++; | ||
| 238 | |||
| 239 | if (len > pos) { | ||
| 240 | len -= pos; | ||
| 241 | if (len > count) | ||
| 242 | len = count; | ||
| 243 | len -= copy_to_user(buf, page+pos, len); | ||
| 244 | if (!len) | ||
| 245 | len = -EFAULT; | ||
| 246 | ret = len; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | free_page((unsigned long)page); | ||
| 250 | return ret; | ||
| 251 | } | ||
| 252 | |||
| 212 | static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, | 253 | static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, |
| 213 | size_t count, loff_t *ppos) | 254 | size_t count, loff_t *ppos) |
| 214 | { | 255 | { |
| 215 | unsigned long arg_start, arg_end; | 256 | unsigned long arg_start, arg_end, env_start, env_end; |
| 216 | unsigned long pos, len; | 257 | unsigned long pos, len; |
| 217 | char *page; | 258 | char *page, c; |
| 218 | 259 | ||
| 219 | /* Check if process spawned far enough to have cmdline. */ | 260 | /* Check if process spawned far enough to have cmdline. */ |
| 220 | if (!mm->env_end) | 261 | if (!mm->env_end) |
| @@ -223,14 +264,46 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, | |||
| 223 | spin_lock(&mm->arg_lock); | 264 | spin_lock(&mm->arg_lock); |
| 224 | arg_start = mm->arg_start; | 265 | arg_start = mm->arg_start; |
| 225 | arg_end = mm->arg_end; | 266 | arg_end = mm->arg_end; |
| 267 | env_start = mm->env_start; | ||
| 268 | env_end = mm->env_end; | ||
| 226 | spin_unlock(&mm->arg_lock); | 269 | spin_unlock(&mm->arg_lock); |
| 227 | 270 | ||
| 228 | if (arg_start >= arg_end) | 271 | if (arg_start >= arg_end) |
| 229 | return 0; | 272 | return 0; |
| 230 | 273 | ||
| 274 | /* | ||
| 275 | * We allow setproctitle() to overwrite the argument | ||
| 276 | * strings, and overflow past the original end. But | ||
| 277 | * only when it overflows into the environment area. | ||
| 278 | */ | ||
| 279 | if (env_start != arg_end || env_end < env_start) | ||
| 280 | env_start = env_end = arg_end; | ||
| 281 | len = env_end - arg_start; | ||
| 282 | |||
| 231 | /* We're not going to care if "*ppos" has high bits set */ | 283 | /* We're not going to care if "*ppos" has high bits set */ |
| 232 | /* .. but we do check the result is in the proper range */ | 284 | pos = *ppos; |
| 233 | pos = arg_start + *ppos; | 285 | if (pos >= len) |
| 286 | return 0; | ||
| 287 | if (count > len - pos) | ||
| 288 | count = len - pos; | ||
| 289 | if (!count) | ||
| 290 | return 0; | ||
| 291 | |||
| 292 | /* | ||
| 293 | * Magical special case: if the argv[] end byte is not | ||
| 294 | * zero, the user has overwritten it with setproctitle(3). | ||
| 295 | * | ||
| 296 | * Possible future enhancement: do this only once when | ||
| 297 | * pos is 0, and set a flag in the 'struct file'. | ||
| 298 | */ | ||
| 299 | if (access_remote_vm(mm, arg_end-1, &c, 1, FOLL_ANON) == 1 && c) | ||
| 300 | return get_mm_proctitle(mm, buf, count, pos, arg_start); | ||
| 301 | |||
| 302 | /* | ||
| 303 | * For the non-setproctitle() case we limit things strictly | ||
| 304 | * to the [arg_start, arg_end[ range. | ||
| 305 | */ | ||
| 306 | pos += arg_start; | ||
| 234 | if (pos < arg_start || pos >= arg_end) | 307 | if (pos < arg_start || pos >= arg_end) |
| 235 | return 0; | 308 | return 0; |
| 236 | if (count > arg_end - pos) | 309 | if (count > arg_end - pos) |
