[PATCH][RFC] Allow setproctitle to work again

From: Brian Gerst (bgerst@quark.vpplus.com)
Date: Wed Jan 26 2000 - 09:41:55 EST


Here is the patch I promised a few days ago. It Works For Me(tm),
although there are some applications (Netscape in particular) that
mangle their argv array and cause garbage to be output. Summary of the
patch:
- mm->{arg,env}_{start,end} now point to the argv[] and envp[] arrays
instead of the string space on the user stack. I have only tested
binfmt_elf.
- access_process_vm has been modified to perform strncpy instead of
memcpy when requested.
- Some crufty code that touched the environment variable space of insmod
was removed from the floppy driver. I see no reason for this code to be
there, and I didn't really want to fix it to work with the new scheme.

While this patch restores the ability to set the process title by
strcpy(argv[0], title), it also allows for argv[0]=title to work, which
is much safer and less prone to trashing the stack and environment
space.

--

Brian Gerst

diff -urN linux-2.3.41p3/arch/alpha/kernel/ptrace.c linux-proctitle/arch/alpha/kernel/ptrace.c --- linux-2.3.41p3/arch/alpha/kernel/ptrace.c Mon Dec 6 22:23:26 1999 +++ linux-proctitle/arch/alpha/kernel/ptrace.c Wed Jan 26 01:25:51 2000 @@ -132,14 +132,14 @@ static inline int read_int(struct task_struct *task, unsigned long addr, int * data) { - int copied = access_process_vm(task, addr, data, sizeof(int), 0); + int copied = access_process_vm(task, addr, data, sizeof(int), APVM_READ); return (copied == sizeof(int)) ? 0 : -EIO; } static inline int write_int(struct task_struct *task, unsigned long addr, int data) { - int copied = access_process_vm(task, addr, &data, sizeof(int), 1); + int copied = access_process_vm(task, addr, &data, sizeof(int), APVM_WRITE); return (copied == sizeof(int)) ? 0 : -EIO; } @@ -292,7 +292,7 @@ case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp; - int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ); ret = -EIO; if (copied != sizeof(tmp)) goto out; @@ -313,7 +313,7 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: { unsigned long tmp = data; - int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1); + int copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_WRITE); ret = (copied == sizeof(tmp)) ? 0 : -EIO; goto out; } diff -urN linux-2.3.41p3/arch/arm/kernel/ptrace.c linux-proctitle/arch/arm/kernel/ptrace.c --- linux-2.3.41p3/arch/arm/kernel/ptrace.c Wed Oct 20 19:29:08 1999 +++ linux-proctitle/arch/arm/kernel/ptrace.c Wed Jan 26 01:25:51 2000 @@ -64,7 +64,7 @@ { int copied; - copied = access_process_vm(child, addr, res, sizeof(*res), 0); + copied = access_process_vm(child, addr, res, sizeof(*res), APVM_READ); return copied != sizeof(*res) ? -EIO : 0; } @@ -74,7 +74,7 @@ { int copied; - copied = access_process_vm(child, addr, &val, sizeof(val), 1); + copied = access_process_vm(child, addr, &val, sizeof(val), APVM_WRITE); return copied != sizeof(val) ? -EIO : 0; } diff -urN linux-2.3.41p3/arch/i386/kernel/ptrace.c linux-proctitle/arch/i386/kernel/ptrace.c --- linux-2.3.41p3/arch/i386/kernel/ptrace.c Sun Jan 23 12:49:43 2000 +++ linux-proctitle/arch/i386/kernel/ptrace.c Wed Jan 26 01:26:31 2000 @@ -203,7 +203,7 @@ unsigned long tmp; int copied; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ); ret = -EIO; if (copied != sizeof(tmp)) break; @@ -237,7 +237,7 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE) == sizeof(data)) break; ret = -EIO; break; diff -urN linux-2.3.41p3/arch/mips/kernel/irixelf.c linux-proctitle/arch/mips/kernel/irixelf.c --- linux-2.3.41p3/arch/mips/kernel/irixelf.c Sun Jul 25 16:45:25 1999 +++ linux-proctitle/arch/mips/kernel/irixelf.c Wed Jan 26 01:25:51 2000 @@ -206,25 +206,25 @@ } #undef NEW_AUX_ENT + current->mm->env_end = (unsigned long) sp; sp -= envc+1; envp = (elf_caddr_t *) sp; + current->mm->arg_end = current->mm->env_start = (unsigned long) sp; sp -= argc+1; argv = (elf_caddr_t *) sp; + current->mm->arg_start = (unsigned long) sp; __put_user((elf_addr_t)argc,--sp); - current->mm->arg_start = (unsigned long) p; while (argc-->0) { __put_user((elf_caddr_t)(unsigned long)p,argv++); p += strlen_user(p); } __put_user(NULL, argv); - current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { __put_user((elf_caddr_t)(unsigned long)p,envp++); p += strlen_user(p); } __put_user(NULL, envp); - current->mm->env_end = (unsigned long) p; return sp; } diff -urN linux-2.3.41p3/arch/mips/kernel/ptrace.c linux-proctitle/arch/mips/kernel/ptrace.c --- linux-2.3.41p3/arch/mips/kernel/ptrace.c Mon Jul 5 22:44:57 1999 +++ linux-proctitle/arch/mips/kernel/ptrace.c Wed Jan 26 01:25:51 2000 @@ -112,7 +112,7 @@ unsigned long tmp; int copied; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ); res = -EIO; if (copied != sizeof(tmp)) goto out; @@ -184,7 +184,7 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: res = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) + if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE) == sizeof(data)) goto out; res = -EIO; diff -urN linux-2.3.41p3/arch/ppc/kernel/ptrace.c linux-proctitle/arch/ppc/kernel/ptrace.c --- linux-2.3.41p3/arch/ppc/kernel/ptrace.c Tue Aug 31 14:36:43 1999 +++ linux-proctitle/arch/ppc/kernel/ptrace.c Wed Jan 26 01:25:51 2000 @@ -358,7 +358,7 @@ unsigned long tmp; int copied; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ); ret = -EIO; if (copied != sizeof(tmp)) goto out; @@ -399,7 +399,7 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE) == sizeof(data)) goto out; ret = -EIO; goto out; diff -urN linux-2.3.41p3/arch/sh/kernel/ptrace.c linux-proctitle/arch/sh/kernel/ptrace.c --- linux-2.3.41p3/arch/sh/kernel/ptrace.c Wed Sep 1 18:34:01 1999 +++ linux-proctitle/arch/sh/kernel/ptrace.c Wed Jan 26 01:25:51 2000 @@ -208,7 +208,7 @@ unsigned long tmp; int copied; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), APVM_READ); ret = -EIO; if (copied != sizeof(tmp)) goto out; @@ -244,7 +244,7 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + if (access_process_vm(child, addr, &data, sizeof(data), APVM_WRITE) == sizeof(data)) goto out; ret = -EIO; goto out; diff -urN linux-2.3.41p3/arch/sparc/kernel/ptrace.c linux-proctitle/arch/sparc/kernel/ptrace.c --- linux-2.3.41p3/arch/sparc/kernel/ptrace.c Tue Aug 31 14:23:29 1999 +++ linux-proctitle/arch/sparc/kernel/ptrace.c Wed Jan 26 01:25:51 2000 @@ -371,7 +371,7 @@ unsigned long tmp; if (access_process_vm(child, addr, - &tmp, sizeof(tmp), 0) == sizeof(tmp)) + &tmp, sizeof(tmp), APVM_READ) == sizeof(tmp)) pt_os_succ_return(regs, tmp, (long *)data); else pt_error_return(regs, EIO); @@ -389,7 +389,7 @@ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: { if (access_process_vm(child, addr, - &data, sizeof(data), 1) == sizeof(data)) + &data, sizeof(data), APVM_WRITE) == sizeof(data)) pt_succ_return(regs, 0); else pt_error_return(regs, EIO); diff -urN linux-2.3.41p3/arch/sparc64/kernel/binfmt_aout32.c linux-proctitle/arch/sparc64/kernel/binfmt_aout32.c --- linux-2.3.41p3/arch/sparc64/kernel/binfmt_aout32.c Thu Aug 26 15:42:32 1999 +++ linux-proctitle/arch/sparc64/kernel/binfmt_aout32.c Wed Jan 26 01:25:51 2000 @@ -175,12 +175,15 @@ if ((envc+argc+3)&1) --sp; + current->mm->env_end = (unsigned long) sp; sp -= envc+1; envp = (u32 *) sp; + current->mm->arg_end = current->mm->env_start = (unsigned long) sp; sp -= argc+1; argv = (u32 *) sp; + current->mm->arg_start = (unsigned long) sp; + put_user(argc,--sp); - current->mm->arg_start = (unsigned long) p; while (argc-->0) { char c; put_user(((u32)A(p)),argv++); @@ -189,7 +192,6 @@ } while (c); } put_user(NULL,argv); - current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { char c; put_user(((u32)A(p)),envp++); @@ -198,7 +200,6 @@ } while (c); } put_user(NULL,envp); - current->mm->env_end = (unsigned long) p; return sp; } diff -urN linux-2.3.41p3/arch/sparc64/kernel/ptrace.c linux-proctitle/arch/sparc64/kernel/ptrace.c --- linux-2.3.41p3/arch/sparc64/kernel/ptrace.c Tue Aug 3 01:07:16 1999 +++ linux-proctitle/arch/sparc64/kernel/ptrace.c Wed Jan 26 01:25:51 2000 @@ -244,13 +244,13 @@ res = -EIO; if (current->thread.flags & SPARC_FLAG_32BIT) { copied = access_process_vm(child, addr, - &tmp32, sizeof(tmp32), 0); + &tmp32, sizeof(tmp32), APVM_READ); tmp64 = (unsigned long) tmp32; if (copied == sizeof(tmp32)) res = 0; } else { copied = access_process_vm(child, addr, - &tmp64, sizeof(tmp64), 0); + &tmp64, sizeof(tmp64), APVM_READ); if (copied == sizeof(tmp64)) res = 0; } @@ -270,13 +270,13 @@ if (current->thread.flags & SPARC_FLAG_32BIT) { tmp32 = data; copied = access_process_vm(child, addr, - &tmp32, sizeof(tmp32), 1); + &tmp32, sizeof(tmp32), APVM_WRITE); if (copied == sizeof(tmp32)) res = 0; } else { tmp64 = data; copied = access_process_vm(child, addr, - &tmp64, sizeof(tmp64), 1); + &tmp64, sizeof(tmp64), APVM_WRITE); if (copied == sizeof(tmp64)) res = 0; } diff -urN linux-2.3.41p3/drivers/block/floppy.c linux-proctitle/drivers/block/floppy.c --- linux-2.3.41p3/drivers/block/floppy.c Sun Jan 23 12:49:47 2000 +++ linux-proctitle/drivers/block/floppy.c Wed Jan 26 01:33:13 2000 @@ -4330,60 +4330,13 @@ } } -static void __init mod_setup(char *pattern, int (*setup)(char *)) -{ - unsigned long i; - char c; - int j; - int match; - char buffer[100]; - int length = strlen(pattern)+1; - - match=0; - j=1; - - for (i=current->mm->env_start; i< current->mm->env_end; i ++){ - get_user(c, (char *)i); - if (match){ - if (j==99) - c='\0'; - buffer[j] = c; - if (!c || c == ' ' || c == '\t'){ - if (j){ - buffer[j] = '\0'; - setup(buffer); - } - j=0; - } else - j++; - if (!c) - break; - continue; - } - if ((!j && !c) || (j && c == pattern[j-1])) - j++; - else - j=0; - if (j==length){ - match=1; - j=0; - } - } -} - - -#ifdef __cplusplus -extern "C" { -#endif int init_module(void) { printk(KERN_INFO "inserting floppy driver for " UTS_RELEASE "\n"); if(floppy) parse_floppy_cfg_string(floppy); - else - mod_setup("floppy=", floppy_setup); - + return floppy_init(); } @@ -4403,10 +4356,6 @@ MODULE_PARM(FLOPPY_DMA,"i"); MODULE_AUTHOR("Alain L. Knaff"); MODULE_SUPPORTED_DEVICE("fd"); - -#ifdef __cplusplus -} -#endif #else diff -urN linux-2.3.41p3/fs/binfmt_aout.c linux-proctitle/fs/binfmt_aout.c --- linux-2.3.41p3/fs/binfmt_aout.c Wed Nov 24 11:36:09 1999 +++ linux-proctitle/fs/binfmt_aout.c Wed Jan 26 01:25:51 2000 @@ -225,16 +225,18 @@ put_user(bprm->exec, --sp); put_user(0x3e9, --sp); #endif + current->mm->env_end = (unsigned long) sp; sp -= envc+1; envp = (char **) sp; + current->mm->env_start = current->mm->arg_end = (unsigned long) sp; sp -= argc+1; argv = (char **) sp; + current->mm->arg_start = (unsigned long) sp; #if defined(__i386__) || defined(__mc68000__) put_user((unsigned long) envp,--sp); put_user((unsigned long) argv,--sp); #endif put_user(argc,--sp); - current->mm->arg_start = (unsigned long) p; while (argc-->0) { char c; put_user(p,argv++); @@ -243,7 +245,6 @@ } while (c); } put_user(NULL,argv); - current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { char c; put_user(p,envp++); @@ -252,7 +253,6 @@ } while (c); } put_user(NULL,envp); - current->mm->env_end = (unsigned long) p; return sp; } diff -urN linux-2.3.41p3/fs/binfmt_elf.c linux-proctitle/fs/binfmt_elf.c --- linux-2.3.41p3/fs/binfmt_elf.c Wed Jan 12 18:53:02 2000 +++ linux-proctitle/fs/binfmt_elf.c Wed Jan 26 01:25:51 2000 @@ -173,29 +173,29 @@ } #undef NEW_AUX_ENT + current->mm->env_end = (unsigned long) sp; sp -= envc+1; envp = (elf_caddr_t *) sp; + current->mm->env_start = current->mm->arg_end = (unsigned long) sp; sp -= argc+1; argv = (elf_caddr_t *) sp; + current->mm->arg_start = (unsigned long) sp; if (!ibcs) { __put_user((elf_addr_t)(unsigned long) envp,--sp); __put_user((elf_addr_t)(unsigned long) argv,--sp); } __put_user((elf_addr_t)argc,--sp); - current->mm->arg_start = (unsigned long) p; while (argc-->0) { __put_user((elf_caddr_t)(unsigned long)p,argv++); p += strlen_user(p); } __put_user(NULL, argv); - current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { __put_user((elf_caddr_t)(unsigned long)p,envp++); p += strlen_user(p); } __put_user(NULL, envp); - current->mm->env_end = (unsigned long) p; return sp; } diff -urN linux-2.3.41p3/fs/proc/base.c linux-proctitle/fs/proc/base.c --- linux-2.3.41p3/fs/proc/base.c Wed Jan 12 18:52:44 2000 +++ linux-proctitle/fs/proc/base.c Wed Jan 26 02:01:58 2000 @@ -100,15 +100,40 @@ /* task is locked and can't drop mm, so we are safe */ +static int get_array(struct task_struct *task, unsigned long start, + unsigned long end, char *buffer) +{ + unsigned long str; + int res; + int buflen = 0; + + while (start < end) { + res = access_process_vm(task, start, &str, sizeof(str), APVM_READ); + if (res != sizeof(str) || !str) + break; + + res = access_process_vm(task, str, buffer, PAGE_SIZE - buflen, + APVM_READ | APVM_STRNCPY); + if (!res || buffer[res - 1]) + break; + + buffer += res; + buflen += res; + + start += sizeof(str); + } + + return buflen; +} + +/* task is locked and can't drop mm, so we are safe */ + static int proc_pid_environ(struct task_struct *task, char * buffer) { struct mm_struct *mm = task->mm; int res = 0; if (mm) { - int len = mm->env_end - mm->env_start; - if (len > PAGE_SIZE) - len = PAGE_SIZE; - res = access_process_vm(task, mm->env_start, buffer, len, 0); + res = get_array(task, mm->env_start, mm->env_end, buffer); } return res; } @@ -120,10 +145,7 @@ struct mm_struct *mm = task->mm; int res = 0; if (mm) { - int len = mm->arg_end - mm->arg_start; - if (len > PAGE_SIZE) - len = PAGE_SIZE; - res = access_process_vm(task, mm->arg_start, buffer, len, 0); + res = get_array(task, mm->arg_start, mm->arg_end, buffer); } return res; } @@ -288,7 +310,7 @@ int this_len, retval; this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; - retval = access_process_vm(task, src, page, this_len, 0); + retval = access_process_vm(task, src, page, this_len, APVM_READ); if (!retval) { if (!copied) copied = -EIO; @@ -331,7 +353,7 @@ copied = -EFAULT; break; } - retval = access_process_vm(task, dst, page, this_len, 1); + retval = access_process_vm(task, dst, page, this_len, APVM_WRITE); if (!retval) { if (!copied) copied = -EIO; diff -urN linux-2.3.41p3/include/linux/mm.h linux-proctitle/include/linux/mm.h --- linux-2.3.41p3/include/linux/mm.h Sun Jan 23 12:50:00 2000 +++ linux-proctitle/include/linux/mm.h Wed Jan 26 01:52:31 2000 @@ -390,6 +390,11 @@ extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len); +/* Flags for access_process_vm() */ +#define APVM_READ 0 +#define APVM_WRITE 1 +#define APVM_STRNCPY 2 + extern int pgt_cache_water[2]; extern int check_pgt_cache(void); diff -urN linux-2.3.41p3/kernel/ptrace.c linux-proctitle/kernel/ptrace.c --- linux-2.3.41p3/kernel/ptrace.c Mon Nov 22 23:48:55 1999 +++ linux-proctitle/kernel/ptrace.c Wed Jan 26 01:56:54 2000 @@ -18,13 +18,14 @@ /* * Access another process' address space, one page at a time. */ -static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write) +static int access_one_page(struct task_struct * tsk, struct vm_area_struct * vma, + unsigned long addr, void *buf, int len, int flags) { pgd_t * pgdir; pmd_t * pgmiddle; pte_t * pgtable; unsigned long mapnr; - unsigned long maddr; + char * maddr; struct page *page; repeat: @@ -42,29 +43,32 @@ if (!pte_present(*pgtable)) goto fault_in_page; mapnr = pte_pagenr(*pgtable); - if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable))) + if ((flags & APVM_WRITE) && (!pte_write(*pgtable) || !pte_dirty(*pgtable))) goto fault_in_page; if (mapnr >= max_mapnr) return 0; page = mem_map + mapnr; flush_cache_page(vma, addr); - if (write) { - maddr = kmap(page); - memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len); - flush_page_to_ram(page); - kunmap(page); + maddr = (char *) kmap(page) + (addr & ~PAGE_MASK); + if (flags & APVM_WRITE) { + if (flags & APVM_STRNCPY) + len = strnlen(buf, len) + 1; + memcpy(maddr, buf, len); } else { - maddr = kmap(page); - memcpy(buf, (char *)maddr + (addr & ~PAGE_MASK), len); - flush_page_to_ram(page); - kunmap(page); + if (flags & APVM_STRNCPY) + len = strnlen(maddr, len) + 1; + memcpy(buf, maddr, len); } + + flush_page_to_ram(page); + kunmap(page); + return len; fault_in_page: /* -1: out of memory. 0 - unmapped page */ - if (handle_mm_fault(tsk, vma, addr, write) > 0) + if (handle_mm_fault(tsk, vma, addr, (flags & APVM_WRITE)) > 0) goto repeat; return 0; @@ -77,7 +81,7 @@ return 0; } -int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) +int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int flags) { int copied; struct vm_area_struct * vma; @@ -96,7 +100,7 @@ if (this_len > len) this_len = len; - retval = access_one_page(tsk, vma, addr, buf, this_len, write); + retval = access_one_page(tsk, vma, addr, buf, this_len, flags); copied += retval; if (retval != this_len) break; @@ -108,6 +112,10 @@ addr += retval; buf += retval; + /* Catch case where null is last byte on page */ + if ((flags & APVM_STRNCPY) && !*((char*)buf-1)) + break; + if (addr < vma->vm_end) continue; if (!vma->vm_next) @@ -130,7 +138,7 @@ int this_len, retval; this_len = (len > sizeof(buf)) ? sizeof(buf) : len; - retval = access_process_vm(tsk, src, buf, this_len, 0); + retval = access_process_vm(tsk, src, buf, this_len, APVM_READ); if (!retval) { if (copied) break; @@ -157,7 +165,7 @@ this_len = (len > sizeof(buf)) ? sizeof(buf) : len; if (copy_from_user(buf, src, this_len)) return -EFAULT; - retval = access_process_vm(tsk, dst, buf, this_len, 1); + retval = access_process_vm(tsk, dst, buf, this_len, APVM_WRITE); if (!retval) { if (copied) break;

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Jan 31 2000 - 21:00:16 EST