cregit-Linux how code gets into the kernel

Release 4.10 fs/proc/base.c

Directory: fs/proc
/*
 *  linux/fs/proc/base.c
 *
 *  Copyright (C) 1991, 1992 Linus Torvalds
 *
 *  proc base directory handling functions
 *
 *  1999, Al Viro. Rewritten. Now it covers the whole per-process part.
 *  Instead of using magical inumbers to determine the kind of object
 *  we allocate and fill in-core inodes upon lookup. They don't even
 *  go into icache. We cache the reference to task_struct upon lookup too.
 *  Eventually it should become a filesystem in its own. We don't use the
 *  rest of procfs anymore.
 *
 *
 *  Changelog:
 *  17-Jan-2005
 *  Allan Bezerra
 *  Bruna Moreira <bruna.moreira@indt.org.br>
 *  Edjard Mota <edjard.mota@indt.org.br>
 *  Ilias Biris <ilias.biris@indt.org.br>
 *  Mauricio Lin <mauricio.lin@indt.org.br>
 *
 *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
 *
 *  A new process specific entry (smaps) included in /proc. It shows the
 *  size of rss for each memory area. The maps entry lacks information
 *  about physical memory size (rss) for each mapped file, i.e.,
 *  rss information for executables and library files.
 *  This additional information is useful for any tools that need to know
 *  about physical memory consumption for a process specific library.
 *
 *  Changelog:
 *  21-Feb-2005
 *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
 *  Pud inclusion in the page table walking.
 *
 *  ChangeLog:
 *  10-Mar-2005
 *  10LE Instituto Nokia de Tecnologia - INdT:
 *  A better way to walks through the page table as suggested by Hugh Dickins.
 *
 *  Simo Piiroinen <simo.piiroinen@nokia.com>:
 *  Smaps information related to shared, private, clean and dirty pages.
 *
 *  Paul Mundt <paul.mundt@nokia.com>:
 *  Overall revision about smaps.
 */

#include <linux/uaccess.h>

#include <linux/errno.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/init.h>
#include <linux/capability.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
#include <linux/mnt_namespace.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/rcupdate.h>
#include <linux/kallsyms.h>
#include <linux/stacktrace.h>
#include <linux/resource.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/ptrace.h>
#include <linux/tracehook.h>
#include <linux/printk.h>
#include <linux/cgroup.h>
#include <linux/cpuset.h>
#include <linux/audit.h>
#include <linux/poll.h>
#include <linux/nsproxy.h>
#include <linux/oom.h>
#include <linux/elf.h>
#include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
#include <linux/fs_struct.h>
#include <linux/slab.h>
#include <linux/flex_array.h>
#include <linux/posix-timers.h>
#ifdef CONFIG_HARDWALL
#include <asm/hardwall.h>
#endif
#include <trace/events/oom.h>
#include "internal.h"
#include "fd.h"

/* NOTE:
 *      Implementing inode permission operations in /proc is almost
 *      certainly an error.  Permission checks need to happen during
 *      each system call not at open time.  The reason is that most of
 *      what we wish to check for permissions in /proc varies at runtime.
 *
 *      The classic example of a problem is opening file descriptors
 *      in /proc for a task before it execs a suid executable.
 */


static u8 nlink_tid;

static u8 nlink_tgid;


struct pid_entry {
	
const char *name;
	
unsigned int len;
	
umode_t mode;
	
const struct inode_operations *iop;
	
const struct file_operations *fop;
	
union proc_op op;
};


#define NOD(NAME, MODE, IOP, FOP, OP) {                       \
        .name = (NAME),                                 \
        .len  = sizeof(NAME) - 1,                       \
        .mode = MODE,                                   \
        .iop  = IOP,                                    \
        .fop  = FOP,                                    \
        .op   = OP,                                     \
}


#define DIR(NAME, MODE, iops, fops)	\
	NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {} )

#define LNK(NAME, get_link)					\
	NOD(NAME, (S_IFLNK|S_IRWXUGO),                          \
                &proc_pid_link_inode_operations, NULL,          \
                { .proc_get_link = get_link } )

#define REG(NAME, MODE, fops)				\
	NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})

#define ONE(NAME, MODE, show)				\
	NOD(NAME, (S_IFREG|(MODE)),                     \
                NULL, &proc_single_file_operations,     \
                { .proc_show = show } )

/*
 * Count the number of hardlinks for the pid_entry table, excluding the .
 * and .. links.
 */

static unsigned int __init pid_entry_nlink(const struct pid_entry *entries, unsigned int n) { unsigned int i; unsigned int count; count = 2; for (i = 0; i < n; ++i) { if (S_ISDIR(entries[i].mode)) ++count; } return count; }

Contributors

PersonTokensPropCommitsCommitProp
vegard nossumvegard nossum6095.24%150.00%
alexey dobriyanalexey dobriyan34.76%150.00%
Total63100.00%2100.00%


static int get_task_root(struct task_struct *task, struct path *root) { int result = -ENOENT; task_lock(task); if (task->fs) { get_fs_root(task->fs, root); result = 0; } task_unlock(task); return result; }

Contributors

PersonTokensPropCommitsCommitProp
hugh dickinshugh dickins2341.07%125.00%
eric w. biedermaneric w. biederman2035.71%125.00%
albert cahalanalbert cahalan712.50%125.00%
miklos szeredimiklos szeredi610.71%125.00%
Total56100.00%4100.00%


static int proc_cwd_link(struct dentry *dentry, struct path *path) { struct task_struct *task = get_proc_task(d_inode(dentry)); int result = -ENOENT; if (task) { task_lock(task); if (task->fs) { get_fs_pwd(task->fs, path); result = 0; } task_unlock(task); put_task_struct(task); } return result; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman3948.75%114.29%
miklos szeredimiklos szeredi2430.00%114.29%
albert cahalanalbert cahalan67.50%114.29%
hugh dickinshugh dickins33.75%114.29%
david howellsdavid howells33.75%114.29%
cyrill gorcunovcyrill gorcunov33.75%114.29%
jan blunckjan blunck22.50%114.29%
Total80100.00%7100.00%


static int proc_root_link(struct dentry *dentry, struct path *path) { struct task_struct *task = get_proc_task(d_inode(dentry)); int result = -ENOENT; if (task) { result = get_task_root(task, path); put_task_struct(task); } return result; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman3967.24%112.50%
albert cahalanalbert cahalan58.62%112.50%
cyrill gorcunovcyrill gorcunov35.17%112.50%
hugh dickinshugh dickins35.17%112.50%
david howellsdavid howells35.17%112.50%
chuck leverchuck lever23.45%112.50%
jan blunckjan blunck23.45%112.50%
miklos szeredimiklos szeredi11.72%112.50%
Total58100.00%8100.00%


static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, size_t _count, loff_t *pos) { struct task_struct *tsk; struct mm_struct *mm; char *page; unsigned long count = _count; unsigned long arg_start, arg_end, env_start, env_end; unsigned long len1, len2, len; unsigned long p; char c; ssize_t rv; BUG_ON(*pos < 0); tsk = get_proc_task(file_inode(file)); if (!tsk) return -ESRCH; mm = get_task_mm(tsk); put_task_struct(tsk); if (!mm) return 0; /* Check if process spawned far enough to have cmdline. */ if (!mm->env_end) { rv = 0; goto out_mmput; } page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) { rv = -ENOMEM; goto out_mmput; } down_read(&mm->mmap_sem); arg_start = mm->arg_start; arg_end = mm->arg_end; env_start = mm->env_start; env_end = mm->env_end; up_read(&mm->mmap_sem); BUG_ON(arg_start > arg_end); BUG_ON(env_start > env_end); len1 = arg_end - arg_start; len2 = env_end - env_start; /* Empty ARGV. */ if (len1 == 0) { rv = 0; goto out_free_page; } /* * Inherently racy -- command line shares address space * with code and data. */ rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0); if (rv <= 0) goto out_free_page; rv = 0; if (c == '\0') { /* Command line (set of strings) occupies whole ARGV. */ if (len1 <= *pos) goto out_free_page; p = arg_start + *pos; len = len1 - *pos; while (count > 0 && len > 0) { unsigned int _count; int nr_read; _count = min3(count, len, PAGE_SIZE); nr_read = access_remote_vm(mm, p, page, _count, 0); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) goto out_free_page; if (copy_to_user(buf, page, nr_read)) { rv = -EFAULT; goto out_free_page; } p += nr_read; len -= nr_read; buf += nr_read; count -= nr_read; rv += nr_read; } } else { /* * Command line (1 string) occupies ARGV and maybe * extends into ENVP. */ if (len1 + len2 <= *pos) goto skip_argv_envp; if (len1 <= *pos) goto skip_argv; p = arg_start + *pos; len = len1 - *pos; while (count > 0 && len > 0) { unsigned int _count, l; int nr_read; bool final; _count = min3(count, len, PAGE_SIZE); nr_read = access_remote_vm(mm, p, page, _count, 0); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) goto out_free_page; /* * Command line can be shorter than whole ARGV * even if last "marker" byte says it is not. */ final = false; l = strnlen(page, nr_read); if (l < nr_read) { nr_read = l; final = true; } if (copy_to_user(buf, page, nr_read)) { rv = -EFAULT; goto out_free_page; } p += nr_read; len -= nr_read; buf += nr_read; count -= nr_read; rv += nr_read; if (final) goto out_free_page; } skip_argv: /* * Command line (1 string) occupies ARGV and * extends into ENVP. */ if (len1 <= *pos) { p = env_start + *pos - len1; len = len1 + len2 - *pos; } else { p = env_start; len = len2; } while (count > 0 && len > 0) { unsigned int _count, l; int nr_read; bool final; _count = min3(count, len, PAGE_SIZE); nr_read = access_remote_vm(mm, p, page, _count, 0); if (nr_read < 0) rv = nr_read; if (nr_read <= 0) goto out_free_page; /* Find EOS. */ final = false; l = strnlen(page, nr_read); if (l < nr_read) { nr_read = l; final = true; } if (copy_to_user(buf, page, nr_read)) { rv = -EFAULT; goto out_free_page; } p += nr_read; len -= nr_read; buf += nr_read; count -= nr_read; rv += nr_read; if (final) goto out_free_page; } skip_argv_envp: ; } out_free_page: free_page((unsigned long)page); out_mmput: mmput(mm); if (rv > 0) *pos += rv; return rv; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan80597.81%337.50%
eric w. biedermaneric w. biederman101.22%112.50%
linus torvaldslinus torvalds40.49%112.50%
christoph lameterchristoph lameter20.24%112.50%
andrea arcangeliandrea arcangeli10.12%112.50%
al viroal viro10.12%112.50%
Total823100.00%8100.00%

static const struct file_operations proc_pid_cmdline_ops = { .read = proc_pid_cmdline_read, .llseek = generic_file_llseek, }; #ifdef CONFIG_KALLSYMS /* * Provides a wchan file via kallsyms in a proper one-value-per-file format. * Returns the resolved symbol. If that fails, simply return the address. */
static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { unsigned long wchan; char symname[KSYM_NAME_LEN]; wchan = get_wchan(task); if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS) && !lookup_symbol_name(wchan, symname)) seq_printf(m, "%s", symname); else seq_putc(m, '0'); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman2834.15%19.09%
alexey dobriyanalexey dobriyan2226.83%218.18%
ingo molnaringo molnar1113.41%19.09%
jake edgejake edge67.32%19.09%
joe perchesjoe perches44.88%19.09%
rick lindsleyrick lindsley44.88%19.09%
paul jacksonpaul jackson33.66%19.09%
robin humblerobin humble22.44%19.09%
robert loverobert love11.22%19.09%
jann hornjann horn11.22%19.09%
Total82100.00%11100.00%

#endif /* CONFIG_KALLSYMS */
static int lock_trace(struct task_struct *task) { int err = mutex_lock_killable(&task->signal->cred_guard_mutex); if (err) return err; if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { mutex_unlock(&task->signal->cred_guard_mutex); return -EPERM; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
al viroal viro5998.33%150.00%
jann hornjann horn11.67%150.00%
Total60100.00%2100.00%


static void unlock_trace(struct task_struct *task) { mutex_unlock(&task->signal->cred_guard_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
al viroal viro21100.00%1100.00%
Total21100.00%1100.00%

#ifdef CONFIG_STACKTRACE #define MAX_STACK_TRACE_DEPTH 64
static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { struct stack_trace trace; unsigned long *entries; int err; int i; entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); if (!entries) return -ENOMEM; trace.nr_entries = 0; trace.max_entries = MAX_STACK_TRACE_DEPTH; trace.entries = entries; trace.skip = 0; err = lock_trace(task); if (!err) { save_stack_trace_tsk(task, &trace); for (i = 0; i < trace.nr_entries; i++) { seq_printf(m, "[<%pK>] %pB\n", (void *)entries[i], (void *)entries[i]); } unlock_trace(task); } kfree(entries); return err; }

Contributors

PersonTokensPropCommitsCommitProp
ken chenken chen14285.54%133.33%
al viroal viro2313.86%133.33%
josh poimboeufjosh poimboeuf10.60%133.33%
Total166100.00%3100.00%

#endif #ifdef CONFIG_SCHED_INFO /* * Provides /proc/PID/schedstat */
static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { if (unlikely(!sched_info_on())) seq_printf(m, "0 0 0\n"); else seq_printf(m, "%llu %llu %lu\n", (unsigned long long)task->se.sum_exec_runtime, (unsigned long long)task->sched_info.run_delay, task->sched_info.pcount); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman2125.93%111.11%
alexey dobriyanalexey dobriyan1720.99%111.11%
naveen n. raonaveen n. rao1720.99%111.11%
ingo molnaringo molnar1113.58%222.22%
andrew mortonandrew morton911.11%111.11%
joe perchesjoe perches33.70%111.11%
ken chenken chen22.47%111.11%
balbir singhbalbir singh11.23%111.11%
Total81100.00%9100.00%

#endif #ifdef CONFIG_LATENCYTOP
static int lstats_show_proc(struct seq_file *m, void *v) { int i; struct inode *inode = m->private; struct task_struct *task = get_proc_task(inode); if (!task) return -ESRCH; seq_puts(m, "Latency Top version : v0.1\n"); for (i = 0; i < 32; i++) { struct latency_record *lr = &task->latency_record[i]; if (lr->backtrace[0]) { int q; seq_printf(m, "%i %li %li", lr->count, lr->time, lr->max); for (q = 0; q < LT_BACKTRACEDEPTH; q++) { unsigned long bt = lr->backtrace[q]; if (!bt) break; if (bt == ULONG_MAX) break; seq_printf(m, " %ps", (void *)bt); } seq_putc(m, '\n'); } } put_task_struct(task); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
arjan van de venarjan van de ven12267.40%125.00%
joe perchesjoe perches3117.13%125.00%
hiroshi shimamotohiroshi shimamoto2614.36%125.00%
alexey dobriyanalexey dobriyan21.10%125.00%
Total181100.00%4100.00%


static int lstats_open(struct inode *inode, struct file *file) { return single_open(file, lstats_show_proc, inode); }

Contributors

PersonTokensPropCommitsCommitProp
arjan van de venarjan van de ven2180.77%133.33%
hiroshi shimamotohiroshi shimamoto519.23%266.67%
Total26100.00%3100.00%


static ssize_t lstats_write(struct file *file, const char __user *buf, size_t count, loff_t *offs) { struct task_struct *task = get_proc_task(file_inode(file)); if (!task) return -ESRCH; clear_all_latency_tracing(task); put_task_struct(task); return count; }

Contributors

PersonTokensPropCommitsCommitProp
arjan van de venarjan van de ven3762.71%133.33%
hiroshi shimamotohiroshi shimamoto1932.20%133.33%
al viroal viro35.08%133.33%
Total59100.00%3100.00%

static const struct file_operations proc_lstats_operations = { .open = lstats_open, .read = seq_read, .write = lstats_write, .llseek = seq_lseek, .release = single_release, }; #endif
static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { unsigned long totalpages = totalram_pages + total_swap_pages; unsigned long points = 0; points = oom_badness(task, NULL, NULL, totalpages) * 1000 / totalpages; seq_printf(m, "%lu\n", points); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman2130.43%110.00%
alexey dobriyanalexey dobriyan1724.64%110.00%
david rientjesdavid rientjes1420.29%220.00%
eric pariseric paris45.80%110.00%
kosaki motohirokosaki motohiro45.80%110.00%
joe perchesjoe perches34.35%110.00%
michael lemaymichael lemay34.35%110.00%
oleg nesterovoleg nesterov22.90%110.00%
andrew mortonandrew morton11.45%110.00%
Total69100.00%10100.00%

struct limit_names { const char *name; const char *unit; }; static const struct limit_names lnames[RLIM_NLIMITS] = { [RLIMIT_CPU] = {"Max cpu time", "seconds"}, [RLIMIT_FSIZE] = {"Max file size", "bytes"}, [RLIMIT_DATA] = {"Max data size", "bytes"}, [RLIMIT_STACK] = {"Max stack size", "bytes"}, [RLIMIT_CORE] = {"Max core file size", "bytes"}, [RLIMIT_RSS] = {"Max resident set", "bytes"}, [RLIMIT_NPROC] = {"Max processes", "processes"}, [RLIMIT_NOFILE] = {"Max open files", "files"}, [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"}, [RLIMIT_AS] = {"Max address space", "bytes"}, [RLIMIT_LOCKS] = {"Max file locks", "locks"}, [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"}, [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"}, [RLIMIT_NICE] = {"Max nice priority", NULL}, [RLIMIT_RTPRIO] = {"Max realtime priority", NULL}, [RLIMIT_RTTIME] = {"Max realtime timeout", "us"}, }; /* Display limits for a process */
static int proc_pid_limits(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { unsigned int i; unsigned long flags; struct rlimit rlim[RLIM_NLIMITS]; if (!lock_task_sighand(task, &flags)) return 0; memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); unlock_task_sighand(task, &flags); /* * print the file header */ seq_printf(m, "%-25s %-20s %-20s %-10s\n", "Limit", "Soft Limit", "Hard Limit", "Units"); for (i = 0; i < RLIM_NLIMITS; i++) { if (rlim[i].rlim_cur == RLIM_INFINITY) seq_printf(m, "%-25s %-20s ", lnames[i].name, "unlimited"); else seq_printf(m, "%-25s %-20lu ", lnames[i].name, rlim[i].rlim_cur); if (rlim[i].rlim_max == RLIM_INFINITY) seq_printf(m, "%-20s ", "unlimited"); else seq_printf(m, "%-20lu ", rlim[i].rlim_max); if (lnames[i].unit) seq_printf(m, "%-10s\n", lnames[i].unit); else seq_putc(m, '\n'); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
neil hormanneil horman20086.58%150.00%
alexey dobriyanalexey dobriyan3113.42%150.00%
Total231100.00%2100.00%

#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { long nr; unsigned long args[6], sp, pc; int res; res = lock_trace(task); if (res) return res; if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) seq_puts(m, "running\n"); else if (nr < 0) seq_printf(m, "%ld 0x%lx 0x%lx\n", nr, sp, pc); else seq_printf(m, "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", nr, args[0], args[1], args[2], args[3], args[4], args[5], sp, pc); unlock_trace(task); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
roland mcgrathroland mcgrath10667.95%125.00%
al viroal viro2415.38%125.00%
alexey dobriyanalexey dobriyan2113.46%125.00%
joe perchesjoe perches53.21%125.00%
Total156100.00%4100.00%

#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ /************************************************************************/ /* Here the fs part begins */ /************************************************************************/ /* permission checks */
static int proc_fd_access_allowed(struct inode *inode) { struct task_struct *task; int allowed = 0; /* Allow access to a task's file descriptors if it is us or we * may use ptrace attach to the process and find out that * information. */ task = get_proc_task(inode); if (task) { allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); put_task_struct(task); } return allowed; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman2548.08%218.18%
al viroal viro1426.92%327.27%
pre-gitpre-git1019.23%436.36%
stephen d. smalleystephen d. smalley23.85%19.09%
jann hornjann horn11.92%19.09%
Total52100.00%11100.00%


int proc_setattr(struct dentry *dentry, struct iattr *attr) { int error; struct inode *inode = d_inode(dentry); if (attr->ia_valid & ATTR_MODE) return -EPERM; error = setattr_prepare(dentry, attr); if (error) return error; setattr_copy(inode, attr); mark_inode_dirty(inode); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman3650.70%112.50%
christoph hellwigchristoph hellwig1926.76%112.50%
al viroal viro912.68%225.00%
david howellsdavid howells34.23%112.50%
jan karajan kara22.82%112.50%
dipankar sarmadipankar sarma11.41%112.50%
pre-gitpre-git11.41%112.50%
Total71100.00%8100.00%

/* * May current process learn task's sched/cmdline info (for hide_pid_min=1) * or euid/egid (for hide_pid_min=2)? */
static bool has_pid_permissions(struct pid_namespace *pid, struct task_struct *task, int hide_pid_min) { if (pid->hide_pid < hide_pid_min) return true; if (in_group_p(pid->pid_gid))