diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index 8529c76..92a0a86 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -1181,7 +1181,7 @@ nfscl_procdoesntexist(u_int8_t *own) tl.cval[2] = *own++; tl.cval[3] = *own++; pid = tl.lval; - p = pfind_locked(pid); + p = pfind_locked(pid, 0); if (p == NULL) return (1); if (p->p_stats == NULL) { diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 6342119..812d992 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -1793,6 +1793,7 @@ note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep) sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN); sbuf_set_drain(sb, sbuf_drain_count, &size); sbuf_bcat(sb, &structsize, sizeof(structsize)); + sx_slock(&p->p_imagelock); PROC_LOCK(p); kern_proc_filedesc_out(p, sb, -1); sbuf_finish(sb); @@ -1801,6 +1802,7 @@ note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep) } else { structsize = sizeof(struct kinfo_file); sbuf_bcat(sb, &structsize, sizeof(structsize)); + sx_slock(&p->p_imagelock); PROC_LOCK(p); kern_proc_filedesc_out(p, sb, -1); } diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 141d438..fcb7f3c 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -477,6 +477,7 @@ proc0_init(void *dummy __unused) p->p_flag2 = 0; p->p_state = PRS_NORMAL; knlist_init_mtx(&p->p_klist, &p->p_mtx); + sx_init(&p->p_imagelock, "process imagelock"); STAILQ_INIT(&p->p_ktr); p->p_nice = NZERO; /* pid_max cannot be greater than PID_MAX */ diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d860256..9b2a3ac 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -3023,7 +3023,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) struct tty *tp; name = (int *)arg1; - error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); + error = pget((pid_t)name[0], PGET_LOCK, &p); if (error != 0) return (error); fdp = fdhold(p); @@ -3208,6 +3208,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) } FILEDESC_SUNLOCK(fdp); fddrop(fdp); + sx_sunlock(&p->p_imagelock); free(kif, M_TEMP); return (0); } @@ -3496,6 +3497,7 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) FILEDESC_SUNLOCK(fdp); fddrop(fdp); fail: + sx_sunlock(&p->p_imagelock); free(efbuf, M_TEMP); return (error); } @@ -3516,7 +3518,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) name = (int *)arg1; sbuf_new_for_sysctl(&sb, NULL, FILEDESC_SBUF_SIZE, req); - error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); + error = pget((pid_t)name[0], PGET_LOCK, &p); if (error != 0) { sbuf_delete(&sb); return (error); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 489096b..35aa127 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -370,6 +370,7 @@ do_execve(td, args, mac_p) * that might allow a local user to illicitly obtain elevated * privileges. */ + sx_xlock(&p->p_imagelock); PROC_LOCK(p); KASSERT((p->p_flag & P_INEXEC) == 0, ("%s(): process already has P_INEXEC flag", __func__)); @@ -917,6 +918,7 @@ exec_fail: SDT_PROBE(proc, kernel, , exec__failure, error, 0, 0, 0, 0); done2: + sx_xunlock(&p->p_imagelock); #ifdef MAC mac_execve_exit(imgp); mac_execve_interpreter_exit(interpvplabel); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 9efaac2..0b97ce6 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -148,6 +148,7 @@ exit1(struct thread *td, int rv) /* * MUST abort all other threads before proceeding past here. */ + sx_xlock(&p->p_imagelock); PROC_LOCK(p); while (p->p_flag & P_HADTHREADS) { /* @@ -206,7 +207,9 @@ exit1(struct thread *td, int rv) * PIOCWAIT in case they aren't listening for S_EXIT stops or * decided to wait again after we told them we are exiting. */ + p->p_flag |= P_WEXIT; + sx_xunlock(&p->p_imagelock); wakeup(&p->p_stype); /* diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 3163622..62a7184 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -228,6 +228,7 @@ proc_init(void *mem, int size, int flags) bzero(&p->p_mtx, sizeof(struct mtx)); mtx_init(&p->p_mtx, "process lock", NULL, MTX_DEF | MTX_DUPOK); mtx_init(&p->p_slock, "process slock", NULL, MTX_SPIN | MTX_RECURSE); + sx_init(&p->p_imagelock, "process imagelock"); cv_init(&p->p_pwait, "ppwait"); cv_init(&p->p_dbgwait, "dbgwait"); TAILQ_INIT(&p->p_threads); /* all threads in proc */ @@ -275,16 +276,20 @@ inferior(p) } struct proc * -pfind_locked(pid_t pid) +pfind_locked(pid_t pid, int lockimage) { struct proc *p; sx_assert(&allproc_lock, SX_LOCKED); LIST_FOREACH(p, PIDHASH(pid), p_hash) { if (p->p_pid == pid) { + if (lockimage) + sx_slock(&p->p_imagelock); PROC_LOCK(p); if (p->p_state == PRS_NEW) { PROC_UNLOCK(p); + if (lockimage) + sx_sunlock(&p->p_imagelock); p = NULL; } break; @@ -305,7 +310,7 @@ pfind(pid_t pid) struct proc *p; sx_slock(&allproc_lock); - p = pfind_locked(pid); + p = pfind_locked(pid, 0); sx_sunlock(&allproc_lock); return (p); } @@ -361,11 +366,17 @@ int pget(pid_t pid, int flags, struct proc **pp) { struct proc *p; - int error; + int error, lockimage; + + lockimage = ((flags & PGET_IMAGELOCK) != 0); + if (lockimage) { + MPASS((flags & PGET_NOTWEXIT) != 0); + MPASS((flags & PGET_HOLD) == 0); + } sx_slock(&allproc_lock); if (pid <= PID_MAX) { - p = pfind_locked(pid); + p = pfind_locked(pid, lockimage); if (p == NULL && (flags & PGET_NOTWEXIT) == 0) p = zpfind_locked(pid); } else if ((flags & PGET_NOTID) == 0) { @@ -410,6 +421,8 @@ pget(pid_t pid, int flags, struct proc **pp) return (0); errout: PROC_UNLOCK(p); + if (lockimage) + sx_sunlock(&p->p_imagelock); return (error); } diff --git a/sys/sys/proc.h b/sys/sys/proc.h index fbd064c..fa034c8 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -511,6 +511,7 @@ struct proc { struct proc *p_pptr; /* (c + e) Pointer to parent process. */ LIST_ENTRY(proc) p_sibling; /* (e) List of sibling processes. */ LIST_HEAD(, proc) p_children; /* (e) Pointer to list of children. */ + struct sx p_imagelock; struct mtx p_mtx; /* (n) Lock for this struct. */ struct ksiginfo *p_ksi; /* Locked by parent proc lock */ sigqueue_t p_sigqueue; /* (c) Sigs not delivered to a td. */ @@ -835,7 +836,7 @@ extern struct proc *initproc, *pageproc; /* Process slots for init, pager. */ extern struct uma_zone *proc_zone; struct proc *pfind(pid_t); /* Find process by id. */ -struct proc *pfind_locked(pid_t pid); +struct proc *pfind_locked(pid_t pid, int imagelock); struct pgrp *pgfind(pid_t); /* Find process group by id. */ struct proc *zpfind(pid_t); /* Find zombie process by id. */ @@ -849,8 +850,10 @@ struct proc *zpfind(pid_t); /* Find zombie process by id. */ #define PGET_NOTWEXIT 0x00010 /* Check that the process is not in P_WEXIT. */ #define PGET_NOTINEXEC 0x00020 /* Check that the process is not in P_INEXEC. */ #define PGET_NOTID 0x00040 /* Do not assume tid if pid > PID_MAX. */ +#define PGET_IMAGELOCK 0x00080 #define PGET_WANTREAD (PGET_HOLD | PGET_CANDEBUG | PGET_NOTWEXIT) +#define PGET_LOCK (PGET_CANDEBUG | PGET_NOTWEXIT | PGET_IMAGELOCK) int pget(pid_t pid, int flags, struct proc **pp);