From b3218816e064d9278f3b6833b74e24a66b6ce03a Mon Sep 17 00:00:00 2001 From: Venkatesh Srinivas Date: Thu, 21 Mar 2013 03:50:52 -0400 Subject: [PATCH] kernel -- syscons: Resolve unmatched PHOLD() for MOUSE_MODE ioctl. When a syscons process put itself into MOUSE_MODE, a process-hold was being placed to stabilize the process for signal delivery. The hold was not being released on process exit, however. This change reworks syscons to install a per-process flag as to whether it is in MOUSE_MODE or not and to remove the excess hold on exit(). It also cleans up the error handling and prevents stale process pointers from lingering in syscons stat structures. Reported-by: mneumann, Studbolt Closes-bug: 2521 --- sys/dev/misc/syscons/Makefile | 1 - sys/dev/misc/syscons/scmouse.c | 166 ++++++++++++++++++++++++++++++----------- sys/sys/proc.h | 4 +- 3 files changed, 124 insertions(+), 47 deletions(-) diff --git a/sys/dev/misc/syscons/Makefile b/sys/dev/misc/syscons/Makefile index 99d0fe1..c8d785a 100644 --- a/sys/dev/misc/syscons/Makefile +++ b/sys/dev/misc/syscons/Makefile @@ -1,5 +1,4 @@ # $FreeBSD: src/sys/modules/syscons/Makefile,v 1.11.2.2 2003/05/15 02:02:39 murray Exp $ -# $DragonFly: src/sys/dev/misc/syscons/Makefile,v 1.5 2007/08/09 02:27:51 swildner Exp $ # .include "../../../platform/${MACHINE_PLATFORM}/Makefile.inc" diff --git a/sys/dev/misc/syscons/scmouse.c b/sys/dev/misc/syscons/scmouse.c index b78b7b2..0cb4dc8 100644 --- a/sys/dev/misc/syscons/scmouse.c +++ b/sys/dev/misc/syscons/scmouse.c @@ -24,18 +24,19 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/dev/syscons/scmouse.c,v 1.12.2.3 2001/07/28 12:51:47 yokota Exp $ - * $DragonFly: src/sys/dev/misc/syscons/scmouse.c,v 1.14 2008/08/10 19:47:31 swildner Exp $ */ #include "opt_syscons.h" #include #include +#include #include #include #include #include #include +#include #include #include @@ -54,11 +55,13 @@ #ifndef SC_NO_SYSMOUSE -/* local variables */ static int cut_buffer_size; static u_char *cut_buffer; /* local functions */ +static void sc_mouse_init(void *); +static void sc_mouse_uninit(void *); + static void set_mouse_pos(scr_stat *scp); #ifndef SC_NO_CUTPASTE static int skip_spc_right(scr_stat *scp, int p); @@ -567,13 +570,56 @@ mouse_paste(scr_stat *scp) #endif /* SC_NO_CUTPASTE */ +static void +sc_mouse_exit1_proc(struct proc *p) +{ + scr_stat *scp; + + scp = p->p_drv_priv; + KKASSERT(scp != NULL); + + get_mplock(); + KKASSERT(scp->mouse_proc == p); + KKASSERT(scp->mouse_pid == p->p_pid); + + scp->mouse_signal = 0; + scp->mouse_proc = NULL; + scp->mouse_pid = 0; + rel_mplock(); + + PRELE(p); + p->p_flags &= ~P_SCMOUSE; + p->p_drv_priv = NULL; +} + +/* + * sc_mouse_exit1: + * + * Handle exit1 for processes registered as MOUSE_MODE handlers. + * We must remove a process hold, established when MOUSE_MODE + * was enabled. + */ +static void +sc_mouse_exit1(struct thread *td) +{ + struct proc *p; + + p = td->td_proc; + KKASSERT(p != NULL); + + if ((p->p_flags & P_SCMOUSE) == 0) + return; + + + sc_mouse_exit1_proc(p); +} + int sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) { mouse_info_t *mouse; scr_stat *cur_scp; scr_stat *scp; - struct proc *oproc; int f; scp = SC_STAT(tp->t_dev); @@ -581,28 +627,57 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) switch (cmd) { case CONS_MOUSECTL: /* control mouse arrow */ - mouse = (mouse_info_t*)data; + mouse = (mouse_info_t*) data; cur_scp = scp->sc->cur_scp; switch (mouse->operation) { + /* + * Setup a process to receive signals on mouse events. + */ case MOUSE_MODE: - if (ISSIGVALID(mouse->u.mode.signal)) { - oproc = scp->mouse_proc; - scp->mouse_signal = mouse->u.mode.signal; - scp->mouse_proc = curproc; - scp->mouse_pid = curproc->p_pid; - PHOLD(curproc); + get_mplock(); + + if (!ISSIGVALID(mouse->u.mode.signal)) { + /* Setting MOUSE_MODE w/ an invalid signal is used to disarm */ + if (scp->mouse_proc == curproc) { + sc_mouse_exit1_proc(curproc); + rel_mplock(); + return 0; + } else { + rel_mplock(); + return EINVAL; + } } else { - oproc = scp->mouse_proc; - scp->mouse_signal = 0; - scp->mouse_proc = NULL; - scp->mouse_pid = 0; - } - if (oproc) { - PRELE(oproc); - oproc = NULL; - } - return 0; + /* Only one mouse process per syscons */ + if (scp->mouse_proc) { + rel_mplock(); + return EINVAL; + } + + /* Only one syscons signal source per process */ + if (curproc->p_flags & P_SCMOUSE) { + rel_mplock(); + return EINVAL; + } + + /* + * Process is stabilized by a hold, which is removed from + * sc_mouse_exit1. scp's mouse_{signal,proc,pid} fields + * are synchronized by the MP Lock. + */ + scp->mouse_signal = mouse->u.mode.signal; + scp->mouse_proc = curproc; + scp->mouse_pid = curproc->p_pid; + curproc->p_flags |= P_SCMOUSE; + KKASSERT(curproc->p_drv_priv == NULL); + curproc->p_drv_priv = scp; + PHOLD(curproc); + + rel_mplock(); + return 0; + } + /*NOTREACHED*/ + break; case MOUSE_SHOW: crit_enter(); @@ -692,21 +767,14 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) cur_scp->status &= ~MOUSE_HIDDEN; + get_mplock(); if (cur_scp->mouse_signal) { - /* has controlling process died? */ - if (cur_scp->mouse_proc && - (cur_scp->mouse_proc != pfindn(cur_scp->mouse_pid))){ - oproc = cur_scp->mouse_proc; - cur_scp->mouse_signal = 0; - cur_scp->mouse_proc = NULL; - cur_scp->mouse_pid = 0; - if (oproc) - PRELE(oproc); - } else { - ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); - break; - } + KKASSERT(cur_scp->mouse_proc != NULL); + ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); + rel_mplock(); + break; } + rel_mplock(); if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) break; @@ -749,20 +817,14 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) cur_scp->status &= ~MOUSE_HIDDEN; + get_mplock(); if (cur_scp->mouse_signal) { - if (cur_scp->mouse_proc && - (cur_scp->mouse_proc != pfindn(cur_scp->mouse_pid))){ - oproc = cur_scp->mouse_proc; - cur_scp->mouse_signal = 0; - cur_scp->mouse_proc = NULL; - cur_scp->mouse_pid = 0; - if (oproc) - PRELE(oproc); - } else { - ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); - break; - } + KKASSERT(cur_scp->mouse_proc != NULL); + ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); + rel_mplock(); + break; } + rel_mplock(); if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) break; @@ -839,4 +901,18 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) return ENOIOCTL; } +void +sc_mouse_init(void *unused) +{ + at_exit(sc_mouse_exit1); +} + +void +sc_mouse_uninit(void *unused) +{ +} + +SYSINIT(sc_mouse_init, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_init, NULL); +SYSUNINIT(sc_mouse_uninit, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_uninit, NULL); + #endif /* SC_NO_SYSMOUSE */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index bcb6efb..3047485 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -333,6 +333,7 @@ struct proc { struct spinlock p_spin; /* Spinlock for LWP access to proc */ struct lwkt_token p_token; /* Token for LWP access to proc */ struct sem_undo *p_sem_undo; /* Fast semaphore tracking lookup */ + void *p_drv_priv; /* scp linkage (for syscons) */ }; #define lwp_wchan lwp_thread->td_wchan @@ -348,7 +349,8 @@ struct proc { #define P_PPWAIT 0x00010 /* Parent is waiting for child to exec/exit */ #define P_PROFIL 0x00020 /* Has started profiling */ #define P_POSTEXIT 0x00040 /* Prevent procfs from stepping after this pt */ -#define P_UNUSED7 0x00080 /* was: Sleep is interruptible */ +#define P_SCMOUSE 0x00080 /* Process is held by syscons ioctl */ + /* was: Sleep is interruptible */ #define P_SUGID 0x00100 /* Had set id privileges since last exec */ #define P_SYSTEM 0x00200 /* System proc: no sigs, stats or swapping */ #define P_UNUSED10 0x00400 /* was: SIGSTOP status */ -- 1.7.12