2a1306574cd1451bada0292b603d2b53b2ff2759
[openafs.git] / src / afs / afs_osi_gcpags.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "afs/sysincludes.h"    /* Standard vendor system headers */
15 #include "afsincludes.h"        /* Afs-based standard headers */
16 #include "afs/afs_stats.h"      /* afs statistics */
17 #ifdef AFS_AIX_ENV
18 #include <sys/adspace.h>        /* for vm_att(), vm_det() */
19 #endif
20
21 #if AFS_GCPAGS
22
23 /* afs_osi_TraverseProcTable() - Walk through the systems process
24  * table, calling afs_GCPAGs_perproc_func() for each process.
25  */
26
27 #if defined(AFS_SUN5_ENV)
28 void
29 afs_osi_TraverseProcTable(void)
30 {
31     afs_proc_t *prp;
32     for (prp = practive; prp != NULL; prp = prp->p_next) {
33         afs_GCPAGs_perproc_func(prp);
34     }
35 }
36 #endif
37
38 #if defined(AFS_HPUX_ENV)
39
40 /*
41  * NOTE: h/proc_private.h gives the process table locking rules
42  * It indicates that access to p_cred must be protected by
43  * mp_mtproc_lock(p);
44  * mp_mtproc_unlock(p);
45  *
46  * The code in sys/pm_prot.c uses pcred_lock() to protect access to
47  * the process creds, and uses mp_mtproc_lock() only for audit-related
48  * changes.  To be safe, we use both.
49  */
50
51 void
52 afs_osi_TraverseProcTable(void)
53 {
54     register proc_t *p;
55     int endchain = 0;
56
57     MP_SPINLOCK(activeproc_lock);
58     MP_SPINLOCK(sched_lock);
59     pcred_lock();
60
61     /*
62      * Instead of iterating through all of proc[], traverse only
63      * the list of active processes.  As an example of this,
64      * see foreach_process() in sys/vm_sched.c.
65      *
66      * We hold the locks for the entire scan in order to get a
67      * consistent view of the current set of creds.
68      */
69
70     for (p = proc; endchain == 0; p = &proc[p->p_fandx]) {
71         if (p->p_fandx == 0) {
72             endchain = 1;
73         }
74
75         if (system_proc(p))
76             continue;
77
78         mp_mtproc_lock(p);
79         afs_GCPAGs_perproc_func(p);
80         mp_mtproc_unlock(p);
81     }
82
83     pcred_unlock();
84     MP_SPINUNLOCK(sched_lock);
85     MP_SPINUNLOCK(activeproc_lock);
86 }
87 #endif
88
89 #if defined(AFS_SGI_ENV)
90
91 #ifdef AFS_SGI65_ENV
92 /* TODO: Fix this later. */
93 static int
94 SGI_ProcScanFunc(void *p, void *arg, int mode)
95 {
96     return 0;
97 }
98 #else /* AFS_SGI65_ENV */
99 static int
100 SGI_ProcScanFunc(proc_t * p, void *arg, int mode)
101 {
102     afs_int32(*perproc_func) (afs_proc_t *) = arg;
103     int code = 0;
104     /* we pass in the function pointer for arg,
105      * mode ==0 for startup call, ==1 for each valid proc,
106      * and ==2 for terminate call.
107      */
108     if (mode == 1) {
109         code = perproc_func(p);
110     }
111     return code;
112 }
113 #endif /* AFS_SGI65_ENV */
114
115 void
116 afs_osi_TraverseProcTable(void)
117 {
118     procscan(SGI_ProcScanFunc, afs_GCPAGs_perproc_func);
119 }
120 #endif /* AFS_SGI_ENV */
121
122 #if defined(AFS_AIX_ENV)
123 #ifdef AFS_AIX51_ENV
124 #define max_proc v.ve_proc
125 #endif
126 void
127 afs_osi_TraverseProcTable(void)
128 {
129     afs_proc_t *p;
130     int i;
131
132     /*
133      * For binary compatibility, on AIX we need to be careful to use the
134      * proper size of a struct proc, even if it is different from what
135      * we were compiled with.
136      */
137     if (!afs_gcpags_procsize)
138         return;
139
140 #ifndef AFS_AIX51_ENV
141     simple_lock(&proc_tbl_lock);
142 #endif
143     for (p = (afs_proc_t *)v.vb_proc, i = 0; p < max_proc;
144          p = (afs_proc_t *)((char *)p + afs_gcpags_procsize), i++) {
145
146 #ifdef AFS_AIX51_ENV
147         if (p->p_pvprocp->pv_stat == SNONE)
148             continue;
149         if (p->p_pvprocp->pv_stat == SIDL)
150             continue;
151         if (p->p_pvprocp->pv_stat == SEXIT)
152             continue;
153 #else
154         if (p->p_stat == SNONE)
155             continue;
156         if (p->p_stat == SIDL)
157             continue;
158         if (p->p_stat == SEXIT)
159             continue;
160 #endif
161
162         /* sanity check */
163
164         if (PROCMASK(p->p_pid) != i) {
165             afs_gcpags = AFS_GCPAGS_EPIDCHECK;
166             break;
167         }
168
169         /* sanity check */
170
171         if ((p->p_nice < P_NICE_MIN) || (P_NICE_MAX < p->p_nice)) {
172             afs_gcpags = AFS_GCPAGS_ENICECHECK;
173             break;
174         }
175
176         afs_GCPAGs_perproc_func(p);
177     }
178 #ifndef AFS_AIX51_ENV
179     simple_unlock(&proc_tbl_lock);
180 #endif
181 }
182 #endif
183
184 #if (defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)) || defined(AFS_FBSD_ENV)
185 void
186 afs_osi_TraverseProcTable(void)
187 {
188     afs_proc_t *p;
189     LIST_FOREACH(p, &allproc, p_list) {
190         if (p->p_stat == SIDL)
191             continue;
192         if (p->p_stat == SZOMB)
193             continue;
194         if (p->p_flag & P_SYSTEM)
195             continue;
196         afs_GCPAGs_perproc_func(p);
197     }
198 }
199 #endif
200
201 #if defined(AFS_LINUX22_ENV)
202 #ifdef EXPORTED_TASKLIST_LOCK
203 extern rwlock_t tasklist_lock __attribute__((weak));
204 #endif
205 void
206 afs_osi_TraverseProcTable(void)
207 {
208 #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_HAS_CRED) || defined(EXPORTED_RCU_READ_LOCK))
209     struct task_struct *p;
210
211 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
212     if (&tasklist_lock)
213         read_lock(&tasklist_lock);
214 #endif /* EXPORTED_TASKLIST_LOCK */
215 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) 
216 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
217     else
218 #endif /* EXPORTED_TASKLIST_LOCK && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
219         rcu_read_lock();
220 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) */
221     
222 #ifdef DEFINED_FOR_EACH_PROCESS
223     for_each_process(p) if (p->pid) {
224 #ifdef STRUCT_TASK_STRUCT_HAS_EXIT_STATE
225         if (p->exit_state)
226             continue;
227 #else
228         if (p->state & TASK_ZOMBIE)
229             continue;
230 #endif
231         afs_GCPAGs_perproc_func(p);
232     }
233 #else
234     for_each_task(p) if (p->pid) {
235 #ifdef STRUCT_TASK_STRUCT_HAS_EXIT_STATE
236         if (p->exit_state)
237             continue;
238 #else
239         if (p->state & TASK_ZOMBIE)
240             continue;
241 #endif
242         afs_GCPAGs_perproc_func(p);
243     }
244 #endif
245 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
246     if (&tasklist_lock)
247         read_unlock(&tasklist_lock);
248 #endif /* EXPORTED_TASKLIST_LOCK */
249 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) 
250 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) && defined(EXPORTED_TASKLIST_LOCK)
251     else
252 #endif /* EXPORTED_TASKLIST_LOCK && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
253         rcu_read_unlock();
254 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) */
255 #endif
256 }
257 #endif
258
259 /* return a pointer (sometimes a static copy ) to the cred for a
260  * given afs_proc_t.
261  * subsequent calls may overwrite the previously returned value.
262  */
263
264 #if defined(AFS_SGI65_ENV)
265 const afs_ucred_t *
266 afs_osi_proc2cred(afs_proc_t * p)
267 {
268     return NULL;
269 }
270 #elif defined(AFS_HPUX_ENV)
271 const afs_ucred_t *
272 afs_osi_proc2cred(afs_proc_t * p)
273 {
274     if (!p)
275         return;
276
277     /*
278      * Cannot use afs_warnuser() here, as the code path
279      * eventually wants to grab sched_lock, which is
280      * already held here
281      */
282
283     return p_cred(p);
284 }
285 #elif defined(AFS_AIX_ENV)
286
287 /* GLOBAL DECLARATIONS */
288
289 /*
290  * LOCKS: the caller must do
291  *  simple_lock(&proc_tbl_lock);
292  *  simple_unlock(&proc_tbl_lock);
293  * around calls to this function.
294  */
295
296 const afs_ucred_t *
297 afs_osi_proc2cred(afs_proc_t * pproc)
298 {
299     afs_ucred_t *pcred = 0;
300
301     /*
302      * pointer to process user structure valid in *our*
303      * address space
304      *
305      * The user structure for a process is stored in the user
306      * address space (as distinct from the kernel address
307      * space), and so to refer to the user structure of a
308      * different process we must employ special measures.
309      *
310      * I followed the example used in the AIX getproc() system
311      * call in bos/kernel/proc/getproc.c
312      */
313     struct user *xmem_userp;
314
315     struct xmem dp;             /* ptr to xmem descriptor */
316     int xm;                     /* xmem result */
317
318     if (!pproc) {
319         return pcred;
320     }
321
322     /*
323      * The process private segment in which the user
324      * area is located may disappear. We need to increment
325      * its use count. Therefore we
326      *    - get the proc_tbl_lock to hold the segment.
327      *    - get the p_lock to lockout vm_cleardata.
328      *    - vm_att to load the segment register (no check)
329      *    - xmattach to bump its use count.
330      *    - release the p_lock.
331      *    - release the proc_tbl_lock.
332      *    - do whatever we need.
333      *    - xmdetach to decrement the use count.
334      *    - vm_det to free the segment register (no check)
335      */
336
337     xmem_userp = NULL;
338     xm = XMEM_FAIL;
339     /* simple_lock(&proc_tbl_lock); */
340 #ifdef __64BIT__
341     if (pproc->p_adspace != vm_handle(NULLSEGID, (int32long64_t) 0)) {
342 #else
343     if (pproc->p_adspace != NULLSEGVAL) {
344 #endif
345
346 #ifdef AFS_AIX51_ENV
347         simple_lock(&pproc->p_pvprocp->pv_lock);
348 #else
349         simple_lock(&pproc->p_lock);
350 #endif
351
352         if (pproc->p_threadcount &&
353 #ifdef AFS_AIX51_ENV
354             pproc->p_pvprocp->pv_threadlist) {
355 #else
356             pproc->p_threadlist) {
357 #endif
358
359             /*
360              * arbitrarily pick the first thread in pproc
361              */
362             struct thread *pproc_thread =
363 #ifdef AFS_AIX51_ENV
364                 pproc->p_pvprocp->pv_threadlist;
365 #else
366                 pproc->p_threadlist;
367 #endif
368
369             /*
370              * location of 'struct user' in pproc's
371              * address space
372              */
373             struct user *pproc_userp = pproc_thread->t_userp;
374
375             /*
376              * create a pointer valid in my own address space
377              */
378
379             xmem_userp = (struct user *)vm_att(pproc->p_adspace, pproc_userp);
380
381             dp.aspace_id = XMEM_INVAL;
382             xm = xmattach(xmem_userp, sizeof(*xmem_userp), &dp, SYS_ADSPACE);
383         }
384
385 #ifdef AFS_AIX51_ENV
386         simple_unlock(&pproc->p_pvprocp->pv_lock);
387 #else
388         simple_unlock(&pproc->p_lock);
389 #endif
390     }
391     /* simple_unlock(&proc_tbl_lock); */
392     if (xm == XMEM_SUCC) {
393
394         static afs_ucred_t cred;
395
396         /*
397          * What locking should we use to protect access to the user
398          * area?  If needed also change the code in AIX/osi_groups.c.
399          */
400
401         /* copy cred to local address space */
402         cred = *xmem_userp->U_cred;
403         pcred = &cred;
404
405         xmdetach(&dp);
406     }
407     if (xmem_userp) {
408         vm_det((void *)xmem_userp);
409     }
410
411     return pcred;
412 }
413
414 #elif defined(AFS_DARWIN80_ENV) 
415 const afs_ucred_t *
416 afs_osi_proc2cred(afs_proc_t * pr)
417 {
418     afs_ucred_t *rv = NULL;
419     static afs_ucred_t cr;
420     struct ucred *pcred;
421
422     if (pr == NULL) {
423         return NULL;
424     }
425     pcred = proc_ucred(pr);
426     cr.cr_ref = 1;
427     afs_set_cr_uid(&cr, afs_cr_uid(pcred));
428     cr.cr_ngroups = pcred->cr_ngroups;
429     memcpy(cr.cr_groups, pcred->cr_groups,
430            NGROUPS * sizeof(gid_t));
431     return &cr;
432 }
433 #elif defined(AFS_FBSD_ENV)
434 const afs_ucred_t *
435 afs_osi_proc2cred(afs_proc_t * pr)
436 {
437     /*
438      * This whole function is kind of an ugly hack.  For one, the
439      * 'const' is a lie.  Also, we should probably be holding the
440      * proc mutex around all accesses to the credentials structure,
441      * but the present API does not allow this.
442      */
443     return pr->p_ucred;
444 }
445 #elif defined(AFS_DARWIN_ENV)
446 const afs_ucred_t *
447 afs_osi_proc2cred(afs_proc_t * pr)
448 {
449     afs_ucred_t *rv = NULL;
450     static afs_ucred_t cr;
451
452     if (pr == NULL) {
453         return NULL;
454     }
455
456     if ((pr->p_stat == SSLEEP) || (pr->p_stat == SRUN)
457         || (pr->p_stat == SSTOP)) {
458         pcred_readlock(pr);
459         cr.cr_ref = 1;
460         afs_set_cr_uid(&cr, afs_cr_uid(pr->p_cred->pc_ucred));
461         cr.cr_ngroups = pr->p_cred->pc_ucred->cr_ngroups;
462         memcpy(cr.cr_groups, pr->p_cred->pc_ucred->cr_groups,
463                NGROUPS * sizeof(gid_t));
464         pcred_unlock(pr);
465         rv = &cr;
466     }
467
468     return rv;
469 }
470 #elif defined(AFS_LINUX22_ENV)
471 #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_HAS_CRED) || defined(EXPORTED_RCU_READ_LOCK))
472 const afs_ucred_t *
473 afs_osi_proc2cred(afs_proc_t * pr)
474 {
475     afs_ucred_t *rv = NULL;
476     static afs_ucred_t cr;
477
478     if (pr == NULL) {
479         return NULL;
480     }
481
482     if ((pr->state == TASK_RUNNING) || (pr->state == TASK_INTERRUPTIBLE)
483         || (pr->state == TASK_UNINTERRUPTIBLE)
484         || (pr->state == TASK_STOPPED)) {
485         /* This is dangerous. If anyone ever crfree's the cred that's
486          * returned from here, we'll go boom, because it's statically
487          * allocated. */
488         atomic_set(&cr.cr_ref, 1);
489         afs_set_cr_uid(&cr, task_uid(pr));
490 #if defined(AFS_LINUX26_ENV)
491 #if defined(STRUCT_TASK_HAS_CRED)
492         get_group_info(pr->cred->group_info);
493         set_cr_group_info(&cr, pr->cred->group_info);
494 #else
495         get_group_info(pr->group_info);
496         set_cr_group_info(&cr, pr->group_info);
497 #endif
498 #else
499         cr.cr_ngroups = pr->ngroups;
500         memcpy(cr.cr_groups, pr->groups, NGROUPS * sizeof(gid_t));
501 #endif
502         rv = &cr;
503     }
504
505     return rv;
506 }
507 #endif
508 #else
509 const afs_ucred_t *
510 afs_osi_proc2cred(afs_proc_t * pr)
511 {
512     afs_ucred_t *rv = NULL;
513
514     if (pr == NULL) {
515         return NULL;
516     }
517     rv = pr->p_cred;
518
519     return rv;
520 }
521 #endif
522
523 #endif /* AFS_GCPAGS */