From 3c323631076d28fe506ded8cad536505395c9a5e Mon Sep 17 00:00:00 2001 From: ad Date: Wed, 4 Feb 2009 21:17:39 +0000 Subject: [PATCH] PR kern/36183 problem with ptrace and multithreaded processes Fix the crashy test case that Thor provided. --- sys/kern/kern_lwp.c | 47 +++++++++++++++++++++++++++++++++++++++--- sys/kern/sys_process.c | 31 ++++++++++++++-------------- sys/sys/lwp.h | 6 ++++-- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/sys/kern/kern_lwp.c b/sys/kern/kern_lwp.c index 2e072cc2a8bf..8dfe95e0c216 100644 --- a/sys/kern/kern_lwp.c +++ b/sys/kern/kern_lwp.c @@ -1,7 +1,7 @@ -/* $NetBSD: kern_lwp.c,v 1.126 2008/10/28 22:11:36 wrstuden Exp $ */ +/* $NetBSD: kern_lwp.c,v 1.127 2009/02/04 21:17:39 ad Exp $ */ /*- - * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -206,7 +206,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.126 2008/10/28 22:11:36 wrstuden Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.127 2009/02/04 21:17:39 ad Exp $"); #include "opt_ddb.h" #include "opt_lockdebug.h" @@ -1388,6 +1388,47 @@ lwp_drainrefs(struct lwp *l) cv_wait(&p->p_lwpcv, p->p_lock); } +/* + * Return true if the specified LWP is 'alive'. Only p->p_lock need + * be held. + */ +bool +lwp_alive(lwp_t *l) +{ + + KASSERT(mutex_owned(l->l_proc->p_lock)); + + switch (l->l_stat) { + case LSSLEEP: + case LSRUN: + case LSONPROC: + case LSSTOP: + case LSSUSPENDED: + return true; + default: + return false; + } +} + +/* + * Return first live LWP in the process. + */ +lwp_t * +lwp_find_first(proc_t *p) +{ + lwp_t *l; + + KASSERT(mutex_owned(p->p_lock)); + + LIST_FOREACH(l, &p->p_lwps, l_sibling) { + if (lwp_alive(l)) { + return l; + } + } + + return NULL; +} + /* * lwp_specific_key_create -- * Create a key for subsystem lwp-specific data. diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index dd7b9bfd92dc..49039cbc353d 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -1,9 +1,12 @@ -/* $NetBSD: sys_process.c,v 1.145 2009/01/22 14:38:35 yamt Exp $ */ +/* $NetBSD: sys_process.c,v 1.146 2009/02/04 21:17:39 ad Exp $ */ /*- - * Copyright (c) 2008 The NetBSD Foundation, Inc. + * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. * All rights reserved. * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -115,7 +118,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.145 2009/01/22 14:38:35 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.146 2009/02/04 21:17:39 ad Exp $"); #include "opt_ptrace.h" #include "opt_ktrace.h" @@ -337,10 +340,16 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) break; } - if (error == 0) + if (error == 0) { error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req), NULL, NULL); + } + if (error == 0) { + lt = lwp_find_first(t); + if (lt == NULL) + error = ESRCH; + } if (error != 0) { mutex_exit(proc_lock); @@ -351,16 +360,6 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) /* Do single-step fixup if needed. */ FIX_SSTEP(t); - - /* - * XXX NJWLWP - * - * The entire ptrace interface needs work to be useful to a - * process with multiple LWPs. For the moment, we'll kluge - * this; memory access will be fine, but register access will - * be weird. - */ - lt = LIST_FIRST(&t->p_lwps); KASSERT(lt != NULL); lwp_addref(lt); @@ -641,7 +640,7 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) lwp_delref(lt); mutex_enter(t->p_lock); if (tmp == 0) - lt = LIST_FIRST(&t->p_lwps); + lt = lwp_find_first(t); else { lt = lwp_find(t, tmp); if (lt == NULL) { @@ -651,7 +650,7 @@ sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) } lt = LIST_NEXT(lt, l_sibling); } - while (lt != NULL && lt->l_stat == LSZOMB) + while (lt != NULL && !lwp_alive(lt)) lt = LIST_NEXT(lt, l_sibling); pl.pl_lwpid = 0; pl.pl_event = 0; diff --git a/sys/sys/lwp.h b/sys/sys/lwp.h index de4b77737ef0..1e8cfbd69171 100644 --- a/sys/sys/lwp.h +++ b/sys/sys/lwp.h @@ -1,7 +1,7 @@ -/* $NetBSD: lwp.h,v 1.116 2009/01/11 02:45:55 christos Exp $ */ +/* $NetBSD: lwp.h,v 1.117 2009/02/04 21:17:39 ad Exp $ */ /*- - * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. + * Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -282,6 +282,8 @@ int lwp_trylock(lwp_t *); void lwp_addref(lwp_t *); void lwp_delref(lwp_t *); void lwp_drainrefs(lwp_t *); +bool lwp_alive(lwp_t *); +lwp_t *lwp_find_first(proc_t *); /* Flags for _lwp_wait1 */ #define LWPWAIT_EXITCONTROL 0x00000001