Bug Summary

File:proc/pgrp.c
Location:line 345, column 45
Description:Use of memory after it is freed

Annotated Source Code

1/* Session and process group manipulation
2 Copyright (C) 1992,93,94,95,96,99,2001,02,13 Free Software Foundation, Inc.
3
4This file is part of the GNU Hurd.
5
6The GNU Hurd is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11The GNU Hurd is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with the GNU Hurd; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* Written by Michael I. Bushnell. */
21
22#include <mach.h>
23#include <sys/types.h>
24#include <hurd/hurd_types.h>
25#include <sys/errno(*__errno_location ()).h>
26#include <stdlib.h>
27#include <signal.h>
28#include <assert.h>
29
30#include "proc.h"
31#include "process_S.h"
32#include "mutated_ourmsg_U.h"
33
34
35/* Create and return a new process group with pgid PGID in session SESS. */
36static inline struct pgrp *
37new_pgrp (pid_t pgid,
38 struct session *sess)
39{
40 struct pgrp *pg;
41
42 pg = malloc (sizeof (struct pgrp));
43 if (! pg)
44 return NULL((void*)0);
45
46 pg->pg_plist = 0;
47 pg->pg_pgid = pgid;
48 pg->pg_orphcnt = 0;
49
50 pg->pg_session = sess;
51 pg->pg_next = sess->s_pgrps;
52 if (pg->pg_next)
53 pg->pg_next->pg_prevp = &pg->pg_next;
54 sess->s_pgrps = pg;
55 pg->pg_prevp = &sess->s_pgrps;
56
57 add_pgrp_to_hash (pg);
58 return pg;
59}
60
61/* Create and return a new session with session leader P. */
62static inline struct session *
63new_session (struct proc *p)
64{
65 struct session *sess;
66
67 sess = malloc (sizeof (struct session));
68 if (! sess)
69 return NULL((void*)0);
70
71 sess->s_sid = p->p_pid;
72 sess->s_pgrps = 0;
73 sess->s_sessionid = MACH_PORT_NULL((mach_port_t) 0);
74
75 add_session_to_hash (sess);
76
77 return sess;
78}
79
80/* Free an empty session */
81static inline void
82free_session (struct session *s)
83{
84 if (s->s_sessionid)
85 mach_port_mod_refs (mach_task_self ()((__mach_task_self_ + 0)), s->s_sessionid,
86 MACH_PORT_RIGHT_RECEIVE((mach_port_right_t) 1), -1);
87 remove_session_from_hash (s);
88 free (s);
89}
90
91/* Free an empty process group. */
92static inline void
93free_pgrp (struct pgrp *pg)
94{
95 *pg->pg_prevp = pg->pg_next;
96 if (pg->pg_next)
12
Taking false branch
97 pg->pg_next->pg_prevp = pg->pg_prevp;
98 if (!pg->pg_session->s_pgrps)
13
Taking false branch
99 free_session (pg->pg_session);
100 remove_pgrp_from_hash (pg);
101 free (pg);
14
Memory is released
102}
103
104/* Implement proc_setsid as described in <hurd/process.defs>. */
105kern_return_t
106S_proc_setsid (struct proc *p)
107{
108 struct session *sess;
109
110 if (!p)
111 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
112
113 if (p->p_pgrp->pg_pgid == p->p_pid || pgrp_find (p->p_pid))
114 return EPERM((0x10 << 26) | ((1) & 0x3fff));
115
116 leave_pgrp (p);
117
118 sess = new_session (p);
119 p->p_pgrp= new_pgrp (p->p_pid, sess);
120 join_pgrp (p);
121
122 return 0;
123}
124
125/* Used in bootstrapping to set the pgrp of processes 0 and 1. */
126void
127boot_setsid (struct proc *p)
128{
129 struct session *sess;
130
131 sess = new_session (p);
132 p->p_pgrp = new_pgrp (p->p_pid, sess);
133 assert (p->p_pgrp)((p->p_pgrp) ? (void) (0) : __assert_fail ("p->p_pgrp",
"pgrp.c", 133, __PRETTY_FUNCTION__))
;
134 join_pgrp (p);
135 return;
136}
137
138/* Implement proc_getsid as described in <hurd/process.defs>. */
139kern_return_t
140S_proc_getsid (struct proc *callerp,
141 pid_t pid,
142 pid_t *sid)
143{
144 struct proc *p = pid_find (pid);
145 if (!p)
146 return ESRCH((0x10 << 26) | ((3) & 0x3fff));
147
148 /* No need to check CALLERP; we don't use it. */
149
150 *sid = p->p_pgrp->pg_session->s_sid;
151 return 0;
152}
153
154/* Implement proc_getsessionpids as described in <hurd/process.defs>. */
155kern_return_t
156S_proc_getsessionpids (struct proc *callerp,
157 pid_t sid,
158 pid_t **pids,
159 size_t *npidsp)
160{
161 int count;
162 struct pgrp *pg;
163 struct proc *p;
164 struct session *s;
165 pid_t *pp = *pids;
166 u_int npids = *npidsp;
167
168 /* No need to check CALLERP; we don't use it. */
169
170 s = session_find (sid);
171 if (!s)
172 return ESRCH((0x10 << 26) | ((3) & 0x3fff));
173
174 count = 0;
175 for (pg = s->s_pgrps; pg; pg = pg->pg_next)
176 for (p = pg->pg_plist; p; p = p->p_gnext)
177 {
178 if (++count <= npids)
179 *pp++ = p->p_pid;
180 }
181
182 if (count > npids)
183 /* They didn't all fit */
184 {
185 *pids = mmap (0, count * sizeof (pid_t), PROT_READ0x04|PROT_WRITE0x02,
186 MAP_ANON0x0002, 0, 0);
187 if (*pids == MAP_FAILED((void *) -1))
188 return errno(*__errno_location ());
189
190 pp = *pids;
191 for (pg = s->s_pgrps; pg; pg = pg->pg_next)
192 for (p = pg->pg_plist; p; p = p->p_gnext)
193 *pp++ = p->p_pid;
194 /* Set dealloc XXX */
195 }
196
197 *npidsp = count;
198 return 0;
199}
200
201/* Implement proc_getsessionpgids as described in <hurd/process.defs>. */
202kern_return_t
203S_proc_getsessionpgids (struct proc *callerp,
204 pid_t sid,
205 pid_t **pgids,
206 size_t *npgidsp)
207{
208 int count;
209 struct pgrp *pg;
210 struct session *s;
211 pid_t *pp = *pgids;
212 int npgids = *npgidsp;
213
214 /* No need to check CALLERP; we don't use it. */
215
216 s = session_find (sid);
217 if (!s)
218 return ESRCH((0x10 << 26) | ((3) & 0x3fff));
219 count = 0;
220
221 for (pg = s->s_pgrps; pg; pg = pg->pg_next)
222 if (++count <= npgids)
223 *pp++ = pg->pg_pgid;
224
225 if (count > npgids)
226 /* They didn't all fit. */
227 {
228 *pgids = mmap (0, count * sizeof (pid_t), PROT_READ0x04|PROT_WRITE0x02,
229 MAP_ANON0x0002, 0, 0);
230 if (*pgids == MAP_FAILED((void *) -1))
231 return errno(*__errno_location ());
232
233 pp = *pgids;
234 for (pg = s->s_pgrps; pg; pg = pg->pg_next)
235 *pp++ = pg->pg_pgid;
236 /* Dealloc ? XXX */
237 }
238 *npgidsp = count;
239 return 0;
240}
241
242/* Implement proc_getpgrppids as described in <hurd/process.defs>. */
243kern_return_t
244S_proc_getpgrppids (struct proc *callerp,
245 pid_t pgid,
246 pid_t **pids,
247 size_t *npidsp)
248{
249
250 struct proc *p;
251 struct pgrp *pg;
252 pid_t *pp = *pids;
253 unsigned int npids = *npidsp, count;
254
255 /* No need to check CALLERP; we don't use it. */
256
257 if (pgid == 0)
258 pg = callerp->p_pgrp;
259 else
260 {
261 pg = pgrp_find (pgid);
262 if (!pg)
263 return ESRCH((0x10 << 26) | ((3) & 0x3fff));
264 }
265
266 count = 0;
267 for (p = pg->pg_plist; p; p = p->p_gnext)
268 if (!p->p_important && ++count <= npids)
269 *pp++ = p->p_pid;
270
271 if (count > npids)
272 /* They didn't all fit. */
273 {
274 *pids = mmap (0, count * sizeof (pid_t), PROT_READ0x04|PROT_WRITE0x02,
275 MAP_ANON0x0002, 0, 0);
276 if (*pids == MAP_FAILED((void *) -1))
277 return errno(*__errno_location ());
278
279 pp = *pids;
280 for (p = pg->pg_plist; p; p = p->p_gnext)
281 if (!p->p_important)
282 *pp++ = p->p_pid;
283 /* Dealloc ? XXX */
284 }
285 *npidsp = count;
286 return 0;
287}
288
289/* Implement proc_getsidport as described in <hurd/process.defs>. */
290kern_return_t
291S_proc_getsidport (struct proc *p,
292 mach_port_t *sessport, mach_msg_type_name_t *sessport_type)
293{
294 error_t err = 0;
295
296 if (!p)
297 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
298
299 if (!p->p_pgrp)
300 *sessport = MACH_PORT_NULL((mach_port_t) 0);
301 else
302 {
303 if (p->p_pgrp->pg_session->s_sessionid == MACH_PORT_NULL((mach_port_t) 0))
304 err = mach_port_allocate (mach_task_self ()((__mach_task_self_ + 0)), MACH_PORT_RIGHT_RECEIVE((mach_port_right_t) 1),
305 &p->p_pgrp->pg_session->s_sessionid);
306 *sessport = p->p_pgrp->pg_session->s_sessionid;
307 }
308 *sessport_type = MACH_MSG_TYPE_MAKE_SEND20;
309 return err;
310}
311
312/* Implement proc_setpgrp as described in <hurd/process.defs>. */
313kern_return_t
314S_proc_setpgrp (struct proc *callerp,
315 pid_t pid,
316 pid_t pgid)
317{
318 struct proc *p;
319 struct pgrp *pg;
320
321 if (!callerp)
1
Assuming 'callerp' is non-null
2
Taking false branch
322 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
323
324 p = pid ? pid_find (pid) : callerp;
3
Assuming 'pid' is 0
4
'?' condition is false
325
326 if (!p || (p != callerp && p->p_parent != callerp))
327 return ESRCH((0x10 << 26) | ((3) & 0x3fff));
328
329 if (p->p_parent == callerp && p->p_exec)
330 return EACCES((0x10 << 26) | ((13) & 0x3fff));
331
332 if (!pgid)
5
Assuming 'pgid' is not equal to 0
6
Taking false branch
333 pgid = p->p_pid;
334 pg = pgrp_find (pgid);
335
336 if (p->p_pgrp->pg_session->s_sid == p->p_pid
337 || p->p_pgrp->pg_session != callerp->p_pgrp->pg_session
338 || ((pgid != p->p_pid
339 && (!pg || pg->pg_session != callerp->p_pgrp->pg_session))))
340 return EPERM((0x10 << 26) | ((1) & 0x3fff));
341
342 if (p->p_pgrp != pg)
7
Taking true branch
343 {
344 leave_pgrp (p);
8
Calling 'leave_pgrp'
16
Returned released memory
345 p->p_pgrp = pg ? pg : new_pgrp (pgid, p->p_pgrp->pg_session);
17
Assuming 'pg' is null
18
'?' condition is false
19
Use of memory after it is freed
346 join_pgrp (p);
347 }
348 else
349 nowait_msg_proc_newids (p->p_msgport, p->p_task, p->p_parent->p_pid,
350 pg->pg_pgid, !pg->pg_orphcnt);
351
352 return 0;
353}
354
355/* Implement proc_getpgrp as described in <hurd/process.defs>. */
356kern_return_t
357S_proc_getpgrp (struct proc *callerp,
358 pid_t pid,
359 pid_t *pgid)
360{
361 struct proc *p = pid_find (pid);
362
363 /* No need to check CALLERP; we don't use it. */
364
365 if (!p)
366 return ESRCH((0x10 << 26) | ((3) & 0x3fff));
367
368 if (p->p_pgrp)
369 *pgid = p->p_pgrp->pg_pgid;
370
371 return 0;
372}
373
374/* Implement proc_mark_exec as described in <hurd/process.defs>. */
375kern_return_t
376S_proc_mark_exec (struct proc *p)
377{
378 if (!p)
379 return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff));
380 p->p_exec = 1;
381 return 0;
382}
383
384/* Make process P no longer a member of its process group.
385 Note that every process is always a member of some process group;
386 this must be followed by setting P->p_pgrp and then calling
387 join_pgrp. */
388void
389leave_pgrp (struct proc *p)
390{
391 struct pgrp *pg = p->p_pgrp;
392
393 *p->p_gprevp = p->p_gnext;
394 if (p->p_gnext)
9
Taking false branch
395 p->p_gnext->p_gprevp = p->p_gprevp;
396
397 /* If we were the last member of our pgrp, free it */
398 if (!pg->pg_plist)
10
Taking true branch
399 free_pgrp (pg);
11
Calling 'free_pgrp'
15
Returned released memory via 1st parameter
400 else if (p->p_parent->p_pgrp != pg
401 && p->p_parent->p_pgrp->pg_session == pg->pg_session
402 && !--pg->pg_orphcnt)
403 {
404 /* We were the last process keeping this from being
405 an orphaned process group -- do the orphaning gook */
406 struct proc *ip;
407 int dosignal = 0;
408
409 for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
410 {
411 if (ip->p_stopped)
412 dosignal = 1;
413 if (ip->p_msgport != MACH_PORT_NULL((mach_port_t) 0))
414 nowait_msg_proc_newids (ip->p_msgport, ip->p_task, ip->p_parent->p_pid,
415 ip->p_pid, 1);
416 }
417 if (dosignal)
418 for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
419 {
420 send_signal (ip->p_msgport, SIGHUP1, ip->p_task);
421 send_signal (ip->p_msgport, SIGCONT19, ip->p_task);
422 }
423 }
424}
425
426/* Cause process P to join its process group. */
427void
428join_pgrp (struct proc *p)
429{
430 struct pgrp *pg = p->p_pgrp;
431 struct proc *tp;
432 int origorphcnt;
433
434 p->p_gnext = pg->pg_plist;
435 p->p_gprevp = &pg->pg_plist;
436 if (pg->pg_plist)
437 pg->pg_plist->p_gprevp = &p->p_gnext;
438 pg->pg_plist = p;
439
440 origorphcnt = !!pg->pg_orphcnt;
441 if (p->p_parent->p_pgrp != pg
442 && p->p_parent->p_pgrp->pg_session == pg->pg_session)
443 pg->pg_orphcnt++;
444 if (origorphcnt != !!pg->pg_orphcnt)
445 {
446 /* Tell all the processes that their status has changed */
447 for (tp = pg->pg_plist; tp; tp = tp->p_gnext)
448 if (tp->p_msgport != MACH_PORT_NULL((mach_port_t) 0))
449 nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
450 tp->p_parent->p_pid, pg->pg_pgid,
451 !pg->pg_orphcnt);
452 }
453 else if (p->p_msgport != MACH_PORT_NULL((mach_port_t) 0))
454 /* Always notify process P, because its pgrp has changed. */
455 nowait_msg_proc_newids (p->p_msgport, p->p_task,
456 p->p_parent->p_pid, pg->pg_pgid, !pg->pg_orphcnt);
457}