X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/89b3af67bb32e691275bf6fa803d1834b2284115..bb59bff194111743b33cc36712410b5656329d3c:/bsd/kern/kern_acct.c diff --git a/bsd/kern/kern_acct.c b/bsd/kern/kern_acct.c index 7488f70db..aec90c9e0 100644 --- a/bsd/kern/kern_acct.c +++ b/bsd/kern/kern_acct.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2010 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -70,6 +70,12 @@ * Purged old history * New version based on 4.4 */ +/* + * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ #include @@ -88,6 +94,9 @@ #include #include #include +#if CONFIG_MACF +#include +#endif /* * The routines implemented in this file are described in: @@ -105,9 +114,9 @@ * The former's operation is described in Leffler, et al., and the latter * was provided by UCB with the 4.4BSD-Lite release */ -comp_t encode_comp_t(u_long, u_long); +comp_t encode_comp_t(uint32_t, uint32_t); void acctwatch(void *); -void acctwatch_funnel(void *); +void acct_init(void); /* * Accounting vnode pointer, and suspended accounting vnode pointer. States @@ -130,22 +139,36 @@ int acctsuspend = 2; /* stop accounting when < 2% free space left */ int acctresume = 4; /* resume when free space risen to > 4% */ int acctchkfreq = 15; /* frequency (in seconds) to check space */ + +static lck_grp_t *acct_subsys_lck_grp; +static lck_mtx_t *acct_subsys_mutex; + +#define ACCT_SUBSYS_LOCK() lck_mtx_lock(acct_subsys_mutex) +#define ACCT_SUBSYS_UNLOCK() lck_mtx_unlock(acct_subsys_mutex) + +void +acct_init(void) +{ + acct_subsys_lck_grp = lck_grp_alloc_init("acct", NULL); + acct_subsys_mutex = lck_mtx_alloc_init(acct_subsys_lck_grp, NULL); +} + + /* * Accounting system call. Written based on the specification and * previous implementation done by Mark Tinguely. */ int -acct(struct proc *p, struct acct_args *uap, __unused int *retval) +acct(proc_t p, struct acct_args *uap, __unused int *retval) { struct nameidata nd; int error; - struct vfs_context context; + struct vfs_context *ctx; - context.vc_proc = p; - context.vc_ucred = kauth_cred_get(); + ctx = vfs_context_current(); /* Make sure that the caller is root. */ - if ((error = suser(kauth_cred_get(), &p->p_acflag))) + if ((error = suser(vfs_context_ucred(ctx), &p->p_acflag))) return (error); /* @@ -153,36 +176,56 @@ acct(struct proc *p, struct acct_args *uap, __unused int *retval) * writing and make sure it's a 'normal'. */ if (uap->path != USER_ADDR_NULL) { - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, &context); + NDINIT(&nd, LOOKUP, OP_OPEN, NOFOLLOW, UIO_USERSPACE, uap->path, ctx); if ((error = vn_open(&nd, FWRITE, 0))) return (error); +#if CONFIG_MACF + error = mac_system_check_acct(vfs_context_ucred(ctx), nd.ni_vp); + if (error) { + vnode_put(nd.ni_vp); + vn_close(nd.ni_vp, FWRITE, ctx); + return (error); + } +#endif vnode_put(nd.ni_vp); if (nd.ni_vp->v_type != VREG) { - vn_close(nd.ni_vp, FWRITE, kauth_cred_get(), p); + vn_close(nd.ni_vp, FWRITE, ctx); return (EACCES); } } +#if CONFIG_MACF + else { + error = mac_system_check_acct(vfs_context_ucred(ctx), NULL); + if (error) + return (error); + } +#endif /* * If accounting was previously enabled, kill the old space-watcher, * close the file, and (if no new file was specified, leave). */ + ACCT_SUBSYS_LOCK(); if (acctp != NULLVP || suspend_acctp != NULLVP) { - untimeout(acctwatch_funnel, NULL); - error = vn_close((acctp != NULLVP ? acctp : suspend_acctp), FWRITE, - kauth_cred_get(), p); + untimeout(acctwatch, NULL); + error = vn_close((acctp != NULLVP ? acctp : suspend_acctp), + FWRITE, vfs_context_current()); acctp = suspend_acctp = NULLVP; } - if (uap->path == USER_ADDR_NULL) + if (uap->path == USER_ADDR_NULL) { + ACCT_SUBSYS_UNLOCK(); return (error); + } /* * Save the new accounting file vnode, and schedule the new * free space watcher. */ acctp = nd.ni_vp; + ACCT_SUBSYS_UNLOCK(); + acctwatch(NULL); return (error); } @@ -194,21 +237,25 @@ acct(struct proc *p, struct acct_args *uap, __unused int *retval) * "acct.h" header file.) */ int -acct_process(p) - struct proc *p; +acct_process(proc_t p) { struct acct an_acct; - struct rusage *r; + struct rusage rup, *r; struct timeval ut, st, tmp; int t; int error; struct vnode *vp; kauth_cred_t safecred; + struct session * sessp; + struct tty *tp; /* If accounting isn't enabled, don't bother */ + ACCT_SUBSYS_LOCK(); vp = acctp; - if (vp == NULLVP) + if (vp == NULLVP) { + ACCT_SUBSYS_UNLOCK(); return (0); + } /* * Get process accounting information. @@ -223,13 +270,16 @@ acct_process(p) an_acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); /* (3) The elapsed time the commmand ran (and its starting time) */ - an_acct.ac_btime = p->p_stats->p_start.tv_sec; + an_acct.ac_btime = p->p_start.tv_sec; microtime(&tmp); - timevalsub(&tmp, &p->p_stats->p_start); + timevalsub(&tmp, &p->p_start); an_acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec); /* (4) The average amount of memory used */ - r = &p->p_stats->p_ru; + proc_lock(p); + rup = p->p_stats->p_ru; + proc_unlock(p); + r = &rup; tmp = ut; timevaladd(&tmp, &st); t = tmp.tv_sec * hz + tmp.tv_usec / tick; @@ -242,29 +292,40 @@ acct_process(p) an_acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0); /* (6) The UID and GID of the process */ - an_acct.ac_uid = p->p_ucred->cr_ruid; - an_acct.ac_gid = p->p_ucred->cr_rgid; + safecred = kauth_cred_proc_ref(p); + + an_acct.ac_uid = kauth_cred_getruid(safecred); + an_acct.ac_gid = kauth_cred_getrgid(safecred); /* (7) The terminal from which the process was started */ - if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) - an_acct.ac_tty = p->p_pgrp->pg_session->s_ttyp->t_dev; - else + + sessp = proc_session(p); + if ((p->p_flag & P_CONTROLT) && (sessp != SESSION_NULL) && ((tp = SESSION_TP(sessp)) != TTY_NULL)) { + tty_lock(tp); + an_acct.ac_tty = tp->t_dev; + tty_unlock(tp); + }else an_acct.ac_tty = NODEV; + if (sessp != SESSION_NULL) + session_rele(sessp); + /* (8) The boolean flags that tell how the process terminated, etc. */ an_acct.ac_flag = p->p_acflag; - safecred = kauth_cred_proc_ref(p); /* * Now, just write the accounting information to the file. */ if ((error = vnode_getwithref(vp)) == 0) { error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&an_acct, sizeof (an_acct), - (off_t)0, UIO_SYSSPACE32, IO_APPEND|IO_UNIT, safecred, + (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, safecred, (int *)0, p); vnode_put(vp); } + kauth_cred_unref(&safecred); + ACCT_SUBSYS_UNLOCK(); + return (error); } @@ -279,8 +340,7 @@ acct_process(p) #define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */ comp_t -encode_comp_t(s, us) - u_long s, us; +encode_comp_t(uint32_t s, uint32_t us) { int exp, rnd; @@ -307,16 +367,6 @@ encode_comp_t(s, us) return (exp); } -void -acctwatch_funnel(a) - void *a; -{ - thread_funnel_set(kernel_flock, TRUE); - acctwatch(a); - thread_funnel_set(kernel_flock, FALSE); -} - - /* * Periodically check the file system to see if accounting * should be turned on or off. Beware the case where the vnode @@ -327,15 +377,14 @@ acctwatch_funnel(a) void acctwatch(__unused void *a) { - struct vfs_context context; + vfs_context_t ctx = vfs_context_current(); struct vfs_attr va; VFSATTR_INIT(&va); VFSATTR_WANTED(&va, f_blocks); VFSATTR_WANTED(&va, f_bavail); - context.vc_proc = current_proc(); - context.vc_ucred = kauth_cred_get(); + ACCT_SUBSYS_LOCK(); if (suspend_acctp != NULLVP) { /* * Resuming accounting when accounting is suspended, and the @@ -343,11 +392,12 @@ acctwatch(__unused void *a) * below a low watermark */ if (suspend_acctp->v_type == VBAD) { - (void) vn_close(suspend_acctp, FWRITE, NOCRED, NULL); + (void) vn_close(suspend_acctp, FWRITE, vfs_context_kernel()); suspend_acctp = NULLVP; + ACCT_SUBSYS_UNLOCK(); return; } - (void)vfs_getattr(suspend_acctp->v_mount, &va, &context); + (void)vfs_getattr(suspend_acctp->v_mount, &va, ctx); if (va.f_bavail > acctresume * va.f_blocks / 100) { acctp = suspend_acctp; suspend_acctp = NULLVP; @@ -360,19 +410,22 @@ acctwatch(__unused void *a) * goes over a high watermark */ if (acctp->v_type == VBAD) { - (void) vn_close(acctp, FWRITE, NOCRED, NULL); + (void) vn_close(acctp, FWRITE, vfs_context_kernel()); acctp = NULLVP; + ACCT_SUBSYS_UNLOCK(); return; } - (void)vfs_getattr(acctp->v_mount, &va, &context); + (void)vfs_getattr(acctp->v_mount, &va, ctx); if (va.f_bavail <= acctsuspend * va.f_blocks / 100) { suspend_acctp = acctp; acctp = NULLVP; log(LOG_NOTICE, "Accounting suspended\n"); } } else { + ACCT_SUBSYS_UNLOCK(); return; - } - - timeout(acctwatch_funnel, NULL, acctchkfreq * hz); + } + ACCT_SUBSYS_UNLOCK(); + + timeout(acctwatch, NULL, acctchkfreq * hz); }