Messages in this thread | | | Date | Fri, 9 May 2003 01:59:46 +0200 (CEST) | From | Bernhard Kaindl <> | Subject | Re: [PATCH][2.4] cleanup ptrace secfix and fix most side effects |
| |
On 8 May 2003, Alan Cox wrote: > On Iau, 2003-05-08 at 23:05, Bernhard Kaindl wrote: > > - mb(); > > - if (!is_dumpable(child)) > > - return -EPERM; > > > > if (!(child->ptrace & PT_PTRACED)) > > return -ESRCH; > > > > Using is_dumpable() here is not neccesary because the checks done here are: > > > > > if (!(child->ptrace & PT_PTRACED)) > > > return -ESRCH; > > Except that current->mm->dumpable is not per task but per mm so you > might ptrace one thread and have another go setuid.
You might try, but as far as I know:
a) setuid requires execve() which decouples from the other thread and also gives the new thread a newly allocated task->mm.
b) If the thread which calls execve() is being traced, execve ignores setuid.
c) If the thread which calls execve() is being not traced, a tracer has to attach first, otherwise
> > > if (!(child->ptrace & PT_PTRACED)) > > > return -ESRCH;
catches the agaist-the-API ptrace call and the only way to set
child->ptrace & PT_PTRACED
is to call ptrace_attach() which checks for matching uids/gids beween tracer and the setuid task and requiring that the tracer may not miss a capability which the setuid task has granted and effectively denies ptrace access otherwise:
if(((current->uid != task->euid) || (current->uid != task->suid) || (current->uid != task->uid) || (current->gid != task->egid) || (current->gid != task->sgid) || (!cap_issubset(task->cap_permitted, current->cap_permitted)) || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto bad;
d) Even if the setuid program changes uids and capabilies back so that you would pass the check above, you will fail in the next line here:
if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE)) goto bad;
And you can't change task->mm->dumpable back to 1 because the new task has got a new mm allocated to which you have no access.
So, unless you have CAP_SYS_PTRACE, you will fail to trace the setuid program(CAP_SYS_PTRACE is documented to allow to trace setuid) unless it does prctl(PR_SET_DUMPABLE, 1) and after giving all capabilies gained away and setting uid and gids back. At this point you could attach to it again, but by calling prctl(PR_SET_DUMPABLE, 1), the setudi program decares that it does not have any sensitive data anymore because you could also send him a signal to cause him core dumping and read the core with emacs then.
Do you see any chance to gain anything this way or do you mean a scenario which I did not describe here?
Thanks, Bernd
PS:
Just in case if people are interested where execve() gets a new mm for the new program:
execve() calls do_execve() which calls the binfmt's file loader(e.g. load_elf_binary) which calls flush_old_exec() which calls exec_mmap() which releases the old mm and allocates a new task->mm for the new process:
fs/exec.c, exec_mmap():
old_mm = current->mm; if (old_mm) { rlimit_rss = old_mm->rlimit_rss; if (atomic_read(&old_mm->mm_users) == 1) { mm_release(); exit_aio(old_mm); exit_mmap(old_mm); return 0; } }
mm = mm_alloc(); [...] current->mm = mm;
EOF
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |