Commit | Line | Data |
---|---|---|
e541e3bd KT |
1 | # |
2 | /* | |
3 | */ | |
4 | ||
5 | #include "../param.h" | |
6 | #include "../systm.h" | |
7 | #include "../user.h" | |
8 | #include "../proc.h" | |
9 | #include "../inode.h" | |
10 | #include "../reg.h" | |
11 | ||
12 | /* | |
13 | * Priority for tracing | |
14 | */ | |
15 | #define IPCPRI (-1) | |
16 | ||
17 | /* | |
18 | * Structure to access an array of integers. | |
19 | */ | |
20 | struct | |
21 | { | |
22 | int inta[]; | |
23 | }; | |
24 | ||
25 | /* | |
26 | * Tracing variables. | |
27 | * Used to pass trace command from | |
28 | * parent to child being traced. | |
29 | * This data base cannot be | |
30 | * shared and is locked | |
31 | * per user. | |
32 | */ | |
33 | struct | |
34 | { | |
35 | int ip_lock; | |
36 | int ip_req; | |
37 | int ip_addr; | |
38 | int ip_data; | |
39 | } ipc; | |
40 | ||
41 | /* | |
42 | * Send the specified signal to | |
43 | * all processes with 'tp' as its | |
44 | * controlling teletype. | |
45 | * Called by tty.c for quits and | |
46 | * interrupts. | |
47 | */ | |
48 | signal(tp, sig) | |
49 | { | |
50 | register struct proc *p; | |
51 | ||
52 | for(p = &proc[0]; p < &proc[NPROC]; p++) | |
53 | if(p->p_ttyp == tp) | |
54 | psignal(p, sig); | |
55 | } | |
56 | ||
57 | /* | |
58 | * Send the specified signal to | |
59 | * the specified process. | |
60 | */ | |
61 | psignal(p, sig) | |
62 | int *p; | |
63 | { | |
64 | register *rp; | |
65 | ||
66 | if(sig >= NSIG) | |
67 | return; | |
68 | rp = p; | |
69 | if(rp->p_sig != SIGKIL) | |
70 | rp->p_sig = sig; | |
71 | if(rp->p_stat > PUSER) | |
72 | rp->p_stat = PUSER; | |
73 | if(rp->p_stat == SWAIT) | |
74 | setrun(rp); | |
75 | } | |
76 | ||
77 | /* | |
78 | * Returns true if the current | |
79 | * process has a signal to process. | |
80 | * This is asked at least once | |
81 | * each time a process enters the | |
82 | * system. | |
83 | * A signal does not do anything | |
84 | * directly to a process; it sets | |
85 | * a flag that asks the process to | |
86 | * do something to itself. | |
87 | */ | |
88 | issig() | |
89 | { | |
90 | register n; | |
91 | register struct proc *p; | |
92 | ||
93 | p = u.u_procp; | |
94 | if(n = p->p_sig) { | |
95 | if (p->p_flag&STRC) { | |
96 | stop(); | |
97 | if ((n = p->p_sig) == 0) | |
98 | return(0); | |
99 | } | |
100 | if((u.u_signal[n]&1) == 0) | |
101 | return(n); | |
102 | } | |
103 | return(0); | |
104 | } | |
105 | ||
106 | /* | |
107 | * Enter the tracing STOP state. | |
108 | * In this state, the parent is | |
109 | * informed and the process is able to | |
110 | * receive commands from the parent. | |
111 | */ | |
112 | stop() | |
113 | { | |
114 | register struct proc *pp, *cp; | |
115 | ||
116 | loop: | |
117 | cp = u.u_procp; | |
118 | if(cp->p_ppid != 1) | |
119 | for (pp = &proc[0]; pp < &proc[NPROC]; pp++) | |
120 | if (pp->p_pid == cp->p_ppid) { | |
121 | wakeup(pp); | |
122 | cp->p_stat = SSTOP; | |
123 | swtch(); | |
124 | if ((cp->p_flag&STRC)==0 || procxmt()) | |
125 | return; | |
126 | goto loop; | |
127 | } | |
128 | exit(); | |
129 | } | |
130 | ||
131 | /* | |
132 | * Perform the action specified by | |
133 | * the current signal. | |
134 | * The usual sequence is: | |
135 | * if(issig()) | |
136 | * psig(); | |
137 | */ | |
138 | psig() | |
139 | { | |
140 | register n, p; | |
141 | register *rp; | |
142 | ||
143 | rp = u.u_procp; | |
144 | n = rp->p_sig; | |
145 | rp->p_sig = 0; | |
146 | if((p=u.u_signal[n]) != 0) { | |
147 | u.u_error = 0; | |
148 | if(n != SIGINS && n != SIGTRC) | |
149 | u.u_signal[n] = 0; | |
150 | n = u.u_ar0[R6] - 4; | |
151 | grow(n); | |
152 | suword(n+2, u.u_ar0[RPS]); | |
153 | suword(n, u.u_ar0[R7]); | |
154 | u.u_ar0[R6] = n; | |
155 | u.u_ar0[RPS] =& ~TBIT; | |
156 | u.u_ar0[R7] = p; | |
157 | return; | |
158 | } | |
159 | switch(n) { | |
160 | ||
161 | case SIGQIT: | |
162 | case SIGINS: | |
163 | case SIGTRC: | |
164 | case SIGIOT: | |
165 | case SIGEMT: | |
166 | case SIGFPT: | |
167 | case SIGBUS: | |
168 | case SIGSEG: | |
169 | case SIGSYS: | |
170 | u.u_arg[0] = n; | |
171 | if(core()) | |
172 | n =+ 0200; | |
173 | } | |
174 | u.u_arg[0] = (u.u_ar0[R0]<<8) | n; | |
175 | exit(); | |
176 | } | |
177 | ||
178 | /* | |
179 | * Create a core image on the file "core" | |
180 | * If you are looking for protection glitches, | |
181 | * there are probably a wealth of them here | |
182 | * when this occurs to a suid command. | |
183 | * | |
184 | * It writes USIZE block of the | |
185 | * user.h area followed by the entire | |
186 | * data+stack segments. | |
187 | */ | |
188 | core() | |
189 | { | |
190 | register s, *ip; | |
191 | extern schar; | |
192 | ||
193 | u.u_error = 0; | |
194 | u.u_dirp = "core"; | |
195 | ip = namei(&schar, 1); | |
196 | if(ip == NULL) { | |
197 | if(u.u_error) | |
198 | return(0); | |
199 | ip = maknode(0666); | |
200 | if(ip == NULL) | |
201 | return(0); | |
202 | } | |
203 | if(!access(ip, IWRITE) && | |
204 | (ip->i_mode&IFMT) == 0 && | |
205 | u.u_uid == u.u_ruid) { | |
206 | itrunc(ip); | |
207 | u.u_offset[0] = 0; | |
208 | u.u_offset[1] = 0; | |
209 | u.u_base = &u; | |
210 | u.u_count = USIZE*64; | |
211 | u.u_segflg = 1; | |
212 | writei(ip); | |
213 | s = u.u_procp->p_size - USIZE; | |
214 | estabur(0, s, 0, 0); | |
215 | u.u_base = 0; | |
216 | u.u_count = s*64; | |
217 | u.u_segflg = 0; | |
218 | writei(ip); | |
219 | } | |
220 | iput(ip); | |
221 | return(u.u_error==0); | |
222 | } | |
223 | ||
224 | /* | |
225 | * grow the stack to include the SP | |
226 | * true return if successful. | |
227 | */ | |
228 | ||
229 | grow(sp) | |
230 | char *sp; | |
231 | { | |
232 | register a, si, i; | |
233 | ||
234 | if(sp >= -u.u_ssize*64) | |
235 | return(0); | |
236 | si = ldiv(-sp, 64) - u.u_ssize + SINCR; | |
237 | if(si <= 0) | |
238 | return(0); | |
239 | if(estabur(u.u_tsize, u.u_dsize, u.u_ssize+si, u.u_sep)) | |
240 | return(0); | |
241 | expand(u.u_procp->p_size+si); | |
242 | a = u.u_procp->p_addr + u.u_procp->p_size; | |
243 | for(i=u.u_ssize; i; i--) { | |
244 | a--; | |
245 | copyseg(a-si, a); | |
246 | } | |
247 | for(i=si; i; i--) | |
248 | clearseg(--a); | |
249 | u.u_ssize =+ si; | |
250 | return(1); | |
251 | } | |
252 | ||
253 | /* | |
254 | * sys-trace system call. | |
255 | */ | |
256 | ptrace() | |
257 | { | |
258 | register struct proc *p; | |
259 | ||
260 | if (u.u_arg[2] <= 0) { | |
261 | u.u_procp->p_flag =| STRC; | |
262 | return; | |
263 | } | |
264 | for (p=proc; p < &proc[NPROC]; p++) | |
265 | if (p->p_stat==SSTOP | |
266 | && p->p_pid==u.u_arg[0] | |
267 | && p->p_ppid==u.u_procp->p_pid) | |
268 | goto found; | |
269 | u.u_error = ESRCH; | |
270 | return; | |
271 | ||
272 | found: | |
273 | while (ipc.ip_lock) | |
274 | sleep(&ipc, IPCPRI); | |
275 | ipc.ip_lock = p->p_pid; | |
276 | ipc.ip_data = u.u_ar0[R0]; | |
277 | ipc.ip_addr = u.u_arg[1] & ~01; | |
278 | ipc.ip_req = u.u_arg[2]; | |
279 | p->p_flag =& ~SWTED; | |
280 | setrun(p); | |
281 | while (ipc.ip_req > 0) | |
282 | sleep(&ipc, IPCPRI); | |
283 | u.u_ar0[R0] = ipc.ip_data; | |
284 | if (ipc.ip_req < 0) | |
285 | u.u_error = EIO; | |
286 | ipc.ip_lock = 0; | |
287 | wakeup(&ipc); | |
288 | } | |
289 | ||
290 | /* | |
291 | * Code that the child process | |
292 | * executes to implement the command | |
293 | * of the parent process in tracing. | |
294 | */ | |
295 | procxmt() | |
296 | { | |
297 | register int i; | |
298 | register int *p; | |
299 | ||
300 | if (ipc.ip_lock != u.u_procp->p_pid) | |
301 | return(0); | |
302 | i = ipc.ip_req; | |
303 | ipc.ip_req = 0; | |
304 | wakeup(&ipc); | |
305 | switch (i) { | |
306 | ||
307 | /* read user I */ | |
308 | case 1: | |
309 | if (fuibyte(ipc.ip_addr) == -1) | |
310 | goto error; | |
311 | ipc.ip_data = fuiword(ipc.ip_addr); | |
312 | break; | |
313 | ||
314 | /* read user D */ | |
315 | case 2: | |
316 | if (fubyte(ipc.ip_addr) == -1) | |
317 | goto error; | |
318 | ipc.ip_data = fuword(ipc.ip_addr); | |
319 | break; | |
320 | ||
321 | /* read u */ | |
322 | case 3: | |
323 | i = ipc.ip_addr; | |
324 | if (i<0 || i >= (USIZE<<6)) | |
325 | goto error; | |
326 | ipc.ip_data = u.inta[i>>1]; | |
327 | break; | |
328 | ||
329 | /* write user I (for now, always an error) */ | |
330 | case 4: | |
331 | if (suiword(ipc.ip_addr, 0) < 0) | |
332 | goto error; | |
333 | suiword(ipc.ip_addr, ipc.ip_data); | |
334 | break; | |
335 | ||
336 | /* write user D */ | |
337 | case 5: | |
338 | if (suword(ipc.ip_addr, 0) < 0) | |
339 | goto error; | |
340 | suword(ipc.ip_addr, ipc.ip_data); | |
341 | break; | |
342 | ||
343 | /* write u */ | |
344 | case 6: | |
345 | p = &u.inta[ipc.ip_addr>>1]; | |
346 | if (p >= u.u_fsav && p < &u.u_fsav[25]) | |
347 | goto ok; | |
348 | for (i=0; i<9; i++) | |
349 | if (p == &u.u_ar0[regloc[i]]) | |
350 | goto ok; | |
351 | goto error; | |
352 | ok: | |
353 | if (p == &u.u_ar0[RPS]) { | |
354 | ipc.ip_data =| 0170000; /* assure user space */ | |
355 | ipc.ip_data =& ~0340; /* priority 0 */ | |
356 | } | |
357 | *p = ipc.ip_data; | |
358 | break; | |
359 | ||
360 | /* set signal and continue */ | |
361 | case 7: | |
362 | u.u_procp->p_sig = ipc.ip_data; | |
363 | return(1); | |
364 | ||
365 | /* force exit */ | |
366 | case 8: | |
367 | exit(); | |
368 | ||
369 | default: | |
370 | error: | |
371 | ipc.ip_req = -1; | |
372 | } | |
373 | return(0); | |
374 | } |