aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/base.c81
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 */
216static 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
212static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf, 253static 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)