#include <sys/types.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
#include <sys/file.h>
#include <sys/user.h>
#include <sys/stropts.h>
#include <sys/systm.h>
#include <sys/pathname.h>
#include <sys/syscall.h>
#include <sys/fcntl.h>
#include <sys/ipc_impl.h>
#include <sys/msg_impl.h>
#include <sys/sem_impl.h>
#include <sys/shm_impl.h>
#include <sys/kmem.h>
#include <sys/socket.h>
#include <sys/cmn_err.h>
#include <sys/debug.h>
#include <sys/thread.h>
#include <netinet/in.h>
#include <c2/audit.h>
#include <c2/audit_kernel.h>
#include <c2/audit_kevents.h>
#include <c2/audit_record.h>
#include <sys/strsubr.h>
#include <sys/tihdr.h>
#include <sys/tiuser.h>
#include <sys/timod.h>
#include <sys/model.h>
#include <sys/disp.h>
#include <sys/devpolicy.h>
#include <sys/crypto/ioctladmin.h>
#include <sys/cred_impl.h>
#include <net/pfpolicy.h>
static void add_return_token(caddr_t *, unsigned int scid, int err, int rval);
static void audit_pathbuild(struct pathname *pnp);
int
audit_savepath(
struct pathname *pnp,
struct vnode *vp,
struct vnode *pvp,
int flag,
cred_t *cr)
{
t_audit_data_t *tad;
au_kcontext_t *kctx = GET_KCTX_PZ;
tad = U2A(u);
if (tad->tad_flag != 0 && flag == ENOENT && pvp != NULL &&
(tad->tad_ctrl & TAD_PUBLIC_EV) &&
!(kctx->auk_policy & AUDIT_PUBLIC)) {
struct vattr attr;
attr.va_mask = AT_ALL;
if (VOP_GETATTR(pvp, &attr, 0, CRED(), NULL) == 0) {
if (object_is_public(&attr)) {
tad->tad_ctrl |= TAD_NOAUDIT;
}
}
}
if ((tad->tad_flag == 0 && !(tad->tad_ctrl & TAD_SAVPATH)) ||
((tad->tad_ctrl & TAD_PATHFND) &&
!(kctx->auk_policy & AUDIT_PATH)) ||
(tad->tad_ctrl & TAD_NOPATH)) {
return (0);
}
tad->tad_ctrl |= TAD_NOPATH;
audit_pathbuild(pnp);
if (tad->tad_flag) {
if (flag &&
(tad->tad_scid == SYS_open ||
tad->tad_scid == SYS_open64 ||
tad->tad_scid == SYS_openat ||
tad->tad_scid == SYS_openat64)) {
tad->tad_ctrl |= TAD_TRUE_CREATE;
}
au_uwrite(au_to_path(tad->tad_aupath));
if (vp) {
if (!flag && !(tad->tad_ctrl & TAD_NOATTRB))
audit_attributes(vp);
}
}
if ((tad->tad_ctrl & TAD_SAVPATH) == 0) {
if (tad->tad_aupath != NULL) {
au_pathrele(tad->tad_aupath);
tad->tad_aupath = NULL;
}
}
if (tad->tad_ctrl & TAD_MLD)
tad->tad_ctrl |= TAD_PATHFND;
tad->tad_ctrl &= ~TAD_NOPATH;
return (0);
}
static void
audit_pathbuild(struct pathname *pnp)
{
char *pp;
int len;
int newsect;
struct audit_path *pfxapp;
struct audit_path *newapp;
t_audit_data_t *tad;
p_audit_data_t *pad;
tad = U2A(u);
ASSERT(tad != NULL);
pad = P2A(curproc);
ASSERT(pad != NULL);
len = (pnp->pn_path - pnp->pn_buf) + 1;
ASSERT(len > 0);
mutex_enter(&pad->pad_lock);
if (tad->tad_aupath != NULL) {
pfxapp = tad->tad_aupath;
} else if ((tad->tad_ctrl & TAD_ATCALL) && pnp->pn_buf[0] != '/') {
ASSERT(tad->tad_atpath != NULL);
pfxapp = tad->tad_atpath;
} else if (tad->tad_ctrl & TAD_ABSPATH) {
pfxapp = pad->pad_root;
} else {
pfxapp = pad->pad_cwd;
}
au_pathhold(pfxapp);
mutex_exit(&pad->pad_lock);
newsect = tad->tad_ctrl & TAD_ATTPATH;
newapp = au_pathdup(pfxapp, newsect, len);
au_pathrele(pfxapp);
pp = newapp->audp_sect[newapp->audp_cnt] - len;
if (!newsect) {
*(pp - 1) = '/';
}
bcopy(pnp->pn_buf, pp, len);
pp[len - 1] = '\0';
audit_fixpath(newapp, len);
if (tad->tad_aupath)
au_pathrele(tad->tad_aupath);
tad->tad_aupath = newapp;
tad->tad_ctrl &= ~(TAD_ABSPATH | TAD_ATTPATH);
}
void
audit_anchorpath(struct pathname *pnp, int flag)
{
au_kcontext_t *kctx = GET_KCTX_PZ;
t_audit_data_t *tad;
tad = U2A(u);
if ((tad->tad_flag == 0 && !(tad->tad_ctrl & TAD_SAVPATH)) ||
((tad->tad_ctrl & TAD_PATHFND) &&
!(kctx->auk_policy & AUDIT_PATH)) ||
(tad->tad_ctrl & TAD_NOPATH)) {
return;
}
if (flag) {
tad->tad_ctrl |= TAD_ABSPATH;
if (tad->tad_aupath != NULL) {
au_pathrele(tad->tad_aupath);
tad->tad_aupath = NULL;
}
}
}
void
audit_symlink(struct pathname *pnp, struct pathname *sympath)
{
char *sp;
char *cp;
uint_t len_path;
t_audit_data_t *tad;
au_kcontext_t *kctx = GET_KCTX_PZ;
tad = U2A(u);
if ((tad->tad_flag == 0 &&
!(tad->tad_ctrl & TAD_SAVPATH)) ||
((tad->tad_ctrl & TAD_PATHFND) &&
!(kctx->auk_policy & AUDIT_PATH)) ||
(tad->tad_ctrl & TAD_NOPATH)) {
return;
}
if (sympath->pn_buf[0] == '/')
return;
sp = cp = pnp->pn_path;
while (*--cp != '/' && cp > pnp->pn_buf)
;
len_path = cp - pnp->pn_buf;
if (len_path) {
pnp->pn_path = pnp->pn_buf;
audit_pathbuild(pnp);
pnp->pn_path = sp;
}
}
int
object_is_public(struct vattr *attr)
{
au_kcontext_t *kctx = GET_KCTX_PZ;
if (!(kctx->auk_policy & AUDIT_PUBLIC) && (attr->va_uid == 0) &&
((attr->va_type == VLNK) ||
((attr->va_mode & (VREAD>>6)) != 0) &&
((attr->va_mode & (VWRITE>>6)) == 0))) {
return (1);
}
return (0);
}
void
audit_attributes(struct vnode *vp)
{
struct vattr attr;
struct t_audit_data *tad;
tad = U2A(u);
if (vp) {
attr.va_mask = AT_ALL;
if (VOP_GETATTR(vp, &attr, 0, CRED(), NULL) != 0)
return;
if (object_is_public(&attr) &&
(tad->tad_ctrl & TAD_PUBLIC_EV)) {
tad->tad_ctrl |= TAD_NOAUDIT;
} else {
au_uwrite(au_to_attr(&attr));
audit_sec_attributes(&(u_ad), vp);
}
}
}
void
audit_exit(int code, int what)
{
struct t_audit_data *tad;
tad = U2A(u);
if (tad->tad_scid == SYS_exit) {
if (tad->tad_flag && tad->tad_event == AUE_EXIT)
audit_finish(0, SYS_exit, 0, 0);
return;
}
if (tad->tad_flag) {
au_uwrite(au_to_text("event aborted"));
audit_finish(0, tad->tad_scid, 0, 0);
}
(void) audit_start(0, SYS_exit, AUC_UNSET, 0, 0);
audit_finish(0, SYS_exit, 0, 0);
}
void
audit_core_start(int sig)
{
au_event_t event;
au_state_t estate;
t_audit_data_t *tad;
au_kcontext_t *kctx;
tad = U2A(u);
ASSERT(tad != (t_audit_data_t *)0);
ASSERT(tad->tad_scid == 0);
ASSERT(tad->tad_event == 0);
ASSERT(tad->tad_evmod == 0);
ASSERT(tad->tad_ctrl == 0);
ASSERT(tad->tad_flag == 0);
ASSERT(tad->tad_aupath == NULL);
kctx = GET_KCTX_PZ;
event = AUE_CORE;
estate = kctx->auk_ets[event];
if ((tad->tad_flag = auditme(kctx, tad, estate)) == 0)
return;
tad->tad_ctrl = TAD_CORE;
tad->tad_scid = 0;
if (!((kctx->auk_auditstate == AUC_AUDITING ||
kctx->auk_auditstate == AUC_INIT_AUDIT) ||
kctx->auk_auditstate == AUC_NOSPACE)) {
tad->tad_flag = 0;
tad->tad_ctrl = 0;
return;
}
tad->tad_event = event;
tad->tad_evmod = 0;
ASSERT(tad->tad_ad == NULL);
au_write(&(u_ad), au_to_arg32(1, "signal", (uint32_t)sig));
}
void
audit_core_finish(int code)
{
int flag;
t_audit_data_t *tad;
au_kcontext_t *kctx;
tad = U2A(u);
ASSERT(tad != (t_audit_data_t *)0);
if ((flag = tad->tad_flag) == 0) {
tad->tad_event = 0;
tad->tad_evmod = 0;
tad->tad_ctrl = 0;
ASSERT(tad->tad_aupath == NULL);
return;
}
tad->tad_flag = 0;
kctx = GET_KCTX_PZ;
if (flag = audit_success(kctx, tad, 0, NULL)) {
cred_t *cr = CRED();
const auditinfo_addr_t *ainfo = crgetauinfo(cr);
ASSERT(ainfo != NULL);
AUDIT_SETSUBJ(&(u_ad), cr, ainfo, kctx);
add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0);
AS_INC(as_generated, 1, kctx);
AS_INC(as_kernel, 1, kctx);
}
au_close(kctx, &(u_ad), flag, tad->tad_event, tad->tad_evmod, NULL);
if (tad->tad_aupath != NULL) {
au_pathrele(tad->tad_aupath);
tad->tad_aupath = NULL;
}
tad->tad_event = 0;
tad->tad_evmod = 0;
tad->tad_ctrl = 0;
}
void
audit_strgetmsg(struct vnode *vp, struct strbuf *mctl, struct strbuf *mdata,
unsigned char *pri, int *flag, int fmode)
{
struct stdata *stp;
t_audit_data_t *tad = U2A(u);
ASSERT(tad != (t_audit_data_t *)0);
stp = vp->v_stream;
mutex_enter(&stp->sd_lock);
if (!tad->tad_flag) {
stp->sd_t_audit_data = NULL;
mutex_exit(&stp->sd_lock);
return;
}
stp->sd_t_audit_data = (caddr_t)curthread;
mutex_exit(&stp->sd_lock);
}
void
audit_strputmsg(struct vnode *vp, struct strbuf *mctl, struct strbuf *mdata,
unsigned char pri, int flag, int fmode)
{
struct stdata *stp;
t_audit_data_t *tad = U2A(u);
ASSERT(tad != (t_audit_data_t *)0);
stp = vp->v_stream;
mutex_enter(&stp->sd_lock);
if (!tad->tad_flag) {
stp->sd_t_audit_data = NULL;
mutex_exit(&stp->sd_lock);
return;
}
stp->sd_t_audit_data = (caddr_t)curthread;
mutex_exit(&stp->sd_lock);
}
void
audit_closef(struct file *fp)
{
f_audit_data_t *fad;
t_audit_data_t *tad;
int success;
au_state_t estate;
struct vnode *vp;
token_t *ad = NULL;
struct vattr attr;
au_emod_t evmod = 0;
const auditinfo_addr_t *ainfo;
cred_t *cr;
au_kcontext_t *kctx = GET_KCTX_PZ;
uint32_t auditing;
boolean_t audit_attr = B_FALSE;
fad = F2A(fp);
estate = kctx->auk_ets[AUE_CLOSE];
tad = U2A(u);
cr = CRED();
if (tad->tad_event == AUE_CLOSE) {
tad->tad_evmod |= (au_emod_t)fad->fad_flags;
return;
}
auditing = (tad->tad_audit == AUC_UNSET) ?
kctx->auk_auditstate : tad->tad_audit;
if (auditing & ~(AUC_AUDITING | AUC_INIT_AUDIT | AUC_NOSPACE))
return;
ainfo = crgetauinfo(cr);
if (ainfo == NULL)
return;
success = ainfo->ai_mask.as_success & estate;
if (success == 0)
return;
if ((vp = fp->f_vnode) != NULL) {
attr.va_mask = AT_ALL;
if (VOP_GETATTR(vp, &attr, 0, CRED(), NULL) == 0) {
if ((fp->f_flag & FWRITE) == 0 &&
object_is_public(&attr)) {
return;
}
audit_attr = B_TRUE;
}
}
evmod = (au_emod_t)fad->fad_flags;
if (fad->fad_aupath != NULL) {
au_write((caddr_t *)&(ad), au_to_path(fad->fad_aupath));
} else {
#ifdef _LP64
au_write((caddr_t *)&(ad), au_to_arg64(
1, "no path: fp", (uint64_t)fp));
#else
au_write((caddr_t *)&(ad), au_to_arg32(
1, "no path: fp", (uint32_t)fp));
#endif
}
if (audit_attr) {
au_write((caddr_t *)&(ad), au_to_attr(&attr));
audit_sec_attributes((caddr_t *)&(ad), vp);
}
AUDIT_SETSUBJ((caddr_t *)&(ad), cr, ainfo, kctx);
add_return_token((caddr_t *)&(ad), tad->tad_scid, 0, 0);
AS_INC(as_generated, 1, kctx);
AS_INC(as_kernel, 1, kctx);
au_close(kctx, (caddr_t *)&(ad), AU_OK | AU_DEFER,
AUE_CLOSE, evmod, NULL);
}
void
audit_setf(file_t *fp, int fd)
{
f_audit_data_t *fad;
t_audit_data_t *tad;
if (fp == NULL)
return;
tad = T2A(curthread);
fad = F2A(fp);
if (!(tad->tad_scid == SYS_open ||
tad->tad_scid == SYS_open64 ||
tad->tad_scid == SYS_openat ||
tad->tad_scid == SYS_openat64))
return;
if (tad->tad_aupath == 0)
return;
fad->fad_aupath = tad->tad_aupath;
tad->tad_aupath = NULL;
if (!(tad->tad_ctrl & TAD_TRUE_CREATE)) {
switch (tad->tad_event) {
case AUE_OPEN_RC:
tad->tad_event = AUE_OPEN_R;
tad->tad_ctrl |= TAD_PUBLIC_EV;
break;
case AUE_OPEN_RTC:
tad->tad_event = AUE_OPEN_RT;
break;
case AUE_OPEN_WC:
tad->tad_event = AUE_OPEN_W;
break;
case AUE_OPEN_WTC:
tad->tad_event = AUE_OPEN_WT;
break;
case AUE_OPEN_RWC:
tad->tad_event = AUE_OPEN_RW;
break;
case AUE_OPEN_RWTC:
tad->tad_event = AUE_OPEN_RWT;
break;
default:
break;
}
}
}
void
audit_ipc(int type, int id, void *vp)
{
if (ad_flag == 0)
return;
switch (type) {
case AT_IPC_MSG:
au_uwrite(au_to_ipc(AT_IPC_MSG, id));
au_uwrite(au_to_ipc_perm(&(((kmsqid_t *)vp)->msg_perm)));
break;
case AT_IPC_SEM:
au_uwrite(au_to_ipc(AT_IPC_SEM, id));
au_uwrite(au_to_ipc_perm(&(((ksemid_t *)vp)->sem_perm)));
break;
case AT_IPC_SHM:
au_uwrite(au_to_ipc(AT_IPC_SHM, id));
au_uwrite(au_to_ipc_perm(&(((kshmid_t *)vp)->shm_perm)));
break;
}
}
void
audit_ipcget(int type, void *vp)
{
if (ad_flag == 0)
return;
switch (type) {
case 0:
au_uwrite(au_to_ipc_perm((struct kipc_perm *)vp));
break;
case AT_IPC_MSG:
au_uwrite(au_to_ipc_perm(&(((kmsqid_t *)vp)->msg_perm)));
break;
case AT_IPC_SEM:
au_uwrite(au_to_ipc_perm(&(((ksemid_t *)vp)->sem_perm)));
break;
case AT_IPC_SHM:
au_uwrite(au_to_ipc_perm(&(((kshmid_t *)vp)->shm_perm)));
break;
}
}
void
audit_reboot(void)
{
int flag;
t_audit_data_t *tad;
au_kcontext_t *kctx = GET_KCTX_PZ;
tad = U2A(u);
if (tad->tad_flag == 0)
return;
if (flag = audit_success(kctx, tad, 0, NULL)) {
cred_t *cr = CRED();
const auditinfo_addr_t *ainfo = crgetauinfo(cr);
if (ainfo == NULL)
return;
AUDIT_SETSUBJ(&(u_ad), cr, ainfo, kctx);
add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0);
AS_INC(as_generated, 1, kctx);
AS_INC(as_kernel, 1, kctx);
}
au_close(kctx, &(u_ad), flag | AU_DONTBLOCK,
tad->tad_event, tad->tad_evmod, NULL);
}
void
audit_setfsat_path(int argnum)
{
klwp_id_t clwp = ttolwp(curthread);
struct file *fp;
uint32_t fd;
t_audit_data_t *tad;
struct f_audit_data *fad;
p_audit_data_t *pad;
uint_t fm;
struct a {
long arg1;
long arg2;
long arg3;
long arg4;
long arg5;
} *uap;
if (clwp == NULL)
return;
uap = (struct a *)clwp->lwp_ap;
tad = U2A(u);
ASSERT(tad != NULL);
switch (tad->tad_scid) {
case SYS_faccessat:
case SYS_fchmodat:
case SYS_fchownat:
case SYS_fstatat:
case SYS_fstatat64:
case SYS_mkdirat:
case SYS_mknodat:
case SYS_openat:
case SYS_openat64:
case SYS_readlinkat:
case SYS_unlinkat:
fd = uap->arg1;
break;
case SYS_linkat:
case SYS_renameat:
if (argnum == 3)
fd = uap->arg3;
else
fd = uap->arg1;
break;
case SYS_symlinkat:
case SYS_utimesys:
fd = uap->arg2;
break;
case SYS_open:
case SYS_open64:
fd = AT_FDCWD;
break;
default:
return;
}
if (tad->tad_atpath != NULL) {
au_pathrele(tad->tad_atpath);
tad->tad_atpath = NULL;
}
if (fd != AT_FDCWD) {
tad->tad_ctrl |= TAD_ATCALL;
if (tad->tad_scid == SYS_openat ||
tad->tad_scid == SYS_openat64) {
fm = (uint_t)uap->arg3;
if (fm & (FXATTR | FXATTRDIROPEN)) {
tad->tad_ctrl |= TAD_ATTPATH;
}
}
if ((fp = getf(fd)) == NULL) {
tad->tad_ctrl |= TAD_NOPATH;
return;
}
fad = F2A(fp);
ASSERT(fad);
if (fad->fad_aupath == NULL) {
tad->tad_ctrl |= TAD_NOPATH;
releasef(fd);
return;
}
au_pathhold(fad->fad_aupath);
tad->tad_atpath = fad->fad_aupath;
releasef(fd);
} else {
if (tad->tad_scid == SYS_open ||
tad->tad_scid == SYS_open64) {
fm = (uint_t)uap->arg2;
if (fm & FXATTR) {
tad->tad_ctrl |= TAD_ATTPATH;
}
return;
}
pad = P2A(curproc);
mutex_enter(&pad->pad_lock);
au_pathhold(pad->pad_cwd);
tad->tad_atpath = pad->pad_cwd;
mutex_exit(&pad->pad_lock);
}
}
void
audit_symlink_create(vnode_t *dvp, char *sname, char *target, int error)
{
t_audit_data_t *tad;
vnode_t *vp;
tad = U2A(u);
if (tad->tad_flag == 0)
return;
au_uwrite(au_to_text(target));
if (error)
return;
error = VOP_LOOKUP(dvp, sname, &vp, NULL, 0, NULL, CRED(),
NULL, NULL, NULL);
if (error == 0) {
audit_attributes(vp);
VN_RELE(vp);
}
}
void
audit_vncreate_start()
{
t_audit_data_t *tad;
tad = U2A(u);
tad->tad_ctrl |= TAD_NOATTRB;
}
void
audit_vncreate_finish(struct vnode *vp, int error)
{
t_audit_data_t *tad;
if (error)
return;
tad = U2A(u);
if (tad->tad_flag == 0)
return;
if (tad->tad_ctrl & TAD_TRUE_CREATE) {
audit_attributes(vp);
}
if (tad->tad_ctrl & TAD_CORE) {
audit_attributes(vp);
tad->tad_ctrl &= ~TAD_CORE;
}
if (!error && ((tad->tad_event == AUE_MKNOD) ||
(tad->tad_event == AUE_MKDIR))) {
audit_attributes(vp);
}
tad->tad_ctrl &= ~TAD_NOATTRB;
}
void
audit_exec(
const char *argstr,
const char *envstr,
ssize_t argc,
ssize_t envc,
cred_t *pfcred)
{
t_audit_data_t *tad;
au_kcontext_t *kctx = GET_KCTX_PZ;
tad = U2A(u);
if (!tad->tad_flag)
return;
if (pfcred != NULL) {
p_audit_data_t *pad;
cred_t *cr = CRED();
priv_set_t pset = CR_IPRIV(cr);
pad = P2A(curproc);
tad->tad_event = AUE_PFEXEC;
if (pad->pad_cwd != NULL)
au_uwrite(au_to_path(pad->pad_cwd));
priv_inverse(&pset);
priv_intersect(&CR_IPRIV(pfcred), &pset);
if (!priv_isemptyset(&pset) ||
!priv_isequalset(&CR_LPRIV(pfcred), &CR_LPRIV(cr))) {
au_uwrite(au_to_privset(
priv_getsetbynum(PRIV_INHERITABLE), &pset, AUT_PRIV,
0));
au_uwrite(au_to_privset(priv_getsetbynum(PRIV_LIMIT),
&CR_LPRIV(pfcred), AUT_PRIV, 0));
}
if (crgetuid(cr) != crgetuid(pfcred) ||
crgetruid(cr) != crgetruid(pfcred) ||
crgetgid(cr) != crgetgid(pfcred) ||
crgetrgid(cr) != crgetrgid(pfcred)) {
AUDIT_SETPROC(&(u_ad), cr, crgetauinfo(cr));
}
}
if (pfcred != NULL || (kctx->auk_policy & AUDIT_ARGV) != 0)
au_uwrite(au_to_exec_args(argstr, argc));
if (kctx->auk_policy & AUDIT_ARGE)
au_uwrite(au_to_exec_env(envstr, envc));
}
void
audit_enterprom(int flg)
{
token_t *rp = NULL;
int sorf;
if (flg)
sorf = AUM_SUCC;
else
sorf = AUM_FAIL;
AUDIT_ASYNC_START(rp, AUE_ENTERPROM, sorf);
au_write((caddr_t *)&(rp), au_to_text("kmdb"));
if (flg)
au_write((caddr_t *)&(rp), au_to_return32(0, 0));
else
au_write((caddr_t *)&(rp), au_to_return32(ECANCELED, 0));
AUDIT_ASYNC_FINISH(rp, AUE_ENTERPROM, 0, NULL);
}
void
audit_exitprom(int flg)
{
int sorf;
token_t *rp = NULL;
if (flg)
sorf = AUM_SUCC;
else
sorf = AUM_FAIL;
AUDIT_ASYNC_START(rp, AUE_EXITPROM, sorf);
au_write((caddr_t *)&(rp), au_to_text("kmdb"));
if (flg)
au_write((caddr_t *)&(rp), au_to_return32(0, 0));
else
au_write((caddr_t *)&(rp), au_to_return32(ECANCELED, 0));
AUDIT_ASYNC_FINISH(rp, AUE_EXITPROM, 0, NULL);
}
struct fcntla {
int fdes;
int cmd;
intptr_t arg;
};
void
audit_chdirec(vnode_t *vp, vnode_t **vpp)
{
int chdir;
int fchdir;
struct audit_path **appp;
struct file *fp;
f_audit_data_t *fad;
p_audit_data_t *pad = P2A(curproc);
t_audit_data_t *tad = T2A(curthread);
struct a {
long fd;
} *uap = (struct a *)ttolwp(curthread)->lwp_ap;
if ((tad->tad_scid == SYS_chdir) || (tad->tad_scid == SYS_chroot)) {
chdir = tad->tad_scid == SYS_chdir;
if (tad->tad_aupath) {
mutex_enter(&pad->pad_lock);
if (chdir)
appp = &(pad->pad_cwd);
else
appp = &(pad->pad_root);
au_pathrele(*appp);
*appp = tad->tad_aupath;
tad->tad_aupath = NULL;
mutex_exit(&pad->pad_lock);
}
} else if ((tad->tad_scid == SYS_fchdir) ||
(tad->tad_scid == SYS_fchroot)) {
fchdir = tad->tad_scid == SYS_fchdir;
if ((fp = getf(uap->fd)) == NULL)
return;
fad = F2A(fp);
if (fad->fad_aupath) {
au_pathhold(fad->fad_aupath);
mutex_enter(&pad->pad_lock);
if (fchdir)
appp = &(pad->pad_cwd);
else
appp = &(pad->pad_root);
au_pathrele(*appp);
*appp = fad->fad_aupath;
mutex_exit(&pad->pad_lock);
if (tad->tad_flag) {
au_uwrite(au_to_path(fad->fad_aupath));
audit_attributes(fp->f_vnode);
}
}
releasef(uap->fd);
}
}
void
audit_sock(
int type,
queue_t *q,
mblk_t *mp,
int from)
{
int32_t len;
int32_t offset;
struct sockaddr_in *sock_data;
struct T_conn_req *conn_req;
struct T_conn_ind *conn_ind;
struct T_unitdata_req *unitdata_req;
struct T_unitdata_ind *unitdata_ind;
au_state_t estate;
t_audit_data_t *tad;
caddr_t saved_thread_ptr;
au_mask_t amask;
const auditinfo_addr_t *ainfo;
au_kcontext_t *kctx;
if (q->q_stream == NULL)
return;
mutex_enter(&q->q_stream->sd_lock);
saved_thread_ptr = q->q_stream->sd_t_audit_data;
if (saved_thread_ptr == NULL) {
mutex_exit(&q->q_stream->sd_lock);
return;
}
q->q_stream->sd_t_audit_data = NULL;
if (curthread != (kthread_id_t)saved_thread_ptr) {
mutex_exit(&q->q_stream->sd_lock);
return;
}
if (curthread->t_sysnum >= SYS_so_socket &&
curthread->t_sysnum <= SYS_sockconfig) {
mutex_exit(&q->q_stream->sd_lock);
return;
}
mutex_exit(&q->q_stream->sd_lock);
tad = U2A(u);
kctx = GET_KCTX_PZ;
if (!tad->tad_flag)
return;
ainfo = crgetauinfo(CRED());
if (ainfo == NULL)
return;
amask = ainfo->ai_mask;
switch (type) {
case T_CONN_REQ:
conn_req = (struct T_conn_req *)mp->b_rptr;
if (conn_req->DEST_offset < sizeof (struct T_conn_req))
return;
offset = conn_req->DEST_offset;
len = conn_req->DEST_length;
estate = kctx->auk_ets[AUE_SOCKCONNECT];
if (amask.as_success & estate || amask.as_failure & estate) {
tad->tad_event = AUE_SOCKCONNECT;
break;
} else {
return;
}
case T_CONN_IND:
conn_ind = (struct T_conn_ind *)mp->b_rptr;
if (conn_ind->SRC_offset < sizeof (struct T_conn_ind))
return;
offset = conn_ind->SRC_offset;
len = conn_ind->SRC_length;
estate = kctx->auk_ets[AUE_SOCKACCEPT];
if (amask.as_success & estate || amask.as_failure & estate) {
tad->tad_event = AUE_SOCKACCEPT;
break;
} else {
return;
}
case T_UNITDATA_REQ:
unitdata_req = (struct T_unitdata_req *)mp->b_rptr;
if (unitdata_req->DEST_offset < sizeof (struct T_unitdata_req))
return;
offset = unitdata_req->DEST_offset;
len = unitdata_req->DEST_length;
estate = kctx->auk_ets[AUE_SOCKSEND];
if (amask.as_success & estate || amask.as_failure & estate) {
tad->tad_event = AUE_SOCKSEND;
break;
} else {
return;
}
case T_UNITDATA_IND:
unitdata_ind = (struct T_unitdata_ind *)mp->b_rptr;
if (unitdata_ind->SRC_offset < sizeof (struct T_unitdata_ind))
return;
offset = unitdata_ind->SRC_offset;
len = unitdata_ind->SRC_length;
estate = kctx->auk_ets[AUE_SOCKRECEIVE];
if (amask.as_success & estate || amask.as_failure & estate) {
tad->tad_event = AUE_SOCKRECEIVE;
break;
} else {
return;
}
default:
return;
}
if ((len < 0) || (len > sizeof (struct sockaddr_in))) {
tad->tad_event = AUE_GETMSG;
return;
}
sock_data = (struct sockaddr_in *)((char *)mp->b_rptr + offset);
switch (sock_data->sin_family) {
case AF_INET:
au_write(&(tad->tad_ad), au_to_sock_inet(sock_data));
break;
default:
tad->tad_event = AUE_GETMSG;
break;
}
}
static void
add_return_token(caddr_t *ad, unsigned int scid, int err, int rval)
{
unsigned int sy_flags;
#ifdef _SYSCALL32_IMPL
if ((curthread->t_lwp == NULL) || (lwp_getdatamodel(
ttolwp(curthread)) == DATAMODEL_NATIVE))
sy_flags = sysent[scid].sy_flags & SE_RVAL_MASK;
else
sy_flags = sysent32[scid].sy_flags & SE_RVAL_MASK;
#else
sy_flags = sysent[scid].sy_flags & SE_RVAL_MASK;
#endif
if (sy_flags == SE_64RVAL)
au_write(ad, au_to_return64(err, rval));
else
au_write(ad, au_to_return32(err, rval));
}
void
audit_fdsend(int fd, struct file *fp, int error)
{
t_audit_data_t *tad;
f_audit_data_t *fad;
struct vnode *vp;
tad = U2A(u);
ASSERT(tad != (t_audit_data_t *)0);
if (!tad->tad_flag)
return;
fad = F2A(fp);
if (fad != NULL && fad->fad_aupath != NULL) {
au_uwrite(au_to_arg32(0, "send fd", (uint32_t)fd));
au_uwrite(au_to_path(fad->fad_aupath));
} else {
au_uwrite(au_to_arg32(0, "send fd", (uint32_t)fd));
#ifdef _LP64
au_uwrite(au_to_arg64(0, "no path", (uint64_t)fp));
#else
au_uwrite(au_to_arg32(0, "no path", (uint32_t)fp));
#endif
}
vp = fp->f_vnode;
audit_attributes(vp);
}
void
audit_priv(int priv, const priv_set_t *set, int flag)
{
t_audit_data_t *tad;
int sbit;
priv_set_t *target;
ASSERT(servicing_interrupt() == 0);
tad = U2A(u);
if (tad->tad_flag == 0)
return;
target = flag ? &tad->tad_sprivs : &tad->tad_fprivs;
sbit = flag ? PAD_SPRIVUSE : PAD_FPRIVUSE;
if (!(tad->tad_evmod & sbit)) {
priv_emptyset(target);
tad->tad_evmod |= sbit;
}
if (priv == PRIV_ALL) {
priv_fillset(target);
} else {
ASSERT(set != NULL || priv != PRIV_NONE);
if (set != NULL)
priv_union(set, target);
if (priv != PRIV_NONE)
priv_addset(target, priv);
}
}
void
audit_psecflags(proc_t *p,
psecflagwhich_t which,
const secflagdelta_t *psd)
{
t_audit_data_t *tad;
secflagset_t new;
const secflagset_t *old;
const char *s;
cred_t *cr;
pid_t pid;
const auditinfo_addr_t *ainfo;
const psecflags_t *psec = &p->p_secflags;
tad = U2A(u);
if (tad->tad_flag == 0)
return;
switch (which) {
case PSF_EFFECTIVE:
s = "effective";
old = &psec->psf_effective;
break;
case PSF_INHERIT:
s = "inherit";
old = &psec->psf_inherit;
break;
case PSF_LOWER:
s = "lower";
old = &psec->psf_lower;
break;
case PSF_UPPER:
s = "upper";
old = &psec->psf_upper;
break;
}
secflags_copy(&new, old);
secflags_apply_delta(&new, psd);
au_uwrite(au_to_secflags(s, *old));
au_uwrite(au_to_secflags(s, new));
ASSERT(mutex_owned(&p->p_lock));
mutex_enter(&p->p_crlock);
pid = p->p_pid;
crhold(cr = p->p_cred);
mutex_exit(&p->p_crlock);
if ((ainfo = crgetauinfo(cr)) == NULL) {
crfree(cr);
return;
}
AUDIT_SETPROC_GENERIC(&(u_ad), cr, ainfo, pid);
crfree(cr);
}
void
audit_setppriv(int op, int set, const priv_set_t *newpriv, const cred_t *ocr)
{
t_audit_data_t *tad;
const priv_set_t *oldpriv;
priv_set_t report;
const char *setname;
tad = U2A(u);
if (tad->tad_flag == 0)
return;
oldpriv = priv_getset(ocr, set);
au_uwrite(au_to_arg32(2, "op", op));
setname = priv_getsetbynum(set);
switch (op) {
case PRIV_OFF:
report = *oldpriv;
priv_intersect(newpriv, &report);
au_uwrite(au_to_privset(setname, &report, AUT_PRIV, 0));
break;
case PRIV_ON:
report = *oldpriv;
priv_inverse(&report);
priv_intersect(newpriv, &report);
au_uwrite(au_to_privset(setname, &report, AUT_PRIV, 0));
break;
case PRIV_SET:
au_uwrite(au_to_privset(setname, oldpriv, AUT_PRIV, 0));
au_uwrite(au_to_privset(setname, newpriv, AUT_PRIV, 0));
break;
}
}
void
audit_devpolicy(int nitems, const devplcysys_t *items)
{
t_audit_data_t *tad;
int i;
tad = U2A(u);
if (tad->tad_flag == 0)
return;
for (i = 0; i < nitems; i++) {
au_uwrite(au_to_arg32(2, "major", items[i].dps_maj));
if (items[i].dps_minornm[0] == '\0') {
au_uwrite(au_to_arg32(2, "lomin", items[i].dps_lomin));
au_uwrite(au_to_arg32(2, "himin", items[i].dps_himin));
} else
au_uwrite(au_to_text(items[i].dps_minornm));
au_uwrite(au_to_privset("read", &items[i].dps_rdp,
AUT_PRIV, 0));
au_uwrite(au_to_privset("write", &items[i].dps_wrp,
AUT_PRIV, 0));
}
}
void
audit_fdrecv(int fd, struct file *fp)
{
t_audit_data_t *tad;
f_audit_data_t *fad;
struct vnode *vp;
tad = U2A(u);
ASSERT(tad != (t_audit_data_t *)0);
if (!tad->tad_flag)
return;
fad = F2A(fp);
if (fad != NULL && fad->fad_aupath != NULL) {
au_uwrite(au_to_arg32(0, "recv fd", (uint32_t)fd));
au_uwrite(au_to_path(fad->fad_aupath));
} else {
au_uwrite(au_to_arg32(0, "recv fd", (uint32_t)fd));
#ifdef _LP64
au_uwrite(au_to_arg64(0, "no path", (uint64_t)fp));
#else
au_uwrite(au_to_arg32(0, "no path", (uint32_t)fp));
#endif
}
vp = fp->f_vnode;
audit_attributes(vp);
}
void
audit_cryptoadm(int cmd, char *module_name, crypto_mech_name_t *mech_names,
uint_t mech_count, uint_t device_instance, uint32_t rv, int error)
{
boolean_t mech_list_required = B_FALSE;
cred_t *cr = CRED();
t_audit_data_t *tad;
token_t *ad = NULL;
const auditinfo_addr_t *ainfo = crgetauinfo(cr);
char buffer[MAXNAMELEN * 2];
au_kcontext_t *kctx = GET_KCTX_PZ;
tad = U2A(u);
if (tad == NULL)
return;
if (ainfo == NULL)
return;
tad->tad_event = AUE_CRYPTOADM;
if (audit_success(kctx, tad, error, NULL) != AU_OK)
return;
AUDIT_SETSUBJ((caddr_t *)&(ad), cr, ainfo, kctx);
switch (cmd) {
case CRYPTO_LOAD_DEV_DISABLED:
if (error == 0 && rv == CRYPTO_SUCCESS) {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_DEV_DISABLED, module=%s,"
" dev_instance=%d",
module_name, device_instance);
mech_list_required = B_TRUE;
} else {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_DEV_DISABLED, return_val=%d", rv);
}
break;
case CRYPTO_LOAD_SOFT_DISABLED:
if (error == 0 && rv == CRYPTO_SUCCESS) {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_SOFT_DISABLED, module=%s",
module_name);
mech_list_required = B_TRUE;
} else {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_SOFT_DISABLED, return_val=%d", rv);
}
break;
case CRYPTO_UNLOAD_SOFT_MODULE:
if (error == 0 && rv == CRYPTO_SUCCESS) {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_UNLOAD_SOFT_MODULE, module=%s",
module_name);
} else {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_UNLOAD_SOFT_MODULE, return_val=%d", rv);
}
break;
case CRYPTO_LOAD_SOFT_CONFIG:
if (error == 0 && rv == CRYPTO_SUCCESS) {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_SOFT_CONFIG, module=%s",
module_name);
mech_list_required = B_TRUE;
} else {
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_SOFT_CONFIG, return_val=%d", rv);
}
break;
case CRYPTO_POOL_CREATE:
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_POOL_CREATE");
break;
case CRYPTO_POOL_WAIT:
(void) snprintf(buffer, sizeof (buffer), "op=CRYPTO_POOL_WAIT");
break;
case CRYPTO_POOL_RUN:
(void) snprintf(buffer, sizeof (buffer), "op=CRYPTO_POOL_RUN");
break;
case CRYPTO_LOAD_DOOR:
if (error == 0 && rv == CRYPTO_SUCCESS)
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_DOOR");
else
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_LOAD_DOOR, return_val=%d", rv);
break;
case CRYPTO_FIPS140_SET:
(void) snprintf(buffer, sizeof (buffer),
"op=CRYPTO_FIPS140_SET, fips_state=%d", rv);
break;
default:
return;
}
au_write((caddr_t *)&ad, au_to_text(buffer));
if (mech_list_required) {
int i;
if (mech_count == 0) {
au_write((caddr_t *)&ad, au_to_text("mech=list empty"));
} else {
char *pb = buffer;
size_t l = sizeof (buffer);
size_t n;
char space[2] = ":";
n = snprintf(pb, l, "mech=");
for (i = 0; i < mech_count; i++) {
pb += n;
l = (n >= l) ? 0 : l - n;
if (i == mech_count - 1)
(void) strcpy(space, "");
n = snprintf(pb, l, "%s%s", mech_names[i],
space);
}
au_write((caddr_t *)&ad, au_to_text(buffer));
}
}
if (error || (rv != CRYPTO_SUCCESS))
add_return_token((caddr_t *)&ad, tad->tad_scid, -1, error);
else
add_return_token((caddr_t *)&ad, tad->tad_scid, 0, rv);
AS_INC(as_generated, 1, kctx);
AS_INC(as_kernel, 1, kctx);
au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CRYPTOADM, tad->tad_evmod,
NULL);
}
void
audit_pf_policy(int cmd, cred_t *cred, netstack_t *ns, char *tun,
boolean_t active, int error, pid_t pid)
{
const auditinfo_addr_t *ainfo;
t_audit_data_t *tad;
token_t *ad = NULL;
au_kcontext_t *kctx = GET_KCTX_PZ;
char buf[80];
int flag;
tad = U2A(u);
if (tad == NULL)
return;
ainfo = crgetauinfo((cred != NULL) ? cred : CRED());
if (ainfo == NULL)
return;
switch (cmd) {
case SPD_ADDRULE: {
tad->tad_event = AUE_PF_POLICY_ADDRULE;
break;
}
case SPD_DELETERULE: {
tad->tad_event = AUE_PF_POLICY_DELRULE;
break;
}
case SPD_FLUSH: {
tad->tad_event = AUE_PF_POLICY_FLUSH;
break;
}
case SPD_UPDATEALGS: {
tad->tad_event = AUE_PF_POLICY_ALGS;
break;
}
case SPD_CLONE: {
tad->tad_event = AUE_PF_POLICY_CLONE;
break;
}
case SPD_FLIP: {
tad->tad_event = AUE_PF_POLICY_FLIP;
break;
}
default:
tad->tad_event = AUE_NULL;
}
tad->tad_evmod = 0;
if (flag = audit_success(kctx, tad, error, cred)) {
zone_t *nszone;
au_write((caddr_t *)&ad,
au_to_arg32(1, "Policy Active?", (uint32_t)active));
au_write((caddr_t *)&ad,
au_to_arg32(2, "Policy Global?", (uint32_t)(tun == NULL)));
nszone = zone_find_by_id(netstackid_to_zoneid(
ns->netstack_stackid));
if (nszone != NULL) {
if (strncmp(crgetzone(cred)->zone_name,
nszone->zone_name, ZONENAME_MAX) != 0) {
token_t *ztoken;
ztoken = au_to_zonename(0, nszone);
au_write((caddr_t *)&ad, ztoken);
}
zone_rele(nszone);
}
if (tun != NULL) {
(void) snprintf(buf, sizeof (buf), "tunnel_name:%s",
tun);
au_write((caddr_t *)&ad, au_to_text(buf));
}
AUDIT_SETSUBJ_GENERIC((caddr_t *)&ad,
((cred != NULL) ? cred : CRED()), ainfo, kctx, pid);
add_return_token((caddr_t *)&ad, 0, error, 0);
AS_INC(as_generated, 1, kctx);
AS_INC(as_kernel, 1, kctx);
}
au_close(kctx, (caddr_t *)&ad, flag, tad->tad_event, tad->tad_evmod,
NULL);
tad->tad_scid = 0;
tad->tad_event = 0;
tad->tad_evmod = 0;
tad->tad_ctrl = 0;
}
void
audit_sec_attributes(caddr_t *ad, struct vnode *vp)
{
if (is_system_labeled()) {
ts_label_t *tsl;
bslabel_t *bsl;
tsl = getflabel(vp);
if (tsl == NULL)
return;
bsl = label2bslabel(tsl);
if (bsl == NULL)
return;
au_write(ad, au_to_label(bsl));
label_rele(tsl);
}
}