aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-13 17:27:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-16 12:57:52 -0400
commitd26d0cd97c88eb1a5704b42e41ab443406807810 (patch)
tree3e68c8c7d4fc8d42021a7747e79591e2a3028701 /fs/proc/base.c
parent3d712546d8ba9f25cdf080d79f90482aa4231ed4 (diff)
/proc/<pid>/cmdline: add back the setproctitle() special case
This makes the setproctitle() special case very explicit indeed, and handles it with a separate helper function entirely. In the process, it re-instates the original semantics of simply stopping at the first NUL character when the original last NUL character is no longer there. [ The original semantics can still be seen in mm/util.c: get_cmdline() that is limited to a fixed-size buffer ] This makes the logic about when we use the string lengths etc much more obvious, and makes it easier to see what we do and what the two very different cases are. Note that even when we allow walking past the end of the argument array (because the setproctitle() might have overwritten and overflowed the original argv[] strings), we only allow it when it overflows into the environment region if it is immediately adjacent. [ Fixed for missing 'count' checks noted by Alexey Izbyshev ] Link: https://lore.kernel.org/lkml/alpine.LNX.2.21.1904052326230.3249@kich.toxcorp.com/ Fixes: 5ab827189965 ("fs/proc: simplify and clarify get_mm_cmdline() function") Cc: Jakub Jankowski <shasta@toxcorp.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Alexey Izbyshev <izbyshev@ispras.ru> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/base.c')
-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)