* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)kern_sig.c 7.10 (Berkeley) %G%
#include "machine/mtpr.h"
#define cantmask (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP))
#define stopsigmask (sigmask(SIGSTOP)|sigmask(SIGTSTP)| \
sigmask(SIGTTIN)|sigmask(SIGTTOU))
* Generalized interface signal handler.
} *uap
= (struct a
*)u
.u_ap
;
register struct sigvec
*sv
;
if (sig
<= 0 || sig
>= NSIG
|| sig
== SIGKILL
|| sig
== SIGSTOP
) {
sv
->sv_handler
= u
.u_signal
[sig
];
sv
->sv_mask
= u
.u_sigmask
[sig
];
if ((u
.u_sigonstack
& bit
) != 0)
sv
->sv_flags
|= SV_ONSTACK
;
if ((u
.u_sigintr
& bit
) != 0)
sv
->sv_flags
|= SV_INTERRUPT
;
copyout((caddr_t
)sv
, (caddr_t
)uap
->osv
, sizeof (vec
));
copyin((caddr_t
)uap
->nsv
, (caddr_t
)sv
, sizeof (vec
));
if (sig
== SIGCONT
&& sv
->sv_handler
== SIG_IGN
) {
register struct sigvec
*sv
;
* Change setting atomically.
u
.u_signal
[sig
] = sv
->sv_handler
;
u
.u_sigmask
[sig
] = sv
->sv_mask
&~ cantmask
;
if (sv
->sv_flags
& SV_INTERRUPT
)
if (sv
->sv_flags
& SV_ONSTACK
)
if (sv
->sv_handler
== SIG_IGN
) {
p
->p_sig
&= ~bit
; /* never to be seen again */
if (sv
->sv_handler
== SIG_DFL
)
} *uap
= (struct a
*)u
.u_ap
;
register struct proc
*p
= u
.u_procp
;
u
.u_r
.r_val1
= p
->p_sigmask
;
p
->p_sigmask
|= uap
->mask
&~ cantmask
;
} *uap
= (struct a
*)u
.u_ap
;
register struct proc
*p
= u
.u_procp
;
u
.u_r
.r_val1
= p
->p_sigmask
;
p
->p_sigmask
= uap
->mask
&~ cantmask
;
} *uap
= (struct a
*)u
.u_ap
;
register struct proc
*p
= u
.u_procp
;
* When returning from sigpause, we want
* the old mask to be restored after the
* signal handler has finished. Thus, we
* save it here and mark the proc structure
* to indicate this (should be in u.).
u
.u_oldmask
= p
->p_sigmask
;
p
->p_sigmask
= uap
->mask
&~ cantmask
;
sleep((caddr_t
)&u
, PSLEP
);
} *uap
= (struct a
*)u
.u_ap
;
u
.u_error
= copyout((caddr_t
)&u
.u_sigstack
, (caddr_t
)uap
->oss
,
sizeof (struct sigstack
));
copyin((caddr_t
)uap
->nss
, (caddr_t
)&ss
, sizeof (ss
));
} *uap
= (struct a
*)u
.u_ap
;
if (uap
->signo
< 0 || uap
->signo
> NSIG
) {
/* kill single process */
if (u
.u_uid
&& u
.u_uid
!= p
->p_uid
)
case -1: /* broadcast signal */
u
.u_error
= killpg1(uap
->signo
, 0, 1);
case 0: /* signal own process group */
u
.u_error
= killpg1(uap
->signo
, 0, 0);
default: /* negative explicit process group */
u
.u_error
= killpg1(uap
->signo
, -uap
->pid
, 0);
} *uap
= (struct a
*)u
.u_ap
;
if (uap
->signo
< 0 || uap
->signo
> NSIG
) {
u
.u_error
= killpg1(uap
->signo
, uap
->pgid
, 0);
/* KILL CODE SHOULDNT KNOW ABOUT PROCESS INTERNALS !?! */
killpg1(signo
, pgid
, all
)
for (p
= allproc
; p
!= NULL
; p
= p
->p_nxt
) {
if (p
->p_ppid
== 0 || p
->p_flag
&SSYS
||
(u
.u_uid
&& u
.u_uid
!= p
->p_uid
&&
!(signo
== SIGCONT
&& inferior(p
))))
* zero pgid means send to my process group.
pgrp
= u
.u_procp
->p_pgrp
;
(signo
==SIGTTIN
|| signo
==SIGTTOU
|| signo
==SIGTSTP
))
for (p
= pgrp
->pg_mem
; p
!= NULL
; p
= p
->p_pgrpnxt
) {
if (p
->p_ppid
== 0 || p
->p_flag
&SSYS
)
if (u
.u_uid
&& u
.u_uid
!= p
->p_uid
&&
!(signo
== SIGCONT
&& inferior(p
))) {
return (error
? error
: (f
== 0 ? ESRCH
: 0));
* Send the specified signal to
* all processes with 'pgid' as
register struct pgrp
*pgrp
;
if ((pgrp
= pgfind(pgid
)) == NULL
)
register struct pgrp
*pgrp
;
(sig
==SIGTTIN
|| sig
==SIGTTOU
|| sig
==SIGTSTP
))
for (p
= pgrp
->pg_mem
; p
!= NULL
; p
= p
->p_pgrpnxt
)
* Send the specified signal to
register int (*action
)();
if ((unsigned)sig
>= NSIG
)
* If proc is traced, always give parent a chance.
* If the signal is being ignored,
* then we forget about it immediately.
if (p
->p_sigignore
& mask
)
else if (p
->p_sigcatch
& mask
)
if ((p
->p_flag
&STRC
) || action
!= SIG_DFL
)
p
->p_sig
&= ~stopsigmask
;
p
->p_sig
&= ~sigmask(SIGCONT
);
* Defer further processing for signals which are held.
* If process is sleeping at negative priority
* we can't interrupt the sleep... the signal will
* be noticed when the process returns through
* Process is sleeping and traced... make it runnable
* so it can discover the signal in issig() and stop
* These are the signals which by default
* If a child in vfork(), stopping could
psignal(p
->p_pptr
, SIGCHLD
);
* These signals are special in that they
* don't get propogated... if the process
* isn't interested, forget it.
p
->p_sig
&= ~mask
; /* take it away */
* All other signals cause the process to run
* If traced process is already stopped,
* then no further action is necessary.
* Kill signal always sets processes running.
* If the process catches SIGCONT, let it handle
* the signal itself. If it isn't waiting on
* an event, then it goes back to run state.
* Otherwise, process goes back to sleep state.
if (action
!= SIG_DFL
|| p
->p_wchan
== 0)
* Already stopped, don't need to stop again.
* (If we did the shell could get confused.)
p
->p_sig
&= ~mask
; /* take it away */
* If process is sleeping interruptibly, then
* unstick it so that when it is continued
* it can look at the signal.
* But don't setrun the process as its not to
* be unstopped by the signal alone.
if (p
->p_wchan
&& p
->p_pri
> PZERO
)
* SRUN, SIDL, SZOMB do nothing with the signal,
* other than kicking ourselves if we are running.
* It will either never be noticed, or noticed very soon.
if (p
== u
.u_procp
&& !noproc
)
* Raise priority to at least PUSER.
* Returns true if the current
* process has a signal to process.
* The signal to process is put in p_cursig.
* This is asked at least once each time a process enters the
* system (though this can usually be done without actually
* calling issig by checking the pending signal masks.)
* A signal does not do anything
* directly to a process; it sets
* a flag that asks the process to
* do something to itself.
sigbits
= p
->p_sig
&~ p
->p_sigmask
;
if ((p
->p_flag
&STRC
) == 0)
sigbits
&= ~p
->p_sigignore
;
sig
= ffs((long)sigbits
);
p
->p_sig
&= ~mask
; /* take the signal! */
if (p
->p_flag
&STRC
&& (p
->p_flag
&SVFORK
) == 0) {
* If traced, always stop, and stay
* stopped until released by the parent.
psignal(p
->p_pptr
, SIGCHLD
);
} while (!procxmt() && p
->p_flag
&STRC
);
* If the traced bit got turned off,
* then put the signal taken above back into p_sig
* and go back up to the top to rescan signals.
* This ensures that p_sig* and u_signal are consistent.
if ((p
->p_flag
&STRC
) == 0) {
* If parent wants us to take the signal,
* then it will leave it in p->p_cursig;
* otherwise we just look for signals again.
* If signal is being masked put it back
* into p_sig and look for other signals.
if (p
->p_sigmask
& mask
) {
switch ((int)u
.u_signal
[sig
]) {
* Don't take default actions on system processes.
psignal(p
->p_pptr
, SIGCHLD
);
* These signals are normally not
* sent if the action is the default.
continue; /* == ignore */
* Masking above should prevent us
* ever trying to take action on a held
* or ignored signal, unless process is traced.
if ((p
->p_flag
&STRC
) == 0)
* This signal has an action, let
* Didn't find a signal to send.
* Let psig process the signal.
* Put the argument process into the stopped
* state and notify the parent via wakeup.
* Signals are handled elsewhere.
wakeup((caddr_t
)p
->p_pptr
);
* Perform the action specified by
* The signal bit has already been cleared by issig,
* and the current signal number stored in p->p_cursig.
register struct proc
*p
= u
.u_procp
;
register int sig
= p
->p_cursig
;
int mask
= sigmask(sig
), returnmask
;
register int (*action
)();
action
= u
.u_signal
[sig
];
if (action
== SIG_IGN
|| (p
->p_sigmask
& mask
))
* Set the new mask value and also defer further
* occurences of this signal (unless we're simulating
* the old signal facilities).
* Special case: user has done a sigpause. Here the
* current mask is not of interest, but rather the
* mask from before the sigpause is what we want restored
* after the signal processing is completed.
if (p
->p_flag
& SOUSIG
) {
if (sig
!= SIGILL
&& sig
!= SIGTRAP
) {
u
.u_signal
[sig
] = SIG_DFL
;
if (p
->p_flag
& SOMASK
) {
returnmask
= u
.u_oldmask
;
returnmask
= p
->p_sigmask
;
p
->p_sigmask
|= u
.u_sigmask
[sig
] | mask
;
sendsig(action
, sig
, returnmask
);
* Create a core image on the file "core"
* If you are looking for protection glitches,
* there are probably a wealth of them here
* when this occurs to a suid command.
* It writes UPAGES block of the
* user.h area followed by the entire
register struct vnode
*vp
;
register struct nameidata
*ndp
= &u
.u_nd
;
if (u
.u_uid
!= u
.u_ruid
|| u
.u_gid
!= u
.u_rgid
)
if (ctob(UPAGES
+ u
.u_dsize
+ u
.u_ssize
) >=
u
.u_rlimit
[RLIMIT_CORE
].rlim_cur
)
if (u
.u_procp
->p_textp
) {
VOP_LOCK(u
.u_procp
->p_textp
->x_vptr
);
error
= VOP_ACCESS(u
.u_procp
->p_textp
->x_vptr
, VREAD
, u
.u_cred
);
VOP_UNLOCK(u
.u_procp
->p_textp
->x_vptr
);
ndp
->ni_segflg
= UIO_SYSSPACE
;
if (error
= vn_open(ndp
, FCREAT
|FWRITE
, 0644))
if (vp
->v_type
!= VREG
||
VOP_GETATTR(vp
, &vattr
, u
.u_cred
) ||
/* unmap funky devices in the user's address space */
for (fd
= 0; fd
< u
.u_lastfile
; fd
++)
if (u
.u_ofile
[fd
] && (u
.u_pofile
[fd
] & UF_MAPPED
))
VOP_SETATTR(vp
, &vattr
, u
.u_cred
);
error
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
)&u
, ctob(UPAGES
), (off_t
)0,
UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, ndp
->ni_cred
, (int *)0);
error
= vn_rdwr(UIO_WRITE
, vp
,
(caddr_t
)ctob(dptov(u
.u_procp
, 0)),
(int)ctob(u
.u_dsize
), (off_t
)ctob(UPAGES
), UIO_USERSPACE
,
IO_NODELOCKED
|IO_UNIT
, ndp
->ni_cred
, (int *)0);
error
= vn_rdwr(UIO_WRITE
, vp
,
(caddr_t
)ctob(sptov(u
.u_procp
, u
.u_ssize
- 1)),
(off_t
)ctob(UPAGES
) + ctob(u
.u_dsize
), UIO_USERSPACE
,
IO_NODELOCKED
|IO_UNIT
, ndp
->ni_cred
, (int *)0);