]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_acct.c
xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / kern / kern_acct.c
index 7488f70dbe9043c1a4169c117809a841d29afb37..aec90c9e0d3b876f785a08bdc2c2de958dc2b63d 100644 (file)
@@ -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@
  * 
  *     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 <sys/param.h>
@@ -88,6 +94,9 @@
 #include <sys/tty.h>
 #include <sys/sysproto.h>
 #include <machine/spl.h>
+#if CONFIG_MACF
+#include <security/mac_framework.h>
+#endif
 
 /*
  * The routines implemented in this file are described in:
  * 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);
 }