> Date: Thu, 4 Mar 2021 11:19:23 +0100
> From: Martin Pieuchot <[email protected]>
>
> On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > From: Patrick Wildt <[email protected]>
> > >
> > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > From: Martin Pieuchot <[email protected]>
> > > > >
> > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > > > > change the value of `ps_single' while one of its siblings might be
> > > > > dereferencing it.
> > > > >
> > > > > To prevent inconsistencies in the code executed by sibling thread, the
> > > > > diff below makes sure `ps_single' is dereferenced only once in various
> > > > > parts of the kernel.
> > > > >
> > > > > ok?
> > > >
> > > > I think that means that ps_single has to be declared "volatile".
> > >
> > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> >
> > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> > are needed to comply with the alpha memory model. At least in some
> > cases...
>
> Updated diff using READ_ONCE(), ok?
If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
where you modify ps_single isn't it?
That is one of the reasons I dislike these macros...
> Index: kern/kern_exit.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_exit.c,v
> retrieving revision 1.196
> diff -u -p -r1.196 kern_exit.c
> --- kern/kern_exit.c 15 Feb 2021 09:35:59 -0000 1.196
> +++ kern/kern_exit.c 4 Mar 2021 10:15:22 -0000
> @@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
> */
> if (qr->ps_flags & PS_TRACED &&
> !(qr->ps_flags & PS_EXITING)) {
> + struct proc *st;
> +
> process_untrace(qr);
>
> /*
> @@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
> * direct the signal to the active
> * thread to avoid deadlock.
> */
> - if (qr->ps_single)
> - ptsignal(qr->ps_single, SIGKILL,
> - STHREAD);
> + st = READ_ONCE(qr->ps_single);
> + if (st != NULL)
> + ptsignal(st, SIGKILL, STHREAD);
> else
> prsignal(qr, SIGKILL);
> } else {
> @@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
> {
> int nfound;
> struct process *pr;
> - struct proc *p;
> + struct proc *p, *st;
> int error;
>
> if (pid == 0)
> @@ -541,10 +543,11 @@ loop:
> proc_finish_wait(q, p);
> return (0);
> }
> +
> + st = READ_ONCE(pr->ps_single);
> if (pr->ps_flags & PS_TRACED &&
> - (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
> - pr->ps_single->p_stat == SSTOP &&
> - (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
> + (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
> + st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
> if (single_thread_wait(pr, 0))
> goto loop;
>
> Index: kern/sys_process.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/sys_process.c,v
> retrieving revision 1.86
> diff -u -p -r1.86 sys_process.c
> --- kern/sys_process.c 8 Feb 2021 10:51:02 -0000 1.86
> +++ kern/sys_process.c 4 Mar 2021 10:15:57 -0000
> @@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
> int
> ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
> {
> - struct proc *t; /* target thread */
> + struct proc *st, *t; /* target thread */
> struct process *tr; /* target process */
> int error = 0;
> int s;
> @@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> * from where it stopped."
> */
>
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = tr->ps_single;
> + st = READ_ONCE(tr->ps_single);
> + if (pid < THREAD_PID_OFFSET && st != NULL)
> + t = st;
>
> /* If the address parameter is not (int *)1, set the pc. */
> if ((int *)addr != (int *)1)
> @@ -464,8 +465,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> * from where it stopped."
> */
>
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = tr->ps_single;
> + st = READ_ONCE(tr->ps_single);
> + if (pid < THREAD_PID_OFFSET && st != NULL)
> + t = st;
>
> #ifdef PT_STEP
> /*
> @@ -495,8 +497,9 @@ ptrace_ctrl(struct proc *p, int req, pid
> break;
>
> case PT_KILL:
> - if (pid < THREAD_PID_OFFSET && tr->ps_single)
> - t = tr->ps_single;
> + st = READ_ONCE(tr->ps_single);
> + if (pid < THREAD_PID_OFFSET && st != NULL)
> + t = st;
>
> /* just send the process a KILL signal. */
> data = SIGKILL;
> @@ -536,6 +539,7 @@ int
> ptrace_kstate(struct proc *p, int req, pid_t pid, void *addr)
> {
> struct process *tr; /* target process */
> + struct proc *st;
> struct ptrace_event *pe = addr;
> int error;
>
> @@ -582,9 +586,9 @@ ptrace_kstate(struct proc *p, int req, p
> tr->ps_ptmask = pe->pe_set_event;
> break;
> case PT_GET_PROCESS_STATE:
> - if (tr->ps_single)
> - tr->ps_ptstat->pe_tid =
> - tr->ps_single->p_tid + THREAD_PID_OFFSET;
> + st = READ_ONCE(tr->ps_single);
> + if (st != NULL)
> + tr->ps_ptstat->pe_tid = st->p_tid + THREAD_PID_OFFSET;
> memcpy(addr, tr->ps_ptstat, sizeof *tr->ps_ptstat);
> break;
> default:
>
>