/*-
- * Copyright (c) 1999-2009, Apple Inc.
+ * Copyright (c) 1999-2010, Apple Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <kern/host.h>
#include <kern/kalloc.h>
#include <kern/zalloc.h>
-#include <kern/lock.h>
-#include <kern/wait_queue.h>
#include <kern/sched_prim.h>
#if CONFIG_MACF
auditon(proc_t p, struct auditon_args *uap, __unused int32_t *retval)
{
kauth_cred_t scred;
- int error;
+ int error = 0;
union auditon_udata udata;
proc_t tp = PROC_NULL;
struct auditinfo_addr aia;
case A_GETPINFO_ADDR:
case A_SENDTRIGGER:
case A_GETSINFO_ADDR:
+ case A_GETSFLAGS:
+ case A_SETSFLAGS:
error = copyin(uap->data, (void *)&udata, uap->length);
if (error)
return (error);
break;
}
+ /* Check appropriate privilege. */
+ switch (uap->cmd) {
/*
* A_GETSINFO doesn't require priviledge but only superuser
* gets to see the audit masks.
*/
- error = suser(kauth_cred_get(), &p->p_acflag);
- if (A_GETSINFO_ADDR == uap->cmd) {
+ case A_GETSINFO_ADDR:
if ((sizeof(udata.au_kau_info) != uap->length) ||
(audit_session_lookup(udata.au_kau_info.ai_asid,
&udata.au_kau_info) != 0))
- return (EINVAL);
- if (error) {
+ error = EINVAL;
+ else if (!kauth_cred_issuser(kauth_cred_get())) {
udata.au_kau_info.ai_mask.am_success = ~0;
udata.au_kau_info.ai_mask.am_failure = ~0;
}
- } else
- if (error)
- return (error);
+ break;
+ case A_GETSFLAGS:
+ case A_SETSFLAGS:
+ /* Getting one's own audit session flags requires no
+ * privilege. Setting the flags is subject to access
+ * control implemented in audit_session_setaia().
+ */
+ break;
+ default:
+ error = suser(kauth_cred_get(), &p->p_acflag);
+ break;
+ }
+ if (error)
+ return (error);
/*
* XXX Need to implement these commands by accessing the global
* values associated with the commands.
*/
- mtx_lock(&audit_mtx);
switch (uap->cmd) {
case A_OLDGETPOLICY:
case A_GETPOLICY:
if (sizeof(udata.au_policy64) == uap->length) {
+ mtx_lock(&audit_mtx);
if (!audit_fail_stop)
udata.au_policy64 |= AUDIT_CNT;
if (audit_panic_on_write_fail)
udata.au_policy64 |= AUDIT_ARGV;
if (audit_arge)
udata.au_policy64 |= AUDIT_ARGE;
+ mtx_unlock(&audit_mtx);
break;
}
- if (sizeof(udata.au_policy) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_policy) != uap->length)
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
if (!audit_fail_stop)
udata.au_policy |= AUDIT_CNT;
if (audit_panic_on_write_fail)
udata.au_policy |= AUDIT_ARGV;
if (audit_arge)
udata.au_policy |= AUDIT_ARGE;
+ mtx_unlock(&audit_mtx);
break;
case A_OLDSETPOLICY:
case A_SETPOLICY:
if (sizeof(udata.au_policy64) == uap->length) {
if (udata.au_policy64 & ~(AUDIT_CNT|AUDIT_AHLT|
- AUDIT_ARGV|AUDIT_ARGE)) {
- mtx_unlock(&audit_mtx);
+ AUDIT_ARGV|AUDIT_ARGE))
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
0);
audit_panic_on_write_fail = (udata.au_policy64 &
AUDIT_AHLT);
audit_argv = (udata.au_policy64 & AUDIT_ARGV);
audit_arge = (udata.au_policy64 & AUDIT_ARGE);
-
+ mtx_unlock(&audit_mtx);
break;
}
if ((sizeof(udata.au_policy) != uap->length) ||
(udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
- AUDIT_ARGE))) {
- mtx_unlock(&audit_mtx);
+ AUDIT_ARGE)))
return (EINVAL);
- }
/*
* XXX - Need to wake up waiters if the policy relaxes?
*/
+ mtx_lock(&audit_mtx);
audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
audit_argv = (udata.au_policy & AUDIT_ARGV);
audit_arge = (udata.au_policy & AUDIT_ARGE);
+ mtx_unlock(&audit_mtx);
break;
case A_GETKMASK:
- if (sizeof(udata.au_mask) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_mask) != uap->length)
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
udata.au_mask = audit_nae_mask;
+ mtx_unlock(&audit_mtx);
break;
case A_SETKMASK:
- if (sizeof(udata.au_mask) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_mask) != uap->length)
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
audit_nae_mask = udata.au_mask;
AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask);
+ mtx_unlock(&audit_mtx);
break;
case A_OLDGETQCTRL:
case A_GETQCTRL:
if (sizeof(udata.au_qctrl64) == uap->length) {
+ mtx_lock(&audit_mtx);
udata.au_qctrl64.aq64_hiwater =
(u_int64_t)audit_qctrl.aq_hiwater;
udata.au_qctrl64.aq64_lowater =
(u_int64_t)audit_qctrl.aq_delay;
udata.au_qctrl64.aq64_minfree =
(int64_t)audit_qctrl.aq_minfree;
+ mtx_unlock(&audit_mtx);
break;
}
- if (sizeof(udata.au_qctrl) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_qctrl) != uap->length)
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
udata.au_qctrl = audit_qctrl;
+ mtx_unlock(&audit_mtx);
break;
case A_OLDSETQCTRL:
udata.au_qctrl64.aq64_hiwater) ||
(udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
(udata.au_qctrl64.aq64_minfree < 0) ||
- (udata.au_qctrl64.aq64_minfree > 100)) {
- mtx_unlock(&audit_mtx);
+ (udata.au_qctrl64.aq64_minfree > 100))
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
audit_qctrl.aq_hiwater =
(int)udata.au_qctrl64.aq64_hiwater;
audit_qctrl.aq_lowater =
audit_qctrl.aq_minfree =
(int)udata.au_qctrl64.aq64_minfree;
audit_qctrl.aq_delay = -1; /* Not used. */
-
- break;
+ mtx_unlock(&audit_mtx);
+ break;
}
if ((sizeof(udata.au_qctrl) != uap->length) ||
(udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
(udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
(udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
(udata.au_qctrl.aq_minfree < 0) ||
- (udata.au_qctrl.aq_minfree > 100)) {
- mtx_unlock(&audit_mtx);
+ (udata.au_qctrl.aq_minfree > 100))
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
audit_qctrl = udata.au_qctrl;
/* XXX The queue delay value isn't used with the kernel. */
audit_qctrl.aq_delay = -1;
+ mtx_unlock(&audit_mtx);
break;
case A_GETCWD:
- mtx_unlock(&audit_mtx);
return (ENOSYS);
- break;
case A_GETCAR:
- mtx_unlock(&audit_mtx);
return (ENOSYS);
- break;
case A_GETSTAT:
- mtx_unlock(&audit_mtx);
return (ENOSYS);
- break;
case A_SETSTAT:
- mtx_unlock(&audit_mtx);
return (ENOSYS);
- break;
case A_SETUMASK:
- mtx_unlock(&audit_mtx);
return (ENOSYS);
- break;
case A_SETSMASK:
- mtx_unlock(&audit_mtx);
return (ENOSYS);
- break;
case A_OLDGETCOND:
case A_GETCOND:
if (sizeof(udata.au_cond64) == uap->length) {
+ mtx_lock(&audit_mtx);
if (audit_enabled && !audit_suspended)
udata.au_cond64 = AUC_AUDITING;
else
udata.au_cond64 = AUC_NOAUDIT;
-
+ mtx_unlock(&audit_mtx);
break;
}
- if (sizeof(udata.au_cond) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_cond) != uap->length)
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
if (audit_enabled && !audit_suspended)
udata.au_cond = AUC_AUDITING;
else
udata.au_cond = AUC_NOAUDIT;
+ mtx_unlock(&audit_mtx);
break;
case A_OLDSETCOND:
case A_SETCOND:
if (sizeof(udata.au_cond64) == uap->length) {
+ mtx_lock(&audit_mtx);
if (udata.au_cond64 == AUC_NOAUDIT)
audit_suspended = 1;
if (udata.au_cond64 == AUC_AUDITING)
audit_suspended = 1;
mtx_unlock(&audit_mtx);
audit_shutdown();
- mtx_lock(&audit_mtx);
+ break;
}
+ mtx_unlock(&audit_mtx);
break;
}
if (sizeof(udata.au_cond) != uap->length) {
- mtx_unlock(&audit_mtx);
return (EINVAL);
}
+ mtx_lock(&audit_mtx);
if (udata.au_cond == AUC_NOAUDIT)
audit_suspended = 1;
if (udata.au_cond == AUC_AUDITING)
audit_suspended = 1;
mtx_unlock(&audit_mtx);
audit_shutdown();
- mtx_lock(&audit_mtx);
+ break;
}
+ mtx_unlock(&audit_mtx);
break;
case A_GETCLASS:
- if (sizeof(udata.au_evclass) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_evclass) != uap->length)
return (EINVAL);
- }
udata.au_evclass.ec_class = au_event_class(
udata.au_evclass.ec_number);
break;
case A_SETCLASS:
- if (sizeof(udata.au_evclass) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_evclass) != uap->length)
return (EINVAL);
- }
au_evclassmap_insert(udata.au_evclass.ec_number,
udata.au_evclass.ec_class);
break;
case A_GETPINFO:
if ((sizeof(udata.au_aupinfo) != uap->length) ||
- IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) {
- mtx_unlock(&audit_mtx);
+ IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
return (EINVAL);
- }
- if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
- mtx_unlock(&audit_mtx);
+ if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
return (ESRCH);
- }
- mtx_unlock(&audit_mtx);
scred = kauth_cred_proc_ref(tp);
if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) {
kauth_cred_unref(&scred);
kauth_cred_unref(&scred);
proc_rele(tp);
tp = PROC_NULL;
- mtx_lock(&audit_mtx);
break;
case A_SETPMASK:
if ((sizeof(udata.au_aupinfo) != uap->length) ||
- IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) {
- mtx_unlock(&audit_mtx);
+ IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
return (EINVAL);
- }
- if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
- mtx_unlock(&audit_mtx);
+ if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
return (ESRCH);
- }
scred = kauth_cred_proc_ref(tp);
bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
kauth_cred_unref(&scred);
aia.ai_mask.am_failure =
udata.au_aupinfo.ap_mask.am_failure;
AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
- error = audit_session_setaia(tp, &aia, 0);
- mtx_unlock(&audit_mtx);
+ error = audit_session_setaia(tp, &aia);
proc_rele(tp);
tp = PROC_NULL;
if (error)
return (error);
- mtx_lock(&audit_mtx);
break;
case A_SETFSIZE:
if ((sizeof(udata.au_fstat) != uap->length) ||
((udata.au_fstat.af_filesz != 0) &&
- (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))) {
- mtx_unlock(&audit_mtx);
+ (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)))
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
audit_fstat.af_filesz = udata.au_fstat.af_filesz;
+ mtx_unlock(&audit_mtx);
break;
case A_GETFSIZE:
- if (sizeof(udata.au_fstat) != uap->length) {
- mtx_unlock(&audit_mtx);
+ if (sizeof(udata.au_fstat) != uap->length)
return (EINVAL);
- }
+ mtx_lock(&audit_mtx);
udata.au_fstat.af_filesz = audit_fstat.af_filesz;
udata.au_fstat.af_currsz = audit_fstat.af_currsz;
+ mtx_unlock(&audit_mtx);
break;
case A_GETPINFO_ADDR:
if ((sizeof(udata.au_aupinfo_addr) != uap->length) ||
- IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid)) {
- mtx_unlock(&audit_mtx);
+ IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid))
return (EINVAL);
- }
- if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) {
- mtx_unlock(&audit_mtx);
+ if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
return (ESRCH);
- }
WARN_IF_AINFO_ADDR_CHANGED(uap->length,
sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)",
"auditpinfo_addr_t");
break;
case A_GETKAUDIT:
- mtx_unlock(&audit_mtx);
if (sizeof(udata.au_kau_info) != uap->length)
return (EINVAL);
audit_get_kinfo(&udata.au_kau_info);
- mtx_lock(&audit_mtx);
break;
case A_SETKAUDIT:
if ((sizeof(udata.au_kau_info) != uap->length) ||
(udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
- udata.au_kau_info.ai_termid.at_type != AU_IPv6)) {
- mtx_unlock(&audit_mtx);
+ udata.au_kau_info.ai_termid.at_type != AU_IPv6))
return (EINVAL);
- }
- mtx_unlock(&audit_mtx);
audit_set_kinfo(&udata.au_kau_info);
- mtx_lock(&audit_mtx);
break;
case A_SENDTRIGGER:
if ((sizeof(udata.au_trigger) != uap->length) ||
(udata.au_trigger < AUDIT_TRIGGER_MIN) ||
- (udata.au_trigger > AUDIT_TRIGGER_MAX)) {
- mtx_unlock(&audit_mtx);
+ (udata.au_trigger > AUDIT_TRIGGER_MAX))
return (EINVAL);
- }
- mtx_unlock(&audit_mtx);
return (audit_send_trigger(udata.au_trigger));
case A_GETSINFO_ADDR:
/* Handled above before switch(). */
break;
+ case A_GETSFLAGS:
+ if (sizeof(udata.au_flags) != uap->length)
+ return (EINVAL);
+ bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags),
+ &udata.au_flags, sizeof(udata.au_flags));
+ break;
+
+ case A_SETSFLAGS:
+ if (sizeof(udata.au_flags) != uap->length)
+ return (EINVAL);
+ bcopy(kauth_cred_get()->cr_audit.as_aia_p, &aia, sizeof(aia));
+ aia.ai_flags = udata.au_flags;
+ error = audit_session_setaia(p, &aia);
+ if (error)
+ return (error);
+ break;
+
default:
- mtx_unlock(&audit_mtx);
return (EINVAL);
}
case A_GETPINFO_ADDR:
case A_GETKAUDIT:
case A_GETSINFO_ADDR:
+ case A_GETSFLAGS:
error = copyout((void *)&udata, uap->data, uap->length);
- if (error) {
- mtx_unlock(&audit_mtx);
+ if (error)
return (ENOSYS);
- }
break;
}
- mtx_unlock(&audit_mtx);
return (0);
}
bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t));
kauth_cred_unref(&scred);
aia.ai_auid = id;
- error = audit_session_setaia(p, &aia, 0);
-
- return (error);
-}
-
-static int
-getaudit_internal(proc_t p, user_addr_t user_addr)
-{
- struct auditinfo ai;
- kauth_cred_t scred;
-
- scred = kauth_cred_proc_ref(p);
- if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) {
- kauth_cred_unref(&scred);
- return (ERANGE);
- }
-
- bzero(&ai, sizeof(ai));
- ai.ai_auid = scred->cr_audit.as_aia_p->ai_auid;
- ai.ai_asid = scred->cr_audit.as_aia_p->ai_asid;
-
- /*
- * Only superuser gets to see the real mask.
- */
- if (suser(scred, &p->p_acflag)) {
- ai.ai_mask.am_success = ~0;
- ai.ai_mask.am_failure = ~0;
- } else {
- ai.ai_mask.am_success = scred->cr_audit.as_mask.am_success;
- ai.ai_mask.am_failure = scred->cr_audit.as_mask.am_failure;
- }
- ai.ai_termid.machine = scred->cr_audit.as_aia_p->ai_termid.at_addr[0];
- ai.ai_termid.port = scred->cr_audit.as_aia_p->ai_termid.at_port;
- kauth_cred_unref(&scred);
-
- return (copyout(&ai, user_addr, sizeof (ai)));
-}
-
-/*
- * System calls to get and set process audit information.
- */
-/* ARGSUSED */
-int
-getaudit(proc_t p, struct getaudit_args *uap, __unused int32_t *retval)
-{
- int error;
-
-#if CONFIG_MACF
- error = mac_proc_check_getaudit(p);
- if (error)
- return (error);
-#endif
- return (getaudit_internal(p, uap->auditinfo));
-}
-
-/* ARGSUSED */
-int
-setaudit(proc_t p, struct setaudit_args *uap, __unused int32_t *retval)
-{
- struct auditinfo ai;
- struct auditinfo_addr newaia;
- kauth_cred_t scred;
- int error;
-
- error = copyin(uap->auditinfo, &ai, sizeof(ai));
- if (error)
- return (error);
- AUDIT_ARG(auditinfo, &ai);
-
- if (ai.ai_asid != AU_ASSIGN_ASID &&
- (uint32_t)ai.ai_asid > ASSIGNED_ASID_MAX)
- return (EINVAL);
-
-#if CONFIG_MACF
- {
- struct auditinfo_addr aia = {
- .ai_auid = ai.ai_auid,
- .ai_mask = ai.ai_mask,
- .ai_termid = {
- .at_port = ai.ai_termid.port,
- .at_type = AU_IPv4,
- .at_addr = { ai.ai_termid.machine, 0, 0, 0 } },
- .ai_asid = ai.ai_asid,
- .ai_flags = 0 };
- error = mac_proc_check_setaudit(p, &aia);
- }
- if (error)
- return (error);
-#endif
-
- bzero(&newaia, sizeof(newaia));
- scred = kauth_cred_proc_ref(p);
- error = suser(scred, &p->p_acflag);
- if (error) {
- kauth_cred_unref(&scred);
- return (error);
- }
- newaia.ai_flags = scred->cr_audit.as_aia_p->ai_flags;
- kauth_cred_unref(&scred);
-
- WARN_IF_BAD_ASID(ai.ai_asid, "setaudit(2)");
-
- newaia.ai_auid = ai.ai_auid;
- bcopy(&ai.ai_mask, &newaia.ai_mask, sizeof(au_mask_t));
- AUDIT_CHECK_IF_KEVENTS_MASK(ai.ai_mask);
- newaia.ai_asid = ai.ai_asid;
- if (ai.ai_asid == AU_DEFAUDITSID)
- newaia.ai_asid = AU_ASSIGN_ASID;
- else
- newaia.ai_asid = ai.ai_asid;
- newaia.ai_termid.at_addr[0] = ai.ai_termid.machine;
- newaia.ai_termid.at_port = ai.ai_termid.port;
- newaia.ai_termid.at_type = AU_IPv4;
-
- error = audit_session_setaia(p, &newaia, 0);
- if (error)
- return (error);
+ error = audit_session_setaia(p, &aia);
- /*
- * If asked to assign an ASID then let the user know what the ASID is
- * by copying the auditinfo struct back out.
- */
- if (newaia.ai_asid == AU_ASSIGN_ASID)
- error = getaudit_internal(p, uap->auditinfo);
-
return (error);
}
getaudit_addr(proc_t p, struct getaudit_addr_args *uap,
__unused int32_t *retval)
{
+#if CONFIG_MACF
+ int error = mac_proc_check_getaudit(p);
+ if (error)
+ return (error);
+#endif /* CONFIG_MACF */
WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
"getaudit_addr(2)", "auditinfo_addr_t");
if (aia.ai_asid == AU_DEFAUDITSID)
aia.ai_asid = AU_ASSIGN_ASID;
- error = audit_session_setaia(p, &aia, 0);
+ error = audit_session_setaia(p, &aia);
if (error)
return (error);
if (uap->path == USER_ADDR_NULL)
return (EINVAL);
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
+ NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | LOCKLEAF | AUDITVNPATH1,
(IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 :
UIO_USERSPACE32), uap->path, vfs_context_current());
error = vn_open(&nd, AUDIT_OPEN_FLAGS, 0);
return (ENOSYS);
}
-int
-getaudit(proc_t p, struct getaudit_args *uap, int32_t *retval)
-{
-#pragma unused(p, uap, retval)
-
- return (ENOSYS);
-}
-
-int
-setaudit(proc_t p, struct setaudit_args *uap, int32_t *retval)
-{
-#pragma unused(p, uap, retval)
-
- return (ENOSYS);
-}
-
int
getaudit_addr(proc_t p, struct getaudit_addr_args *uap, int32_t *retval)
{