2017-11-20 19:43:44 +00:00
|
|
|
/*-
|
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*
|
2009-02-08 14:39:35 +00:00
|
|
|
* Copyright (c) 1999-2009 Apple Inc.
|
2017-03-29 23:31:35 +00:00
|
|
|
* Copyright (c) 2005, 2016-2017 Robert N. M. Watson
|
2006-02-01 20:01:18 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
2017-03-27 10:38:53 +00:00
|
|
|
* Portions of this software were developed by BAE Systems, the University of
|
|
|
|
* Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
|
|
|
|
* contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
|
|
|
|
* Computing (TC) research program.
|
|
|
|
*
|
2006-02-01 20:01:18 +00:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2008-07-22 15:29:48 +00:00
|
|
|
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
|
2006-02-01 20:01:18 +00:00
|
|
|
* its contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
|
|
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2008-04-13 22:06:56 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2006-02-01 20:01:18 +00:00
|
|
|
#include <sys/param.h>
|
2015-07-05 19:05:16 +00:00
|
|
|
#include <sys/capsicum.h>
|
2006-02-01 20:01:18 +00:00
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/filedesc.h>
|
|
|
|
#include <sys/libkern.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/proc.h>
|
2008-10-30 17:47:57 +00:00
|
|
|
#include <sys/rwlock.h>
|
2006-02-01 20:01:18 +00:00
|
|
|
#include <sys/sem.h>
|
2008-07-31 16:57:41 +00:00
|
|
|
#include <sys/sbuf.h>
|
2017-03-27 10:38:53 +00:00
|
|
|
#include <sys/sx.h>
|
2006-02-01 20:01:18 +00:00
|
|
|
#include <sys/syscall.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <sys/sysent.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
|
|
|
|
#include <bsm/audit.h>
|
|
|
|
#include <bsm/audit_kevents.h>
|
|
|
|
#include <security/audit/audit.h>
|
|
|
|
#include <security/audit/audit_private.h>
|
|
|
|
|
2009-07-28 21:39:58 +00:00
|
|
|
struct aue_open_event {
|
|
|
|
int aoe_flags;
|
|
|
|
au_event_t aoe_event;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct aue_open_event aue_open[] = {
|
|
|
|
{ O_RDONLY, AUE_OPEN_R },
|
|
|
|
{ (O_RDONLY | O_CREAT), AUE_OPEN_RC },
|
|
|
|
{ (O_RDONLY | O_CREAT | O_TRUNC), AUE_OPEN_RTC },
|
|
|
|
{ (O_RDONLY | O_TRUNC), AUE_OPEN_RT },
|
|
|
|
{ O_RDWR, AUE_OPEN_RW },
|
|
|
|
{ (O_RDWR | O_CREAT), AUE_OPEN_RWC },
|
|
|
|
{ (O_RDWR | O_CREAT | O_TRUNC), AUE_OPEN_RWTC },
|
|
|
|
{ (O_RDWR | O_TRUNC), AUE_OPEN_RWT },
|
|
|
|
{ O_WRONLY, AUE_OPEN_W },
|
|
|
|
{ (O_WRONLY | O_CREAT), AUE_OPEN_WC },
|
|
|
|
{ (O_WRONLY | O_CREAT | O_TRUNC), AUE_OPEN_WTC },
|
|
|
|
{ (O_WRONLY | O_TRUNC), AUE_OPEN_WT },
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct aue_open_event aue_openat[] = {
|
|
|
|
{ O_RDONLY, AUE_OPENAT_R },
|
|
|
|
{ (O_RDONLY | O_CREAT), AUE_OPENAT_RC },
|
|
|
|
{ (O_RDONLY | O_CREAT | O_TRUNC), AUE_OPENAT_RTC },
|
|
|
|
{ (O_RDONLY | O_TRUNC), AUE_OPENAT_RT },
|
|
|
|
{ O_RDWR, AUE_OPENAT_RW },
|
|
|
|
{ (O_RDWR | O_CREAT), AUE_OPENAT_RWC },
|
|
|
|
{ (O_RDWR | O_CREAT | O_TRUNC), AUE_OPENAT_RWTC },
|
|
|
|
{ (O_RDWR | O_TRUNC), AUE_OPENAT_RWT },
|
|
|
|
{ O_WRONLY, AUE_OPENAT_W },
|
|
|
|
{ (O_WRONLY | O_CREAT), AUE_OPENAT_WC },
|
|
|
|
{ (O_WRONLY | O_CREAT | O_TRUNC), AUE_OPENAT_WTC },
|
|
|
|
{ (O_WRONLY | O_TRUNC), AUE_OPENAT_WT },
|
|
|
|
};
|
|
|
|
|
2017-03-29 23:31:35 +00:00
|
|
|
static const int aue_msgsys[] = {
|
|
|
|
/* 0 */ AUE_MSGCTL,
|
|
|
|
/* 1 */ AUE_MSGGET,
|
|
|
|
/* 2 */ AUE_MSGSND,
|
|
|
|
/* 3 */ AUE_MSGRCV,
|
|
|
|
};
|
|
|
|
static const int aue_msgsys_count = sizeof(aue_msgsys) / sizeof(int);
|
|
|
|
|
|
|
|
static const int aue_semsys[] = {
|
|
|
|
/* 0 */ AUE_SEMCTL,
|
|
|
|
/* 1 */ AUE_SEMGET,
|
|
|
|
/* 2 */ AUE_SEMOP,
|
|
|
|
};
|
|
|
|
static const int aue_semsys_count = sizeof(aue_semsys) / sizeof(int);
|
|
|
|
|
|
|
|
static const int aue_shmsys[] = {
|
|
|
|
/* 0 */ AUE_SHMAT,
|
|
|
|
/* 1 */ AUE_SHMDT,
|
|
|
|
/* 2 */ AUE_SHMGET,
|
|
|
|
/* 3 */ AUE_SHMCTL,
|
|
|
|
};
|
|
|
|
static const int aue_shmsys_count = sizeof(aue_shmsys) / sizeof(int);
|
|
|
|
|
2006-02-01 20:01:18 +00:00
|
|
|
/*
|
2018-03-17 17:56:08 +00:00
|
|
|
* Check whether an event is auditable by comparing the mask of classes this
|
2006-02-01 20:01:18 +00:00
|
|
|
* event is part of against the given mask.
|
|
|
|
*/
|
|
|
|
int
|
Introduce support for per-audit pipe preselection independent from the
global audit trail configuration. This allows applications consuming
audit trails to specify parameters for which audit records are of
interest, including selecting records not required by the global trail.
Allowing application interest specification without changing the global
configuration allows intrusion detection systems to run without
interfering with global auditing or each other (if multiple are
present). To implement this:
- Kernel audit records now carry a flag to indicate whether they have
been selected by the global trail or by the audit pipe subsystem,
set during record commit, so that this information is available
after BSM conversion when delivering the BSM to the trail and audit
pipes in the audit worker thread asynchronously. Preselection by
either record target will cause the record to be kept.
- Similar changes to preselection when the audit record is created
when the system call is entering: consult both the global trail and
pipes.
- au_preselect() now accepts the class in order to avoid repeatedly
looking up the mask for each preselection test.
- Define a series of ioctls that allow applications to specify whether
they want to track the global trail, or program their own
preselection parameters: they may specify their own flags and naflags
masks, similar to the global masks of the same name, as well as a set
of per-auid masks. They also set a per-pipe mode specifying whether
they track the global trail, or user their own -- the door is left
open for future additional modes. A new ioctl is defined to allow a
user process to flush the current audit pipe queue, which can be used
after reprogramming pre-selection to make sure that only records of
interest are received in future reads.
- Audit pipe data structures are extended to hold the additional fields
necessary to support preselection. By default, audit pipes track the
global trail, so "praudit /dev/auditpipe" will track the global audit
trail even though praudit doesn't program the audit pipe selection
model.
- Comment about the complexities of potentially adding partial read
support to audit pipes.
By using a set of ioctls, applications can select which records are of
interest, and toggle the preselection mode.
Obtained from: TrustedBSD Project
2006-06-05 14:48:17 +00:00
|
|
|
au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
|
2006-02-01 20:01:18 +00:00
|
|
|
{
|
|
|
|
au_class_t effmask = 0;
|
|
|
|
|
|
|
|
if (mask_p == NULL)
|
|
|
|
return (-1);
|
|
|
|
|
2006-03-19 17:34:00 +00:00
|
|
|
/*
|
2006-02-01 20:01:18 +00:00
|
|
|
* Perform the actual check of the masks against the event.
|
|
|
|
*/
|
|
|
|
if (sorf & AU_PRS_SUCCESS)
|
Introduce support for per-audit pipe preselection independent from the
global audit trail configuration. This allows applications consuming
audit trails to specify parameters for which audit records are of
interest, including selecting records not required by the global trail.
Allowing application interest specification without changing the global
configuration allows intrusion detection systems to run without
interfering with global auditing or each other (if multiple are
present). To implement this:
- Kernel audit records now carry a flag to indicate whether they have
been selected by the global trail or by the audit pipe subsystem,
set during record commit, so that this information is available
after BSM conversion when delivering the BSM to the trail and audit
pipes in the audit worker thread asynchronously. Preselection by
either record target will cause the record to be kept.
- Similar changes to preselection when the audit record is created
when the system call is entering: consult both the global trail and
pipes.
- au_preselect() now accepts the class in order to avoid repeatedly
looking up the mask for each preselection test.
- Define a series of ioctls that allow applications to specify whether
they want to track the global trail, or program their own
preselection parameters: they may specify their own flags and naflags
masks, similar to the global masks of the same name, as well as a set
of per-auid masks. They also set a per-pipe mode specifying whether
they track the global trail, or user their own -- the door is left
open for future additional modes. A new ioctl is defined to allow a
user process to flush the current audit pipe queue, which can be used
after reprogramming pre-selection to make sure that only records of
interest are received in future reads.
- Audit pipe data structures are extended to hold the additional fields
necessary to support preselection. By default, audit pipes track the
global trail, so "praudit /dev/auditpipe" will track the global audit
trail even though praudit doesn't program the audit pipe selection
model.
- Comment about the complexities of potentially adding partial read
support to audit pipes.
By using a set of ioctls, applications can select which records are of
interest, and toggle the preselection mode.
Obtained from: TrustedBSD Project
2006-06-05 14:48:17 +00:00
|
|
|
effmask |= (mask_p->am_success & class);
|
2006-03-19 17:34:00 +00:00
|
|
|
|
2006-02-01 20:01:18 +00:00
|
|
|
if (sorf & AU_PRS_FAILURE)
|
Introduce support for per-audit pipe preselection independent from the
global audit trail configuration. This allows applications consuming
audit trails to specify parameters for which audit records are of
interest, including selecting records not required by the global trail.
Allowing application interest specification without changing the global
configuration allows intrusion detection systems to run without
interfering with global auditing or each other (if multiple are
present). To implement this:
- Kernel audit records now carry a flag to indicate whether they have
been selected by the global trail or by the audit pipe subsystem,
set during record commit, so that this information is available
after BSM conversion when delivering the BSM to the trail and audit
pipes in the audit worker thread asynchronously. Preselection by
either record target will cause the record to be kept.
- Similar changes to preselection when the audit record is created
when the system call is entering: consult both the global trail and
pipes.
- au_preselect() now accepts the class in order to avoid repeatedly
looking up the mask for each preselection test.
- Define a series of ioctls that allow applications to specify whether
they want to track the global trail, or program their own
preselection parameters: they may specify their own flags and naflags
masks, similar to the global masks of the same name, as well as a set
of per-auid masks. They also set a per-pipe mode specifying whether
they track the global trail, or user their own -- the door is left
open for future additional modes. A new ioctl is defined to allow a
user process to flush the current audit pipe queue, which can be used
after reprogramming pre-selection to make sure that only records of
interest are received in future reads.
- Audit pipe data structures are extended to hold the additional fields
necessary to support preselection. By default, audit pipes track the
global trail, so "praudit /dev/auditpipe" will track the global audit
trail even though praudit doesn't program the audit pipe selection
model.
- Comment about the complexities of potentially adding partial read
support to audit pipes.
By using a set of ioctls, applications can select which records are of
interest, and toggle the preselection mode.
Obtained from: TrustedBSD Project
2006-06-05 14:48:17 +00:00
|
|
|
effmask |= (mask_p->am_failure & class);
|
2006-03-19 17:34:00 +00:00
|
|
|
|
2006-02-01 20:01:18 +00:00
|
|
|
if (effmask)
|
|
|
|
return (1);
|
2006-03-19 17:34:00 +00:00
|
|
|
else
|
2006-02-01 20:01:18 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-03-19 17:34:00 +00:00
|
|
|
* Convert sysctl names and present arguments to events.
|
2006-02-01 20:01:18 +00:00
|
|
|
*/
|
|
|
|
au_event_t
|
2008-03-01 11:40:49 +00:00
|
|
|
audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
|
2006-02-01 20:01:18 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
/* can't parse it - so return the worst case */
|
2006-03-19 17:34:00 +00:00
|
|
|
if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
|
2006-02-01 20:01:18 +00:00
|
|
|
return (AUE_SYSCTL);
|
|
|
|
|
|
|
|
switch (name[0]) {
|
|
|
|
/* non-admin "lookups" treat them special */
|
|
|
|
case KERN_OSTYPE:
|
|
|
|
case KERN_OSRELEASE:
|
|
|
|
case KERN_OSREV:
|
|
|
|
case KERN_VERSION:
|
|
|
|
case KERN_ARGMAX:
|
|
|
|
case KERN_CLOCKRATE:
|
|
|
|
case KERN_BOOTTIME:
|
|
|
|
case KERN_POSIX1:
|
|
|
|
case KERN_NGROUPS:
|
|
|
|
case KERN_JOB_CONTROL:
|
|
|
|
case KERN_SAVED_IDS:
|
|
|
|
case KERN_OSRELDATE:
|
|
|
|
case KERN_DUMMY:
|
|
|
|
return (AUE_SYSCTL_NONADMIN);
|
|
|
|
|
|
|
|
/* only treat the changeable controls as admin */
|
|
|
|
case KERN_MAXVNODES:
|
|
|
|
case KERN_MAXPROC:
|
|
|
|
case KERN_MAXFILES:
|
|
|
|
case KERN_MAXPROCPERUID:
|
|
|
|
case KERN_MAXFILESPERPROC:
|
|
|
|
case KERN_HOSTID:
|
|
|
|
case KERN_SECURELVL:
|
|
|
|
case KERN_HOSTNAME:
|
|
|
|
case KERN_VNODE:
|
|
|
|
case KERN_PROC:
|
|
|
|
case KERN_FILE:
|
|
|
|
case KERN_PROF:
|
|
|
|
case KERN_NISDOMAINNAME:
|
|
|
|
case KERN_UPDATEINTERVAL:
|
|
|
|
case KERN_NTP_PLL:
|
|
|
|
case KERN_BOOTFILE:
|
|
|
|
case KERN_DUMPDEV:
|
|
|
|
case KERN_IPC:
|
|
|
|
case KERN_PS_STRINGS:
|
|
|
|
case KERN_USRSTACK:
|
|
|
|
case KERN_LOGSIGEXIT:
|
|
|
|
case KERN_IOV_MAX:
|
|
|
|
return ((valid_arg & ARG_VALUE) ?
|
2008-07-31 09:54:35 +00:00
|
|
|
AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
|
2006-02-01 20:01:18 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
return (AUE_SYSCTL);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-03-19 17:34:00 +00:00
|
|
|
* Convert an open flags specifier into a specific type of open event for
|
2006-02-01 20:01:18 +00:00
|
|
|
* auditing purposes.
|
|
|
|
*/
|
|
|
|
au_event_t
|
2008-03-01 11:40:49 +00:00
|
|
|
audit_flags_and_error_to_openevent(int oflags, int error)
|
2006-03-19 17:34:00 +00:00
|
|
|
{
|
2009-07-28 21:39:58 +00:00
|
|
|
int i;
|
2006-02-01 20:01:18 +00:00
|
|
|
|
2006-03-19 17:34:00 +00:00
|
|
|
/*
|
|
|
|
* Need to check only those flags we care about.
|
|
|
|
*/
|
2006-02-01 20:01:18 +00:00
|
|
|
oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
|
2016-04-21 15:38:28 +00:00
|
|
|
for (i = 0; i < nitems(aue_open); i++) {
|
2009-07-28 21:39:58 +00:00
|
|
|
if (aue_open[i].aoe_flags == oflags)
|
|
|
|
return (aue_open[i].aoe_event);
|
2006-02-01 20:01:18 +00:00
|
|
|
}
|
2009-07-28 21:39:58 +00:00
|
|
|
return (AUE_OPEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
au_event_t
|
|
|
|
audit_flags_and_error_to_openatevent(int oflags, int error)
|
|
|
|
{
|
|
|
|
int i;
|
2006-02-01 20:01:18 +00:00
|
|
|
|
2006-03-19 17:34:00 +00:00
|
|
|
/*
|
2009-07-28 21:39:58 +00:00
|
|
|
* Need to check only those flags we care about.
|
2006-02-01 20:01:18 +00:00
|
|
|
*/
|
2009-07-28 21:39:58 +00:00
|
|
|
oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
|
2016-04-21 15:38:28 +00:00
|
|
|
for (i = 0; i < nitems(aue_openat); i++) {
|
2009-07-28 21:39:58 +00:00
|
|
|
if (aue_openat[i].aoe_flags == oflags)
|
|
|
|
return (aue_openat[i].aoe_event);
|
2006-02-01 20:01:18 +00:00
|
|
|
}
|
2009-07-28 21:39:58 +00:00
|
|
|
return (AUE_OPENAT);
|
2006-02-01 20:01:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert a MSGCTL command to a specific event.
|
|
|
|
*/
|
2009-02-08 14:39:35 +00:00
|
|
|
au_event_t
|
2008-02-25 20:28:00 +00:00
|
|
|
audit_msgctl_to_event(int cmd)
|
2006-02-01 20:01:18 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case IPC_RMID:
|
|
|
|
return (AUE_MSGCTL_RMID);
|
|
|
|
|
|
|
|
case IPC_SET:
|
|
|
|
return (AUE_MSGCTL_SET);
|
|
|
|
|
|
|
|
case IPC_STAT:
|
|
|
|
return (AUE_MSGCTL_STAT);
|
|
|
|
|
|
|
|
default:
|
2007-06-01 21:58:59 +00:00
|
|
|
/* We will audit a bad command. */
|
2006-02-01 20:01:18 +00:00
|
|
|
return (AUE_MSGCTL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert a SEMCTL command to a specific event.
|
|
|
|
*/
|
2009-02-08 14:39:35 +00:00
|
|
|
au_event_t
|
2008-02-25 20:28:00 +00:00
|
|
|
audit_semctl_to_event(int cmd)
|
2006-02-01 20:01:18 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case GETALL:
|
|
|
|
return (AUE_SEMCTL_GETALL);
|
|
|
|
|
|
|
|
case GETNCNT:
|
|
|
|
return (AUE_SEMCTL_GETNCNT);
|
|
|
|
|
|
|
|
case GETPID:
|
|
|
|
return (AUE_SEMCTL_GETPID);
|
|
|
|
|
|
|
|
case GETVAL:
|
|
|
|
return (AUE_SEMCTL_GETVAL);
|
|
|
|
|
|
|
|
case GETZCNT:
|
|
|
|
return (AUE_SEMCTL_GETZCNT);
|
|
|
|
|
|
|
|
case IPC_RMID:
|
|
|
|
return (AUE_SEMCTL_RMID);
|
|
|
|
|
|
|
|
case IPC_SET:
|
|
|
|
return (AUE_SEMCTL_SET);
|
|
|
|
|
|
|
|
case SETALL:
|
|
|
|
return (AUE_SEMCTL_SETALL);
|
|
|
|
|
|
|
|
case SETVAL:
|
|
|
|
return (AUE_SEMCTL_SETVAL);
|
|
|
|
|
|
|
|
case IPC_STAT:
|
|
|
|
return (AUE_SEMCTL_STAT);
|
|
|
|
|
|
|
|
default:
|
2008-07-31 09:54:35 +00:00
|
|
|
/* We will audit a bad command. */
|
2006-02-01 20:01:18 +00:00
|
|
|
return (AUE_SEMCTL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-29 23:31:35 +00:00
|
|
|
/*
|
|
|
|
* Convert msgsys(2), semsys(2), and shmsys(2) system-call variations into
|
|
|
|
* audit events, if possible.
|
|
|
|
*/
|
|
|
|
au_event_t
|
|
|
|
audit_msgsys_to_event(int which)
|
|
|
|
{
|
|
|
|
|
|
|
|
if ((which >= 0) && (which < aue_msgsys_count))
|
|
|
|
return (aue_msgsys[which]);
|
|
|
|
|
|
|
|
/* Audit a bad command. */
|
|
|
|
return (AUE_MSGSYS);
|
|
|
|
}
|
|
|
|
|
|
|
|
au_event_t
|
|
|
|
audit_semsys_to_event(int which)
|
|
|
|
{
|
|
|
|
|
|
|
|
if ((which >= 0) && (which < aue_semsys_count))
|
|
|
|
return (aue_semsys[which]);
|
|
|
|
|
|
|
|
/* Audit a bad command. */
|
|
|
|
return (AUE_SEMSYS);
|
|
|
|
}
|
|
|
|
|
|
|
|
au_event_t
|
|
|
|
audit_shmsys_to_event(int which)
|
|
|
|
{
|
|
|
|
|
|
|
|
if ((which >= 0) && (which < aue_shmsys_count))
|
|
|
|
return (aue_shmsys[which]);
|
|
|
|
|
|
|
|
/* Audit a bad command. */
|
|
|
|
return (AUE_SHMSYS);
|
|
|
|
}
|
|
|
|
|
2006-02-01 20:01:18 +00:00
|
|
|
/*
|
|
|
|
* Convert a command for the auditon() system call to a audit event.
|
|
|
|
*/
|
2009-02-08 14:39:35 +00:00
|
|
|
au_event_t
|
2006-02-01 20:01:18 +00:00
|
|
|
auditon_command_event(int cmd)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch(cmd) {
|
|
|
|
case A_GETPOLICY:
|
|
|
|
return (AUE_AUDITON_GPOLICY);
|
|
|
|
|
|
|
|
case A_SETPOLICY:
|
|
|
|
return (AUE_AUDITON_SPOLICY);
|
|
|
|
|
|
|
|
case A_GETKMASK:
|
|
|
|
return (AUE_AUDITON_GETKMASK);
|
|
|
|
|
|
|
|
case A_SETKMASK:
|
|
|
|
return (AUE_AUDITON_SETKMASK);
|
|
|
|
|
|
|
|
case A_GETQCTRL:
|
|
|
|
return (AUE_AUDITON_GQCTRL);
|
|
|
|
|
|
|
|
case A_SETQCTRL:
|
|
|
|
return (AUE_AUDITON_SQCTRL);
|
|
|
|
|
|
|
|
case A_GETCWD:
|
|
|
|
return (AUE_AUDITON_GETCWD);
|
|
|
|
|
|
|
|
case A_GETCAR:
|
|
|
|
return (AUE_AUDITON_GETCAR);
|
|
|
|
|
|
|
|
case A_GETSTAT:
|
|
|
|
return (AUE_AUDITON_GETSTAT);
|
|
|
|
|
|
|
|
case A_SETSTAT:
|
|
|
|
return (AUE_AUDITON_SETSTAT);
|
|
|
|
|
|
|
|
case A_SETUMASK:
|
|
|
|
return (AUE_AUDITON_SETUMASK);
|
|
|
|
|
|
|
|
case A_SETSMASK:
|
|
|
|
return (AUE_AUDITON_SETSMASK);
|
|
|
|
|
|
|
|
case A_GETCOND:
|
|
|
|
return (AUE_AUDITON_GETCOND);
|
|
|
|
|
|
|
|
case A_SETCOND:
|
|
|
|
return (AUE_AUDITON_SETCOND);
|
|
|
|
|
|
|
|
case A_GETCLASS:
|
|
|
|
return (AUE_AUDITON_GETCLASS);
|
|
|
|
|
|
|
|
case A_SETCLASS:
|
|
|
|
return (AUE_AUDITON_SETCLASS);
|
|
|
|
|
|
|
|
case A_GETPINFO:
|
|
|
|
case A_SETPMASK:
|
|
|
|
case A_SETFSIZE:
|
|
|
|
case A_GETFSIZE:
|
|
|
|
case A_GETPINFO_ADDR:
|
|
|
|
case A_GETKAUDIT:
|
|
|
|
case A_SETKAUDIT:
|
|
|
|
default:
|
|
|
|
return (AUE_AUDITON); /* No special record */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-19 17:34:00 +00:00
|
|
|
/*
|
|
|
|
* Create a canonical path from given path by prefixing either the root
|
|
|
|
* directory, or the current working directory. If the process working
|
2007-06-01 21:58:59 +00:00
|
|
|
* directory is NULL, we could use 'rootvnode' to obtain the root directory,
|
2006-03-19 17:34:00 +00:00
|
|
|
* but this results in a volfs name written to the audit log. So we will
|
|
|
|
* leave the filename starting with '/' in the audit log in this case.
|
2006-02-01 20:01:18 +00:00
|
|
|
*/
|
|
|
|
void
|
2020-02-21 01:40:49 +00:00
|
|
|
audit_canon_path_vp(struct thread *td, struct vnode *rdir, struct vnode *cdir,
|
|
|
|
char *path, char *cpath)
|
2006-02-01 20:01:18 +00:00
|
|
|
{
|
2020-02-21 01:40:20 +00:00
|
|
|
struct vnode *vp;
|
2008-07-31 16:57:41 +00:00
|
|
|
char *rbuf, *fbuf, *copy;
|
|
|
|
struct sbuf sbf;
|
2020-02-21 01:40:20 +00:00
|
|
|
int error;
|
2006-02-01 20:01:18 +00:00
|
|
|
|
2008-07-31 16:57:41 +00:00
|
|
|
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
|
|
|
|
__func__, __FILE__, __LINE__);
|
2006-12-29 10:37:32 +00:00
|
|
|
|
2008-07-31 16:57:41 +00:00
|
|
|
copy = path;
|
2020-04-17 02:09:31 +00:00
|
|
|
if (*path == '/') {
|
2020-02-21 01:40:49 +00:00
|
|
|
vp = rdir;
|
2020-04-17 02:09:31 +00:00
|
|
|
} else {
|
|
|
|
if (cdir == NULL) {
|
|
|
|
cpath[0] = '\0';
|
|
|
|
return;
|
|
|
|
}
|
2020-02-21 01:40:49 +00:00
|
|
|
vp = cdir;
|
2020-04-17 02:09:31 +00:00
|
|
|
}
|
2020-02-21 01:40:49 +00:00
|
|
|
MPASS(vp != NULL);
|
2008-07-31 16:57:41 +00:00
|
|
|
/*
|
|
|
|
* NB: We require that the supplied array be at least MAXPATHLEN bytes
|
|
|
|
* long. If this is not the case, then we can run into serious trouble.
|
|
|
|
*/
|
|
|
|
(void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
|
|
|
|
/*
|
|
|
|
* Strip leading forward slashes.
|
2020-02-21 01:40:20 +00:00
|
|
|
*
|
|
|
|
* Note this does nothing to fully canonicalize the path.
|
2008-07-31 16:57:41 +00:00
|
|
|
*/
|
|
|
|
while (*copy == '/')
|
|
|
|
copy++;
|
|
|
|
/*
|
|
|
|
* Make sure we handle chroot(2) and prepend the global path to these
|
|
|
|
* environments.
|
|
|
|
*
|
|
|
|
* NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
|
|
|
|
* on Darwin. As a result, this may need some additional attention
|
|
|
|
* in the future.
|
|
|
|
*/
|
2020-08-24 08:57:02 +00:00
|
|
|
error = vn_fullpath_global(vp, &rbuf, &fbuf);
|
2020-02-21 01:40:20 +00:00
|
|
|
if (error) {
|
|
|
|
cpath[0] = '\0';
|
|
|
|
return;
|
2008-07-31 16:57:41 +00:00
|
|
|
}
|
2020-02-21 01:40:20 +00:00
|
|
|
(void) sbuf_cat(&sbf, rbuf);
|
|
|
|
/*
|
|
|
|
* We are going to concatenate the resolved path with the passed path
|
|
|
|
* with all slashes removed and we want them glued with a single slash.
|
|
|
|
* However, if the directory is /, the slash is already there.
|
|
|
|
*/
|
|
|
|
if (rbuf[1] != '\0')
|
2008-08-24 03:12:17 +00:00
|
|
|
(void) sbuf_putc(&sbf, '/');
|
2020-02-21 01:40:20 +00:00
|
|
|
free(fbuf, M_TEMP);
|
2008-07-31 16:57:41 +00:00
|
|
|
/*
|
|
|
|
* Now that we have processed any alternate root and relative path
|
|
|
|
* names, add the supplied pathname.
|
|
|
|
*/
|
2020-02-21 01:40:20 +00:00
|
|
|
(void) sbuf_cat(&sbf, copy);
|
2008-07-31 16:57:41 +00:00
|
|
|
/*
|
|
|
|
* One or more of the previous sbuf operations could have resulted in
|
|
|
|
* the supplied buffer being overflowed. Check to see if this is the
|
|
|
|
* case.
|
|
|
|
*/
|
2010-09-10 16:42:16 +00:00
|
|
|
if (sbuf_error(&sbf) != 0) {
|
2008-07-31 16:57:41 +00:00
|
|
|
cpath[0] = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sbuf_finish(&sbf);
|
2006-02-01 20:01:18 +00:00
|
|
|
}
|
2020-02-21 01:40:49 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
audit_canon_path(struct thread *td, int dirfd, char *path, char *cpath)
|
|
|
|
{
|
|
|
|
struct vnode *cdir, *rdir;
|
2020-03-01 21:53:46 +00:00
|
|
|
struct pwd *pwd;
|
2020-02-21 01:40:49 +00:00
|
|
|
cap_rights_t rights;
|
|
|
|
int error;
|
2020-03-01 21:53:46 +00:00
|
|
|
bool vrele_cdir;
|
2020-02-21 01:40:49 +00:00
|
|
|
|
|
|
|
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
|
|
|
|
__func__, __FILE__, __LINE__);
|
|
|
|
|
2020-03-01 21:53:46 +00:00
|
|
|
pwd = pwd_hold(td);
|
|
|
|
rdir = pwd->pwd_rdir;
|
|
|
|
cdir = NULL;
|
|
|
|
vrele_cdir = false;
|
|
|
|
if (*path != '/') {
|
2020-02-21 01:40:49 +00:00
|
|
|
if (dirfd == AT_FDCWD) {
|
2020-03-01 21:53:46 +00:00
|
|
|
cdir = pwd->pwd_cdir;
|
2020-02-21 01:40:49 +00:00
|
|
|
} else {
|
|
|
|
error = fgetvp(td, dirfd, cap_rights_init(&rights), &cdir);
|
|
|
|
if (error != 0) {
|
|
|
|
cpath[0] = '\0';
|
2020-03-01 21:53:46 +00:00
|
|
|
pwd_drop(pwd);
|
2020-02-21 01:40:49 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-03-01 21:53:46 +00:00
|
|
|
vrele_cdir = true;
|
2020-02-21 01:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
audit_canon_path_vp(td, rdir, cdir, path, cpath);
|
|
|
|
|
2020-03-01 21:53:46 +00:00
|
|
|
pwd_drop(pwd);
|
|
|
|
if (vrele_cdir)
|
2020-02-21 01:40:49 +00:00
|
|
|
vrele(cdir);
|
|
|
|
}
|