2020-06-27 15:19:46

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 00/11] add support for audit container identifier

Add support for audit kernel container identifiers to userspace tools.

The first and second add new record types. The third adds filter
support. The fourth and 5th start to add search support.

The 6th is to read the calling process' audit container identifier from
the /proc filesystem matching the kernel /proc read patch.

The 7th is to fix signal support and the 8th is to learn the audit
container identifier of the process that signals the audit daemon.

The 9th is a touch up to allow the contid field to be interpreted as a
CSV list.

The 10th adds audit contid list support to ausearch.

The last adds audit library support to allow a process to give
permission to a container orchestrator in a non-init user namespace via
audit netlink messages.

See: https://github.com/linux-audit/audit-userspace/issues/51
See: https://github.com/linux-audit/audit-userspace/issues/40
See: https://github.com/linux-audit/audit-kernel/issues/90
See: https://github.com/linux-audit/audit-kernel/issues/91
See: https://github.com/linux-audit/audit-testsuite/issues/64
https://githu.com/linux-audit/audit-testsuite/pull/91
https://github.com/rgbriggs/audit-testsuite/tree/ghat64-contid
See: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID

A repo of the code is here:
[email protected]:rgbriggs/audit-userspace.git ghau40-containerid-filter.v9
And test rpms built from it are here:
people.redhat.com/~rbriggs/ghak90/git-8277e93-fc32

Changelog:
v9
- accept a contid list for sig_info2
- bump AUDIT_CONTAINER_ID to 1336 to accommodate AUDIT_EVENT_LISTENER
- fix logical result reversal in audit_signal_info_has_ctx()
- fix event_contid clist declaration, fix comment about CONTAINER_OP/ID old-/contid CSV
- add SET_CAPCONTID to lib/netlink.c adjust_reply() and check_events()
- rebase on ghak28 parser
- rebase on ghak25 parser
- rebase on ghau86 fix
- in auparse/interpret.c:print_contid() also detect "-1"
- remove patches to limit nesting depth and netns count
- whitespace fixes
- squash clist into slist
- simplify audit_[sg]et_capcontid()

v8
- renumber contid records and drop netlink contid set/get support
- remove subject attributes from parse_container_op()
- fix audit_request_signal_info.3 manpage
- add manpage for audit_set_capcontid()
- implement clist for contid list search
- rebase on audit_bpf patches (bump CONTAINER_ID to 1335)
- implement control for audit container identifier nesting depth limit with manpage
- implent control for audit container identifier netns count limit with manpage

v7
- rebase on ghau90 and touchup
- rebase on ghak10 support (change AUDIT_CONTAINER_ID to 1334)
- render type contid as a CSV
- switch from /proc to audit netlink to set/get contid, auid/sessionid
- add support for capcontid

v6
- auditd signaller tracking was moved to a new AUDIT_SIGNAL_INFO2
request and record
- swap CONTAINER_OP contid/old-contid to ease parsing
- add to auparse

v5
- updated aux record from AUDIT_CONTAINER to AUDIT_CONTAINER_ID
- add AUDIT_CONTAINER_ID to normalization
- rebase on AUDIT_ANOM_LINK and AUDIT_MAC_CALIPSO_ADD

v4
- change from AUDIT_CONTAINER_ID to AUDIT_CONTAINER_OP
- change from AUDIT_FEATURE_BITMAP_CONTAINERID_FILTER to
AUDIT_FEATURE_BITMAP_CONTAINERID
- change from event_container_id to event_contid internally
- change from container_id to contid and event_container_id to
event_contid internally
- change command line option from --container-id to --contid

v3
- change from AUDIT_CONTAINER to AUDIT_CONTAINER_ID
- change from AUDIT_CONTAINER_INFO to AUDIT_CONTAINER
- change from AUDIT_CONTAINERID to AUDIT_CONTID
- update github issue refs
- add audit_get_containerid
- change event_container_id default value
- add --containerid to ausearch options help text
- update ausearch parser and error codes

v2
- rebase on UINT_MAX patch
- add patches for AUDIT_CONTAINER, AUDIT_CONTAINER_INFO, ausearch,
normalization

Richard Guy Briggs (11):
AUDIT_CONTAINER_OP message type basic support
AUDIT_CONTAINER_ID message type basic support
auditctl: add support for AUDIT_CONTID filter
add ausearch containerid support
start normalization containerid support
libaudit: add support to get the task audit container identifier
signal_info: only print context if it is available.
add support for audit_signal_info2
contid: interpret correctly CONTAINER_ID contid field csv
ausearch: convert contid to comma-sep/carrat-mod cnode/clist
libaudit: add support to get and set capcontid on a task

auparse/auditd-config.c | 1 +
auparse/auparse-defs.h | 3 +-
auparse/interpret.c | 10 +++
auparse/normalize.c | 1 +
auparse/normalize_record_map.h | 3 +
auparse/typetab.h | 2 +
bindings/python/auparse_python.c | 1 +
docs/Makefile.am | 3 +-
docs/audit_get_capcontid.3 | 25 ++++++
docs/audit_get_containerid.3 | 25 ++++++
docs/audit_request_signal_info.3 | 15 +++-
docs/audit_set_capcontid.3 | 24 +++++
docs/auditctl.8 | 3 +
lib/fieldtab.h | 1 +
lib/libaudit.c | 188 +++++++++++++++++++++++++++++++++++++--
lib/libaudit.h | 36 +++++++-
lib/msg_typetab.h | 4 +
lib/netlink.c | 6 ++
src/Makefile.am | 6 +-
src/auditctl-listing.c | 21 +++++
src/auditd-config.c | 1 +
src/auditd-config.h | 1 +
src/auditd-event.c | 28 ++++--
src/auditd-reconfig.c | 27 ++++--
src/auditd.c | 4 +-
src/aureport-options.c | 2 +
src/ausearch-contid.c | 172 +++++++++++++++++++++++++++++++++++
src/ausearch-contid.h | 60 +++++++++++++
src/ausearch-llist.c | 6 ++
src/ausearch-llist.h | 2 +
src/ausearch-lol.c | 4 +
src/ausearch-match.c | 35 ++++++++
src/ausearch-options.c | 78 +++++++++++++++-
src/ausearch-options.h | 2 +
src/ausearch-parse.c | 124 ++++++++++++++++++++++++++
src/ausearch-report.c | 6 +-
36 files changed, 898 insertions(+), 32 deletions(-)
create mode 100644 docs/audit_get_capcontid.3
create mode 100644 docs/audit_get_containerid.3
create mode 100644 docs/audit_set_capcontid.3
create mode 100644 src/ausearch-contid.c
create mode 100644 src/ausearch-contid.h

--
1.8.3.1


2020-06-27 15:20:07

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 01/11] AUDIT_CONTAINER_OP message type basic support

This defines the message number for the audit container identifier
registration record should the kernel headers not be up to date, gives
the record number a name for printing and allows the record to be
interpreted since it is in the 1000 range like AUDIT_LOGIN.

See: https://github.com/linux-audit/audit-userspace/issues/51
See: https://github.com/linux-audit/audit-kernel/issues/90
See: https://github.com/linux-audit/audit-testsuite/issues/64
See: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID
Signed-off-by: Richard Guy Briggs <[email protected]>
---
lib/libaudit.h | 4 ++++
lib/msg_typetab.h | 1 +
lib/netlink.c | 1 +
src/ausearch-lol.c | 2 ++
4 files changed, 8 insertions(+)

diff --git a/lib/libaudit.h b/lib/libaudit.h
index c3a8e4ddb65c..da7c61cc2e6d 100644
--- a/lib/libaudit.h
+++ b/lib/libaudit.h
@@ -246,6 +246,10 @@ extern "C" {
#define AUDIT_GET_FEATURE 1019 /* Get which features are enabled */
#endif

+#ifndef AUDIT_CONTAINER_OP
+#define AUDIT_CONTAINER_OP 1020 /* Container creation notice */
+#endif
+
#ifndef AUDIT_MMAP
#define AUDIT_MMAP 1323 /* Descriptor and flags in mmap */
#endif
diff --git a/lib/msg_typetab.h b/lib/msg_typetab.h
index 35127709c039..881f440c9d32 100644
--- a/lib/msg_typetab.h
+++ b/lib/msg_typetab.h
@@ -44,6 +44,7 @@ _S(AUDIT_LOGIN, "LOGIN" )
//_S(AUDIT_TTY_SET, "TTY_SET" )
//_S(AUDIT_SET_FEATURE, "SET_FEATURE" )
//_S(AUDIT_GET_FEATURE, "GET_FEATURE" )
+_S(AUDIT_CONTAINER_OP, "CONTAINER_OP" )
_S(AUDIT_USER_AUTH, "USER_AUTH" )
_S(AUDIT_USER_ACCT, "USER_ACCT" )
_S(AUDIT_USER_MGMT, "USER_MGMT" )
diff --git a/lib/netlink.c b/lib/netlink.c
index 5b2028fda7e8..caa963b1ddb2 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -184,6 +184,7 @@ static int adjust_reply(struct audit_reply *rep, int len)
break;
case AUDIT_USER:
case AUDIT_LOGIN:
+ case AUDIT_CONTAINER_OP:
case AUDIT_KERNEL:
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
diff --git a/src/ausearch-lol.c b/src/ausearch-lol.c
index f0f36e04dd93..05fe80fe3ad6 100644
--- a/src/ausearch-lol.c
+++ b/src/ausearch-lol.c
@@ -248,6 +248,8 @@ static void check_events(lol *lo, time_t sec)
ready++;
} else if ( cur->l->e.type < AUDIT_LOGIN ||
(cur->l->e.type > AUDIT_LOGIN &&
+ cur->l->e.type < AUDIT_CONTAINER_OP ) ||
+ (cur->l->e.type > AUDIT_CONTAINER_OP &&
cur->l->e.type < AUDIT_FIRST_EVENT ) ||
cur->l->e.type == AUDIT_PROCTITLE ||
(cur->l->e.type >= AUDIT_MAC_UNLBL_ALLOW &&
--
1.8.3.1

2020-06-27 15:20:15

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 04/11] add ausearch containerid support

Add support to ausearch for searching on the containerid field in
records.

Signed-off-by: Richard Guy Briggs <[email protected]>
---
src/aureport-options.c | 1 +
src/ausearch-llist.c | 2 ++
src/ausearch-llist.h | 1 +
src/ausearch-match.c | 3 +++
src/ausearch-options.c | 48 +++++++++++++++++++++++++++++++++++++++++-
src/ausearch-options.h | 1 +
src/ausearch-parse.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/src/aureport-options.c b/src/aureport-options.c
index bd847d7d57f0..29d267f2d1cb 100644
--- a/src/aureport-options.c
+++ b/src/aureport-options.c
@@ -62,6 +62,7 @@ const char *event_vmname = NULL;
long long event_exit = 0;
int event_exit_is_set = 0;
int event_ppid = -1, event_session_id = -2;
+unsigned long long event_contid = -1;
int event_debug = 0, event_machine = -1;

/* These are used by aureport */
diff --git a/src/ausearch-llist.c b/src/ausearch-llist.c
index ef5503c34fd9..ade727a9e102 100644
--- a/src/ausearch-llist.c
+++ b/src/ausearch-llist.c
@@ -60,6 +60,7 @@ void list_create(llist *l)
l->s.arch = 0;
l->s.syscall = 0;
l->s.session_id = -2;
+ l->s.contid = -1;
l->s.uuid = NULL;
l->s.vmname = NULL;
l->s.tuid = NULL;
@@ -211,6 +212,7 @@ void list_clear(llist* l)
l->s.arch = 0;
l->s.syscall = 0;
l->s.session_id = -2;
+ l->s.contid = -1;
free(l->s.uuid);
l->s.uuid = NULL;
free(l->s.vmname);
diff --git a/src/ausearch-llist.h b/src/ausearch-llist.h
index 64e4ee1f3694..2d1f52237ce6 100644
--- a/src/ausearch-llist.h
+++ b/src/ausearch-llist.h
@@ -56,6 +56,7 @@ typedef struct
int arch; // arch
int syscall; // syscall
uint32_t session_id; // Login session id
+ __u64 contid; // Container id
long long exit; // Syscall exit code
int exit_is_set; // Syscall exit code is valid
char *hostname; // remote hostname
diff --git a/src/ausearch-match.c b/src/ausearch-match.c
index 61a11d30a09b..47c12581a963 100644
--- a/src/ausearch-match.c
+++ b/src/ausearch-match.c
@@ -113,6 +113,9 @@ int match(llist *l)
if ((event_session_id != -2) &&
(event_session_id != l->s.session_id))
return 0;
+ if ((event_contid != -1) &&
+ (event_contid != l->s.contid))
+ return 0;
if (event_exit_is_set) {
if (l->s.exit_is_set == 0)
return 0;
diff --git a/src/ausearch-options.c b/src/ausearch-options.c
index 5363fdace73c..b45793e88109 100644
--- a/src/ausearch-options.c
+++ b/src/ausearch-options.c
@@ -60,6 +60,7 @@ int event_syscall = -1, event_machine = -1;
int event_ua = 0, event_ga = 0, event_se = 0;
int just_one = 0;
uint32_t event_session_id = -2;
+unsigned long long event_contid = -1;
long long event_exit = 0;
int event_exit_is_set = 0;
int line_buffered = 0;
@@ -92,7 +93,7 @@ S_TIME_END, S_TIME_START, S_TERMINAL, S_ALL_UID, S_EFF_UID, S_UID, S_LOGINID,
S_VERSION, S_EXACT_MATCH, S_EXECUTABLE, S_CONTEXT, S_SUBJECT, S_OBJECT,
S_PPID, S_KEY, S_RAW, S_NODE, S_IN_LOGS, S_JUST_ONE, S_SESSION, S_EXIT,
S_LINEBUFFERED, S_UUID, S_VMNAME, S_DEBUG, S_CHECKPOINT, S_ARCH, S_FORMAT,
-S_EXTRA_TIME, S_EXTRA_LABELS, S_EXTRA_KEYS, S_EXTRA_OBJ2, S_ESCAPE };
+S_EXTRA_TIME, S_EXTRA_LABELS, S_EXTRA_KEYS, S_EXTRA_OBJ2, S_ESCAPE, S_CONTID };

static struct nv_pair optiontab[] = {
{ S_EVENT, "-a" },
@@ -100,6 +101,7 @@ static struct nv_pair optiontab[] = {
{ S_EVENT, "--event" },
{ S_COMM, "-c" },
{ S_COMM, "--comm" },
+ { S_CONTID, "--contid" },
{ S_CHECKPOINT, "--checkpoint" },
{ S_DEBUG, "--debug" },
{ S_EXIT, "-e" },
@@ -197,6 +199,7 @@ static void usage(void)
"\t-a,--event <Audit event id>\tsearch based on audit event id\n"
"\t--arch <CPU>\t\t\tsearch based on the CPU architecture\n"
"\t-c,--comm <Comm name>\t\tsearch based on command line name\n"
+ "\t--contid <audit container id>\tsearch based on the task's audit container id\n"
"\t--checkpoint <checkpoint file>\tsearch from last complete event\n"
"\t--debug\t\t\tWrite malformed events that are skipped to stderr\n"
"\t-e,--exit <Exit code or errno>\tsearch based on syscall exit code\n"
@@ -1182,6 +1185,49 @@ int check_params(int count, char *vars[])
}
c++;
break;
+ case S_CONTID:
+ if (!optarg) {
+ if ((c+1 < count) && vars[c+1])
+ optarg = vars[c+1];
+ else {
+ fprintf(stderr,
+ "Argument is required for %s\n",
+ vars[c]);
+ retval = -1;
+ break;
+ }
+ }
+ {
+ size_t len = strlen(optarg);
+
+ if (isdigit(optarg[0])) {
+ errno = 0;
+ event_contid = strtoull(optarg, NULL, 0);
+ if (errno) {
+ fprintf(stderr,
+ "Numeric container ID conversion error (%s) for %s\n",
+ strerror(errno), optarg);
+ retval = -1;
+ }
+ } else if (len >= 2 && *(optarg) == '-' &&
+ (isdigit(optarg[1]))) {
+ errno = 0;
+ event_contid = strtoll(optarg, NULL, 0);
+ if (errno) {
+ retval = -1;
+ fprintf(stderr, "Error converting %s\n",
+ optarg);
+ }
+ } else {
+ fprintf(stderr,
+ "Container ID is non-numeric and unknown (%s)\n",
+ optarg);
+ retval = -1;
+ break;
+ }
+ }
+ c++;
+ break;
case S_UUID:
if (!optarg) {
fprintf(stderr,
diff --git a/src/ausearch-options.h b/src/ausearch-options.h
index 1372762b4b3e..085d492d101c 100644
--- a/src/ausearch-options.h
+++ b/src/ausearch-options.h
@@ -40,6 +40,7 @@ extern int line_buffered;
extern int event_debug;
extern pid_t event_ppid;
extern uint32_t event_session_id;
+extern unsigned long long event_contid;
extern ilist *event_type;

/* Data type to govern output format */
diff --git a/src/ausearch-parse.c b/src/ausearch-parse.c
index 5cd24e8bd7cb..374b369be7b7 100644
--- a/src/ausearch-parse.c
+++ b/src/ausearch-parse.c
@@ -53,6 +53,8 @@ static int parse_path(const lnode *n, search_items *s);
static int parse_user(const lnode *n, search_items *s, anode *avc);
static int parse_obj(const lnode *n, search_items *s);
static int parse_login(const lnode *n, search_items *s);
+static int parse_container_op(const lnode *n, search_items *s);
+static int parse_container_id(const lnode *n, search_items *s);
static int parse_daemon1(const lnode *n, search_items *s);
static int parse_daemon2(const lnode *n, search_items *s);
static int parse_sockaddr(const lnode *n, search_items *s);
@@ -115,6 +117,9 @@ int extract_search_items(llist *l)
case AUDIT_LOGIN:
ret = parse_login(n, s);
break;
+ case AUDIT_CONTAINER_OP:
+ ret = parse_container_op(n, s);
+ break;
case AUDIT_IPC:
case AUDIT_OBJ_PID:
ret = parse_obj(n, s);
@@ -184,6 +189,9 @@ int extract_search_items(llist *l)
case AUDIT_TTY:
ret = parse_tty(n, s);
break;
+ case AUDIT_CONTAINER_ID:
+ ret = parse_container_id(n, s);
+ break;
default:
if (event_debug)
fprintf(stderr,
@@ -1474,6 +1482,55 @@ static int parse_login(const lnode *n, search_items *s)
return 0;
}

+static int parse_container_op(const lnode *n, search_items *s)
+{
+ char *ptr, *str, *term = n->message;
+
+ // skip op
+ // skip opid
+ // get contid
+ if (event_contid != -1) {
+ str = strstr(term, "contid=");
+ if (str == NULL)
+ return 46;
+ ptr = str + 7;
+ term = strchr(ptr, ' ');
+ if (term == NULL)
+ return 47;
+ *term = 0;
+ errno = 0;
+ s->contid = strtoull(ptr, NULL, 10);
+ if (errno)
+ return 48;
+ *term = ' ';
+ }
+ // skip old-contid
+ return 0;
+}
+
+static int parse_container_id(const lnode *n, search_items *s)
+{
+ char *ptr, *str, *term = n->message;
+
+ // get contid
+ if (event_contid != -1) {
+ str = strstr(term, "contid=");
+ if (str == NULL)
+ return 49;
+ ptr = str + 7;
+ term = strchr(ptr, ' ');
+ if (term)
+ return 50;
+ *term = 0;
+ errno = 0;
+ s->contid = strtoull(ptr, NULL, 10);
+ if (errno)
+ return 51;
+ *term = ' ';
+ }
+ return 0;
+}
+
static int parse_daemon1(const lnode *n, search_items *s)
{
char *ptr, *str, *term, saved, *mptr;
--
1.8.3.1

2020-06-27 15:20:28

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 05/11] start normalization containerid support

Signed-off-by: Richard Guy Briggs <[email protected]>
---
auparse/auparse-defs.h | 3 ++-
auparse/interpret.c | 10 ++++++++++
auparse/normalize_record_map.h | 2 ++
auparse/typetab.h | 2 ++
bindings/python/auparse_python.c | 1 +
5 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/auparse/auparse-defs.h b/auparse/auparse-defs.h
index 27bfa943612c..a9b144df3462 100644
--- a/auparse/auparse-defs.h
+++ b/auparse/auparse-defs.h
@@ -87,7 +87,8 @@ typedef enum { AUPARSE_TYPE_UNCLASSIFIED, AUPARSE_TYPE_UID, AUPARSE_TYPE_GID,
AUPARSE_TYPE_PROCTITLE, AUPARSE_TYPE_HOOK,
AUPARSE_TYPE_NETACTION, AUPARSE_TYPE_MACPROTO,
AUPARSE_TYPE_IOCTL_REQ, AUPARSE_TYPE_ESCAPED_KEY,
- AUPARSE_TYPE_ESCAPED_FILE, AUPARSE_TYPE_FANOTIFY } auparse_type_t;
+ AUPARSE_TYPE_ESCAPED_FILE, AUPARSE_TYPE_FANOTIFY, AUPARSE_TYPE_CONTID
+} auparse_type_t;

/* This type determines what escaping if any gets applied to interpreted fields */
typedef enum { AUPARSE_ESC_RAW, AUPARSE_ESC_TTY, AUPARSE_ESC_SHELL,
diff --git a/auparse/interpret.c b/auparse/interpret.c
index e23c3533877b..14fcc72148c8 100644
--- a/auparse/interpret.c
+++ b/auparse/interpret.c
@@ -2843,6 +2843,13 @@ static const char *print_seccomp_code(const char *val)
return out;
}

+static const char *print_contid(const char *val)
+{
+ if (strcmp(val, "18446744073709551615") == 0 || strcmp(val, "-1") == 0)
+ return strdup("unset");
+ return strdup(val);
+}
+
int lookup_type(const char *name)
{
int i;
@@ -3083,6 +3090,9 @@ unknown:
case AUPARSE_TYPE_FANOTIFY:
out = print_fanotify(id->val);
break;
+ case AUPARSE_TYPE_CONTID:
+ out = print_contid(id->val);
+ break;
case AUPARSE_TYPE_MAC_LABEL:
case AUPARSE_TYPE_UNCLASSIFIED:
default:
diff --git a/auparse/normalize_record_map.h b/auparse/normalize_record_map.h
index fee778e76db7..7332249c7b34 100644
--- a/auparse/normalize_record_map.h
+++ b/auparse/normalize_record_map.h
@@ -25,6 +25,7 @@

_S(AUDIT_USER, "sent-message")
_S(AUDIT_LOGIN, "changed-login-id-to")
+_S(AUDIT_CONTAINER_OP, "changed-container-id-to")
_S(AUDIT_USER_AUTH, "authenticated")
_S(AUDIT_USER_ACCT, "was-authorized")
_S(AUDIT_USER_MGMT, "modified-user-account")
@@ -84,6 +85,7 @@ _S(AUDIT_FEATURE_CHANGE, "changed-audit-feature")
//_S(AUDIT_REPLACE,"")
_S(AUDIT_KERN_MODULE, "loaded-kernel-module")
_S(AUDIT_FANOTIFY, "accessed-policy-controlled-file")
+_S(AUDIT_CONTAINER_ID, "has-container-id")
_S(AUDIT_AVC, "accessed-mac-policy-controlled-object")
_S(AUDIT_MAC_POLICY_LOAD, "loaded-selinux-policy")
_S(AUDIT_MAC_STATUS, "changed-selinux-enforcement-to")
diff --git a/auparse/typetab.h b/auparse/typetab.h
index 0391e87f731c..0c160bb56c3b 100644
--- a/auparse/typetab.h
+++ b/auparse/typetab.h
@@ -142,3 +142,5 @@ _S(AUPARSE_TYPE_IOCTL_REQ, "ioctlcmd" )
_S(AUPARSE_TYPE_FANOTIFY, "resp" )
_S(AUPARSE_TYPE_ESCAPED, "sw" )
_S(AUPARSE_TYPE_ESCAPED, "root_dir" )
+_S(AUPARSE_TYPE_CONTID, "contid" )
+_S(AUPARSE_TYPE_CONTID, "old-contid" )
diff --git a/bindings/python/auparse_python.c b/bindings/python/auparse_python.c
index 1ba59cf78527..947d018cf594 100644
--- a/bindings/python/auparse_python.c
+++ b/bindings/python/auparse_python.c
@@ -2376,6 +2376,7 @@ initauparse(void)
PyModule_AddIntConstant(m, "AUPARSE_ESC_TTY", AUPARSE_ESC_TTY);
PyModule_AddIntConstant(m, "AUPARSE_ESC_SHELL", AUPARSE_ESC_SHELL);
PyModule_AddIntConstant(m, "AUPARSE_ESC_SHELL_QUOTE", AUPARSE_ESC_SHELL_QUOTE);
+ PyModule_AddIntConstant(m, "AUPARSE_TYPE_CONTID", AUPARSE_TYPE_CONTID);

#ifdef IS_PY3K
return m;
--
1.8.3.1

2020-06-27 15:20:48

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 06/11] libaudit: add support to get the task audit container identifier

Add the audit_get_containerid() call analogous to audit_getloginuid()
and audit_get_session() calls to get our own audit container identifier.

This is intended as a debug patch, not to be upstreamed.

Signed-off-by: Richard Guy Briggs <[email protected]>
---
docs/Makefile.am | 2 +-
docs/audit_get_containerid.3 | 25 +++++++++++++++++++++++++
lib/libaudit.c | 29 +++++++++++++++++++++++++++++
lib/libaudit.h | 1 +
4 files changed, 56 insertions(+), 1 deletion(-)
create mode 100644 docs/audit_get_containerid.3

diff --git a/docs/Makefile.am b/docs/Makefile.am
index 8fb030c6e5e4..209789bb2051 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -28,7 +28,7 @@ man_MANS = audit_add_rule_data.3 audit_add_watch.3 auditctl.8 auditd.8 \
auditd.conf.5 auditd-plugins.5 \
audit_delete_rule_data.3 audit_detect_machine.3 \
audit_encode_nv_string.3 audit_getloginuid.3 \
-audit_get_reply.3 audit_get_session.3 \
+audit_get_reply.3 audit_get_session.3 audit_get_containerid.3 \
audit_log_acct_message.3 audit_log_user_avc_message.3 \
audit_log_user_command.3 audit_log_user_comm_message.3 \
audit_log_user_message.3 audit_log_semanage_message.3 \
diff --git a/docs/audit_get_containerid.3 b/docs/audit_get_containerid.3
new file mode 100644
index 000000000000..ef62a25db970
--- /dev/null
+++ b/docs/audit_get_containerid.3
@@ -0,0 +1,25 @@
+.TH "AUDIT_GET_CONTAINERID" "3" "Feb 2018" "Red Hat" "Linux Audit API"
+.SH NAME
+audit_get_containerid \- Get a program's container id value
+.SH SYNOPSIS
+.B #include <libaudit.h>
+.sp
+uin64_t audit_get_containerid(void);
+
+.SH DESCRIPTION
+This function returns the task's audit container identifier attribute.
+
+.SH "RETURN VALUE"
+
+This function returns the audit container identifier value if it was set. It will return a \-1 if the audit container identifier is unset. However, since uint64_t is an unsigned type, you will see the converted value instead of \-1.
+
+.SH "ERRORS"
+
+This function returns \-2 on failure. Additionally, in the event of a real error, errno would be set. The function can set errno based on failures of open, read, or strtoull.
+
+.SH "SEE ALSO"
+
+.BR audit_getloginuid (3).
+
+.SH AUTHOR
+Richard Guy Briggs
diff --git a/lib/libaudit.c b/lib/libaudit.c
index 2e7b18a70eb8..e64bc4628da4 100644
--- a/lib/libaudit.c
+++ b/lib/libaudit.c
@@ -951,6 +951,35 @@ uint32_t audit_get_session(void)
return ses;
}

+/*
+ * This function will retrieve the audit container identifier or -2 if
+ * there is an error.
+ */
+uint64_t audit_get_containerid(void)
+{
+ uint64_t containerid;
+ int len, in;
+ char buf[32];
+
+ errno = 0;
+ in = open("/proc/self/audit_containerid", O_NOFOLLOW|O_RDONLY);
+ if (in < 0)
+ return -2;
+ do {
+ len = read(in, buf, sizeof(buf));
+ } while (len < 0 && errno == EINTR);
+ close(in);
+ if (len < 0 || len >= sizeof(buf))
+ return -2;
+ buf[len] = 0;
+ errno = 0;
+ containerid = strtoull(buf, 0, 10);
+ if (errno)
+ return -2;
+ else
+ return containerid;
+}
+
int audit_rule_syscall_data(struct audit_rule_data *rule, int scall)
{
int word = AUDIT_WORD(scall);
diff --git a/lib/libaudit.h b/lib/libaudit.h
index a249463a0888..ec171e4d08f3 100644
--- a/lib/libaudit.h
+++ b/lib/libaudit.h
@@ -601,6 +601,7 @@ extern int audit_get_reply(int fd, struct audit_reply *rep, reply_t block,
extern uid_t audit_getloginuid(void);
extern int audit_setloginuid(uid_t uid);
extern uint32_t audit_get_session(void);
+extern uint64_t audit_get_containerid(void);
extern int audit_detect_machine(void);
extern int audit_determine_machine(const char *arch);
extern char *audit_format_signal_info(char *buf, int len, char *op, struct audit_reply *rep, char *res);
--
1.8.3.1

2020-06-27 15:20:58

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 07/11] signal_info: only print context if it is available.

Signed-off-by: Richard Guy Briggs <[email protected]>
---
src/auditd-event.c | 20 +++++++++++++++-----
src/auditd-reconfig.c | 2 --
2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/auditd-event.c b/src/auditd-event.c
index e6b2a961f02b..800f4d83bc83 100644
--- a/src/auditd-event.c
+++ b/src/auditd-event.c
@@ -1323,13 +1323,16 @@ static void reconfigure(struct auditd_event *e)
const char *ctx = nconf->sender_ctx;
struct timeval tv;
char txt[MAX_AUDIT_MESSAGE_LENGTH];
+ int txt_len;
char date[40];
unsigned int seq_num;
int need_size_check = 0, need_reopen = 0, need_space_check = 0;

- snprintf(txt, sizeof(txt),
- "config change requested by pid=%d auid=%u subj=%s",
- pid, uid, ctx);
+ txt_len = snprintf(txt, sizeof(txt),
+ "config change requested by pid=%d auid=%u", pid, uid);
+ if (ctx)
+ snprintf(txt + txt_len, sizeof(txt) - txt_len,
+ " subj=%s", ctx);
audit_msg(LOG_NOTICE, "%s", txt);

/* Do the reconfiguring. These are done in a specific
@@ -1578,8 +1581,15 @@ static void reconfigure(struct auditd_event *e)

e->reply.type = AUDIT_DAEMON_CONFIG;
e->reply.len = snprintf(e->reply.msg.data, MAX_AUDIT_MESSAGE_LENGTH-2,
- "%s: op=reconfigure state=changed auid=%u pid=%d subj=%s res=success",
- date, uid, pid, ctx );
+ "%s: op=reconfigure state=changed auid=%u pid=%d",
+ date, uid, pid);
+ if (ctx)
+ e->reply.len += snprintf(e->reply.msg.data + e->reply.len,
+ MAX_AUDIT_MESSAGE_LENGTH-2 - e->reply.len,
+ " subj=%s", ctx);
+ e->reply.len += snprintf(e->reply.msg.data + e->reply.len,
+ MAX_AUDIT_MESSAGE_LENGTH-2 - e->reply.len,
+ " res=success");
e->reply.message = e->reply.msg.data;
free((char *)ctx);
}
diff --git a/src/auditd-reconfig.c b/src/auditd-reconfig.c
index f5b00e6d1dc7..1af402526c4e 100644
--- a/src/auditd-reconfig.c
+++ b/src/auditd-reconfig.c
@@ -106,8 +106,6 @@ static void *config_thread_main(void *arg)
if (e->reply.len > 24)
new_config.sender_ctx =
strdup(e->reply.signal_info->ctx);
- else
- new_config.sender_ctx = strdup("?");
memcpy(e->reply.msg.data, &new_config, sizeof(new_config));
e->reply.conf = (struct daemon_conf *)e->reply.msg.data;
e->reply.type = AUDIT_DAEMON_RECONFIG;
--
1.8.3.1

2020-06-27 15:21:24

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 09/11] contid: interpret correctly CONTAINER_ID contid field csv

The CONTAINER_ID record contid field can contain comma-separated values
when accompanying a NETFILTER_PKT record. Records appeared interpreted
as such:

Wrong:
CONTAINER_ID msg=audit(2019-04-10 13:20:18.746:1690) : contid=777 666,333
Right:
CONTAINER_ID msg=audit(2019-04-10 13:20:18.746:1690) : contid=777,666,333

Signed-off-by: Richard Guy Briggs <[email protected]>
---
src/ausearch-report.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/ausearch-report.c b/src/ausearch-report.c
index 416c2b13fa6a..754b28af2cb6 100644
--- a/src/ausearch-report.c
+++ b/src/ausearch-report.c
@@ -279,7 +279,7 @@ no_print:
if (str && val && (str < val)) {
// Value side has commas and another field exists
// Known: LABEL_LEVEL_CHANGE banners=none,none
- // Known: ROLL_ASSIGN new-role=r,r
+ // Known: ROLE_ASSIGN new-role=r,r
// Known: any MAC LABEL can potentially have commas
int ftype = auparse_interp_adjust_type(n->type,
name, val);
@@ -293,9 +293,11 @@ no_print:
} else if (str && (val == NULL)) {
// Goes all the way to the end. Done parsing
// Known: MCS context in PATH rec obj=u:r:t:s0:c2,c7
+ // Known: CONTAINER_ID/OP old-/contid can be a comma-separated list
int ftype = auparse_interp_adjust_type(n->type,
name, ptr);
- if (ftype == AUPARSE_TYPE_MAC_LABEL)
+ if (ftype == AUPARSE_TYPE_MAC_LABEL
+ || ftype == AUPARSE_TYPE_CONTID)
str = NULL;
else {
*str++ = 0;
--
1.8.3.1

2020-06-27 15:21:54

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 03/11] auditctl: add support for AUDIT_CONTID filter

A u64 container identifier has been added to the kernel view of tasks.
This allows container orchestrators to label tasks with a unique
tamperproof identifier that gets inherited by its children to be able to
track the provenance of actions by a container.

Add support to libaudit and auditctl for the AUDIT_CONTID field to
filter based on audit container identifier. This field is specified
with the "contid" field name on the command line.

Since it is a u64 and larger than any other numeric field, send it as a
string but do the appropriate conversions on each end in each direction.

See: https://github.com/linux-audit/audit-userspace/issues/40
See: https://github.com/linux-audit/audit-kernel/issues/91
See: https://github.com/linux-audit/audit-testsuite/issues/64
See: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID
Signed-off-by: Richard Guy Briggs <[email protected]>
---
docs/auditctl.8 | 3 +++
lib/fieldtab.h | 1 +
lib/libaudit.c | 35 +++++++++++++++++++++++++++++++++++
lib/libaudit.h | 7 +++++++
src/auditctl-listing.c | 21 +++++++++++++++++++++
5 files changed, 67 insertions(+)

diff --git a/docs/auditctl.8 b/docs/auditctl.8
index 6606077c2c44..daed435f03af 100644
--- a/docs/auditctl.8
+++ b/docs/auditctl.8
@@ -216,6 +216,9 @@ Address family number as found in /usr/include/bits/socket.h. For example, IPv4
.B sessionid
User's login session ID
.TP
+.B contid
+Process' audit container ID
+.TP
.B subj_user
Program's SE Linux User
.TP
diff --git a/lib/fieldtab.h b/lib/fieldtab.h
index b597cafb2df8..e0a49d0154bb 100644
--- a/lib/fieldtab.h
+++ b/lib/fieldtab.h
@@ -47,6 +47,7 @@ _S(AUDIT_OBJ_TYPE, "obj_type" )
_S(AUDIT_OBJ_LEV_LOW, "obj_lev_low" )
_S(AUDIT_OBJ_LEV_HIGH, "obj_lev_high" )
_S(AUDIT_SESSIONID, "sessionid" )
+_S(AUDIT_CONTID, "contid" )

_S(AUDIT_DEVMAJOR, "devmajor" )
_S(AUDIT_DEVMINOR, "devminor" )
diff --git a/lib/libaudit.c b/lib/libaudit.c
index 864821e5e615..2e7b18a70eb8 100644
--- a/lib/libaudit.c
+++ b/lib/libaudit.c
@@ -1763,6 +1763,41 @@ int audit_rule_fieldpair_data(struct audit_rule_data **rulep, const char *pair,
if (rule->values[rule->field_count] >= AF_MAX)
return -EAU_FIELDVALTOOBIG;
break;
+ case AUDIT_CONTID: {
+ unsigned long long val;
+
+ if ((audit_get_features() &
+ AUDIT_FEATURE_BITMAP_CONTAINERID) == 0)
+ return -EAU_FIELDNOSUPPORT;
+ if (flags != AUDIT_FILTER_EXCLUDE &&
+ flags != AUDIT_FILTER_USER &&
+ flags != AUDIT_FILTER_EXIT)
+ return -EAU_FIELDNOFILTER;
+ if (isdigit((char)*(v)))
+ val = strtoull(v, NULL, 0);
+ else if (strlen(v) >= 2 && *(v) == '-' &&
+ (isdigit((char)*(v+1))))
+ val = strtoll(v, NULL, 0);
+ else if (strcmp(v, "unset") == 0)
+ val = ULLONG_MAX;
+ else
+ return -EAU_FIELDVALNUM;
+ if (errno)
+ return -EAU_FIELDVALNUM;
+ vlen = sizeof(unsigned long long);
+ rule->values[rule->field_count] = vlen;
+ offset = rule->buflen;
+ rule->buflen += vlen;
+ *rulep = realloc(rule, sizeof(*rule) + rule->buflen);
+ if (*rulep == NULL) {
+ free(rule);
+ audit_msg(LOG_ERR, "Cannot realloc memory!\n");
+ return -3;
+ }
+ rule = *rulep;
+ *(unsigned long long *)(&rule->buf[offset]) = val;
+ break;
+ }
case AUDIT_DEVMAJOR...AUDIT_INODE:
case AUDIT_SUCCESS:
if (flags != AUDIT_FILTER_EXIT)
diff --git a/lib/libaudit.h b/lib/libaudit.h
index 9c2f6d4248b0..a249463a0888 100644
--- a/lib/libaudit.h
+++ b/lib/libaudit.h
@@ -362,6 +362,9 @@ extern "C" {
#ifndef AUDIT_FEATURE_BITMAP_FILTER_FS
#define AUDIT_FEATURE_BITMAP_FILTER_FS 0x00000040
#endif
+#ifndef AUDIT_FEATURE_BITMAP_CONTAINERID
+#define AUDIT_FEATURE_BITMAP_CONTAINERID 0x00000080
+#endif

/* Defines for interfield comparison update */
#ifndef AUDIT_OBJ_UID
@@ -388,6 +391,10 @@ extern "C" {
#define AUDIT_FSTYPE 26
#endif

+#ifndef AUDIT_CONTID
+#define AUDIT_CONTID 27
+#endif
+
#ifndef AUDIT_COMPARE_UID_TO_OBJ_UID
#define AUDIT_COMPARE_UID_TO_OBJ_UID 1
#endif
diff --git a/src/auditctl-listing.c b/src/auditctl-listing.c
index 6eb3b56bbc79..652867eb2c49 100644
--- a/src/auditctl-listing.c
+++ b/src/auditctl-listing.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include "auditctl-listing.h"
#include "private.h"
#include "auditctl-llist.h"
@@ -460,6 +461,26 @@ static void print_rule(const struct audit_rule_data *r)
audit_operator_to_symbol(op),
audit_fstype_to_name(
r->values[i]));
+ } else if (field == AUDIT_CONTID) {
+ unsigned long long val;
+
+ if (r->values[i] == sizeof(unsigned long long)) {
+ val = *(unsigned long long *)(&r->buf[boffset]);
+
+ if (val != ULLONG_MAX)
+ printf(" -F %s%s%llu", name,
+ audit_operator_to_symbol(op),
+ val);
+ else
+ printf(" -F %s%s%s", name,
+ audit_operator_to_symbol(op),
+ "unset");
+ } else {
+ printf(" -F %s%s%s", name,
+ audit_operator_to_symbol(op),
+ "inval");
+ }
+ boffset += r->values[i];
} else {
// The default is signed decimal
printf(" -F %s%s%d", name,
--
1.8.3.1

2020-06-27 15:23:16

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 08/11] add support for audit_signal_info2

Since a process in a container could potentially signal the audit daemon
(reconfig, terminate, roll log, resume), that audit container identifier
information should be made available to the audit daemon to report the
full provenance of the signal. It is not possible to add it to the
existing audit_signal_info struct without causing a kABI change.
Introduce a new audit message type AUDIT_SIGNAL_INFO2 using a new
audit_sig_info2 struct to be able to transfer this information from
kernel to userspace.

struct audit_sig_info2 {
uid_t uid;
pid_t pid;
uint64_t cid;
char ctx[];
};

Signed-off-by: Richard Guy Briggs <[email protected]>
---
auparse/auditd-config.c | 1 +
docs/audit_request_signal_info.3 | 15 ++++++++++-
lib/libaudit.c | 56 ++++++++++++++++++++++++++++++++++------
lib/libaudit.h | 16 +++++++++++-
lib/msg_typetab.h | 1 +
lib/netlink.c | 4 +++
src/auditd-config.c | 1 +
src/auditd-config.h | 1 +
src/auditd-event.c | 10 ++++++-
src/auditd-reconfig.c | 25 +++++++++++++-----
src/auditd.c | 4 ++-
11 files changed, 116 insertions(+), 18 deletions(-)

diff --git a/auparse/auditd-config.c b/auparse/auditd-config.c
index 59984b47bd5a..7a3ed33ffb4b 100644
--- a/auparse/auditd-config.c
+++ b/auparse/auditd-config.c
@@ -77,6 +77,7 @@ void clear_config(struct daemon_conf *config)
config->sender_uid = 0;
config->sender_pid = 0;
config->sender_ctx = NULL;
+ config->sender_cid = NULL;
config->write_logs = 1;
config->log_file = strdup("/var/log/audit/audit.log");
config->log_format = LF_RAW;
diff --git a/docs/audit_request_signal_info.3 b/docs/audit_request_signal_info.3
index b68d7bbefeed..90c5da5bcf7d 100644
--- a/docs/audit_request_signal_info.3
+++ b/docs/audit_request_signal_info.3
@@ -14,10 +14,23 @@ audit_request_signal_info requests that the kernel send information about the se
struct audit_sig_info {
uid_t uid;
pid_t pid;
- char ctx[0];
+ char ctx[];
};
.fi

+If the process has an audit container identifier, the signal info structure is as follows:
+
+.nf
+struct audit_sig_info2 {
+ uid_t uid;
+ pid_t pid;
+ uint32_t cid_len;
+ char data[];
+};
+.fi
+
+The data field contains first the audit container identifier list of length cid_len, followed by the SElinux context to the end of the structure.
+
This function is likely to be used only by audit daemons and shouldn't be called by any other kind of program.

.SH "RETURN VALUE"
diff --git a/lib/libaudit.c b/lib/libaudit.c
index e64bc4628da4..1a7fed76b9b0 100644
--- a/lib/libaudit.c
+++ b/lib/libaudit.c
@@ -25,6 +25,7 @@
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
@@ -667,7 +668,12 @@ int audit_request_rules_list_data(int fd)

int audit_request_signal_info(int fd)
{
- int rc = audit_send(fd, AUDIT_SIGNAL_INFO, NULL, 0);
+ int rc;
+
+ if (audit_get_containerid() == (uint64_t)-2)
+ rc = audit_send(fd, AUDIT_SIGNAL_INFO, NULL, 0);
+ else
+ rc = audit_send(fd, AUDIT_SIGNAL_INFO2, NULL, 0);
if (rc < 0)
audit_msg(LOG_WARNING,
"Error sending signal_info request (%s)",
@@ -675,16 +681,50 @@ int audit_request_signal_info(int fd)
return rc;
}

+bool audit_signal_info_has_ctx(struct audit_reply *rep)
+{
+ if (rep->type == AUDIT_SIGNAL_INFO) {
+ if (rep->len == 24)
+ return false;
+ } else {
+ if (rep->len == 24 + sizeof(uint32_t) + rep->signal_info2->cid_len)
+ return false;
+ }
+ return true;
+}
+
+#ifndef MIN
+#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
+#endif
char *audit_format_signal_info(char *buf, int len, char *op,
struct audit_reply *rep, char *res)
{
- if (rep->len == 24)
- snprintf(buf, len, "op=%s auid=%u pid=%d res=%s", op,
- rep->signal_info->uid, rep->signal_info->pid, res);
- else
- snprintf(buf, len, "op=%s auid=%u pid=%d subj=%s res=%s",
- op, rep->signal_info->uid, rep->signal_info->pid,
- rep->signal_info->ctx, res);
+ int c = 0;
+
+ if (rep->type == AUDIT_SIGNAL_INFO) {
+ c += snprintf(buf + c, len - c, "op=%s auid=%u pid=%d",
+ op,
+ rep->signal_info->uid,
+ rep->signal_info->pid);
+ if (audit_signal_info_has_ctx(rep))
+ c += snprintf(buf + c, len - c, " subj=%s",
+ rep->signal_info->ctx);
+ c += snprintf(buf + c, len - c, " res=%s", res);
+ } else {
+ c += snprintf(buf + c, len - c, "op=%s auid=%u pid=%d",
+ op,
+ rep->signal_info2->uid,
+ rep->signal_info2->pid);
+ if (audit_signal_info_has_ctx(rep))
+ c += snprintf(buf + c, len - c, " subj=%s",
+ rep->signal_info2->data +
+ rep->signal_info2->cid_len);
+ c += snprintf(buf + c, len - c, " res=%s", res);
+ if (rep->signal_info2->cid_len != 0)
+ c += snprintf(buf + c,
+ MIN(len - c, rep->signal_info2->cid_len),
+ " contid=%s", rep->signal_info2->data);
+ }
return buf;
}

diff --git a/lib/libaudit.h b/lib/libaudit.h
index ec171e4d08f3..f4e820e9b097 100644
--- a/lib/libaudit.h
+++ b/lib/libaudit.h
@@ -34,6 +34,7 @@ extern "C" {
#include <linux/netlink.h>
#include <linux/audit.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <syslog.h>


@@ -250,6 +251,10 @@ extern "C" {
#define AUDIT_CONTAINER_OP 1020 /* Container creation notice */
#endif

+#ifndef AUDIT_SIGNAL_INFO2
+#define AUDIT_SIGNAL_INFO2 1021 /* auditd signal sender info */
+#endif
+
#ifndef AUDIT_MMAP
#define AUDIT_MMAP 1323 /* Descriptor and flags in mmap */
#endif
@@ -499,7 +504,14 @@ extern "C" {
struct audit_sig_info {
uid_t uid;
pid_t pid;
- char ctx[0];
+ char ctx[];
+};
+
+struct audit_sig_info2 {
+ uid_t uid;
+ pid_t pid;
+ uint32_t cid_len;
+ char data[];
};

/* defines for audit subsystem */
@@ -527,6 +539,7 @@ struct audit_reply {
char *message;
struct nlmsgerr *error;
struct audit_sig_info *signal_info;
+ struct audit_sig_info2 *signal_info2;
struct daemon_conf *conf;
#ifdef AUDIT_FEATURE_BITMAP_ALL
struct audit_features *features;
@@ -604,6 +617,7 @@ extern uint32_t audit_get_session(void);
extern uint64_t audit_get_containerid(void);
extern int audit_detect_machine(void);
extern int audit_determine_machine(const char *arch);
+extern bool audit_signal_info_has_ctx(struct audit_reply *rep);
extern char *audit_format_signal_info(char *buf, int len, char *op, struct audit_reply *rep, char *res);

/* Translation functions */
diff --git a/lib/msg_typetab.h b/lib/msg_typetab.h
index 7490939c39a2..e904ece158ce 100644
--- a/lib/msg_typetab.h
+++ b/lib/msg_typetab.h
@@ -44,6 +44,7 @@ _S(AUDIT_LOGIN, "LOGIN" )
//_S(AUDIT_TTY_SET, "TTY_SET" )
//_S(AUDIT_SET_FEATURE, "SET_FEATURE" )
//_S(AUDIT_GET_FEATURE, "GET_FEATURE" )
+//_S(AUDIT_SIGNAL_INFO2, "SIGNAL_INFO2" )
_S(AUDIT_CONTAINER_OP, "CONTAINER_OP" )
_S(AUDIT_USER_AUTH, "USER_AUTH" )
_S(AUDIT_USER_ACCT, "USER_ACCT" )
diff --git a/lib/netlink.c b/lib/netlink.c
index caa963b1ddb2..66a3a3b7e83c 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -146,6 +146,7 @@ static int adjust_reply(struct audit_reply *rep, int len)
rep->message = NULL;
rep->error = NULL;
rep->signal_info = NULL;
+ rep->signal_info2 = NULL;
rep->conf = NULL;
#if defined(HAVE_DECL_AUDIT_FEATURE_VERSION) && \
defined(HAVE_STRUCT_AUDIT_STATUS_FEATURE_BITMAP)
@@ -194,6 +195,9 @@ static int adjust_reply(struct audit_reply *rep, int len)
case AUDIT_SIGNAL_INFO:
rep->signal_info = NLMSG_DATA(rep->nlh);
break;
+ case AUDIT_SIGNAL_INFO2:
+ rep->signal_info2 = NLMSG_DATA(rep->nlh);
+ break;
}
return len;
}
diff --git a/src/auditd-config.c b/src/auditd-config.c
index ce260de5025a..2a98a5f97e94 100644
--- a/src/auditd-config.c
+++ b/src/auditd-config.c
@@ -307,6 +307,7 @@ void clear_config(struct daemon_conf *config)
config->sender_uid = 0;
config->sender_pid = 0;
config->sender_ctx = NULL;
+ config->sender_cid = NULL;
config->write_logs = 1;
config->log_file = strdup("/var/log/audit/audit.log");
config->log_format = LF_ENRICHED;
diff --git a/src/auditd-config.h b/src/auditd-config.h
index 50ed3507d34c..4641c4e7223c 100644
--- a/src/auditd-config.h
+++ b/src/auditd-config.h
@@ -49,6 +49,7 @@ struct daemon_conf
uid_t sender_uid; /* the uid for sender of sighup */
pid_t sender_pid; /* the pid for sender of sighup */
const char *sender_ctx; /* the context for the sender of sighup */
+ const char *sender_cid; /* the contid for sender of sighup */
unsigned int write_logs;
const char *log_file;
logging_formats log_format;
diff --git a/src/auditd-event.c b/src/auditd-event.c
index 800f4d83bc83..9cb5d7a0efeb 100644
--- a/src/auditd-event.c
+++ b/src/auditd-event.c
@@ -1321,6 +1321,7 @@ static void reconfigure(struct auditd_event *e)
uid_t uid = nconf->sender_uid;
pid_t pid = nconf->sender_pid;
const char *ctx = nconf->sender_ctx;
+ const char *cid = nconf->sender_cid;
struct timeval tv;
char txt[MAX_AUDIT_MESSAGE_LENGTH];
int txt_len;
@@ -1331,8 +1332,11 @@ static void reconfigure(struct auditd_event *e)
txt_len = snprintf(txt, sizeof(txt),
"config change requested by pid=%d auid=%u", pid, uid);
if (ctx)
+ txt_len += snprintf(txt + txt_len, sizeof(txt) - txt_len,
+ " subj=%s", ctx);
+ if (cid)
snprintf(txt + txt_len, sizeof(txt) - txt_len,
- " subj=%s", ctx);
+ " contid=%s", cid);
audit_msg(LOG_NOTICE, "%s", txt);

/* Do the reconfiguring. These are done in a specific
@@ -1590,6 +1594,10 @@ static void reconfigure(struct auditd_event *e)
e->reply.len += snprintf(e->reply.msg.data + e->reply.len,
MAX_AUDIT_MESSAGE_LENGTH-2 - e->reply.len,
" res=success");
+ if (cid)
+ e->reply.len += snprintf(e->reply.msg.data + e->reply.len,
+ MAX_AUDIT_MESSAGE_LENGTH-2 - e->reply.len,
+ "contid=%s", cid);
e->reply.message = e->reply.msg.data;
free((char *)ctx);
}
diff --git a/src/auditd-reconfig.c b/src/auditd-reconfig.c
index 1af402526c4e..681f80adf925 100644
--- a/src/auditd-reconfig.c
+++ b/src/auditd-reconfig.c
@@ -101,11 +101,25 @@ static void *config_thread_main(void *arg)

if (load_config(&new_config, TEST_AUDITD) == 0) {
/* We will re-use the current reply */
- new_config.sender_uid = e->reply.signal_info->uid;
- new_config.sender_pid = e->reply.signal_info->pid;
- if (e->reply.len > 24)
- new_config.sender_ctx =
- strdup(e->reply.signal_info->ctx);
+ if (e->reply.type == AUDIT_SIGNAL_INFO) {
+ new_config.sender_uid = e->reply.signal_info->uid;
+ new_config.sender_pid = e->reply.signal_info->pid;
+ new_config.sender_cid = NULL;
+ } else {
+ new_config.sender_uid = e->reply.signal_info2->uid;
+ new_config.sender_pid = e->reply.signal_info2->pid;
+ new_config.sender_cid = strndup(e->reply.signal_info2->data,
+ e->reply.signal_info2->cid_len);
+ }
+ if (audit_signal_info_has_ctx(&e->reply)) {
+ if (e->reply.type == AUDIT_SIGNAL_INFO)
+ new_config.sender_ctx =
+ strdup(e->reply.signal_info->ctx);
+ else
+ new_config.sender_ctx =
+ strdup(e->reply.signal_info2->data +
+ e->reply.signal_info2->cid_len);
+ }
memcpy(e->reply.msg.data, &new_config, sizeof(new_config));
e->reply.conf = (struct daemon_conf *)e->reply.msg.data;
e->reply.type = AUDIT_DAEMON_RECONFIG;
@@ -125,4 +139,3 @@ static void *config_thread_main(void *arg)
pthread_mutex_unlock(&config_lock);
return NULL;
}
-
diff --git a/src/auditd.c b/src/auditd.c
index fa783a2cfa50..507e7711fb20 100644
--- a/src/auditd.c
+++ b/src/auditd.c
@@ -515,6 +515,7 @@ static void netlink_handler(struct ev_loop *loop, struct ev_io *io,
case AUDIT_REPLACE:
break;
case AUDIT_SIGNAL_INFO:
+ case AUDIT_SIGNAL_INFO2:
if (hup_info_requested) {
char hup[MAX_AUDIT_MESSAGE_LENGTH];
audit_msg(LOG_DEBUG,
@@ -1078,7 +1079,8 @@ static int get_reply(int rfd, struct audit_reply *rep, int seq)
continue;

/* If its not what we are expecting, keep looping */
- if (rep->type == AUDIT_SIGNAL_INFO)
+ if (rep->type == AUDIT_SIGNAL_INFO ||
+ rep->type == AUDIT_SIGNAL_INFO2)
return 1;

/* If we get done or error, break out */
--
1.8.3.1

2020-06-27 15:23:27

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 10/11] ausearch: convert contid to comma-sep/carrat-mod cnode/clist

Now that the kernel is able to track container nesting ("audit: track
container nesting"), convert the ausearch internals to parse and track
the compound list of contids stored in their native u64 format for
faster and more efficient processing.

Signed-off-by: Richard Guy Briggs <[email protected]>
---
src/Makefile.am | 6 +-
src/aureport-options.c | 3 +-
src/ausearch-contid.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++
src/ausearch-contid.h | 60 +++++++++++++++++
src/ausearch-llist.c | 8 ++-
src/ausearch-llist.h | 3 +-
src/ausearch-match.c | 36 ++++++++++-
src/ausearch-options.c | 36 ++++++++++-
src/ausearch-options.h | 3 +-
src/ausearch-parse.c | 110 ++++++++++++++++++++++++-------
10 files changed, 402 insertions(+), 35 deletions(-)
create mode 100644 src/ausearch-contid.c
create mode 100644 src/ausearch-contid.h

diff --git a/src/Makefile.am b/src/Makefile.am
index fda612b1ccb0..91c29cfbe52e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,7 +25,7 @@ SUBDIRS = test
AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/src/libev -I${top_srcdir}/auparse -I${top_srcdir}/audisp -I${top_srcdir}/common
sbin_PROGRAMS = auditd auditctl aureport ausearch autrace
AM_CFLAGS = -D_GNU_SOURCE -Wno-pointer-sign
-noinst_HEADERS = auditd-config.h auditd-event.h auditd-listen.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h ausearch-lol.h auditctl-listing.h ausearch-checkpt.h
+noinst_HEADERS = auditd-config.h auditd-event.h auditd-listen.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h ausearch-lol.h auditctl-listing.h ausearch-checkpt.h ausearch-contid.h

auditd_SOURCES = auditd.c auditd-event.c auditd-config.c auditd-reconfig.c auditd-sendmail.c auditd-dispatch.c
if ENABLE_LISTENER
@@ -41,10 +41,10 @@ auditctl_CFLAGS = -fPIE -DPIE -g -D_GNU_SOURCE
auditctl_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now
auditctl_LDADD = -L${top_builddir}/lib -laudit -L${top_builddir}/auparse -lauparse -L${top_builddir}/common -laucommon

-aureport_SOURCES = aureport.c auditd-config.c ausearch-llist.c aureport-options.c ausearch-string.c ausearch-parse.c aureport-scan.c aureport-output.c ausearch-lookup.c ausearch-int.c ausearch-time.c ausearch-nvpair.c ausearch-avc.c ausearch-lol.c
+aureport_SOURCES = aureport.c auditd-config.c ausearch-llist.c aureport-options.c ausearch-string.c ausearch-parse.c aureport-scan.c aureport-output.c ausearch-lookup.c ausearch-int.c ausearch-time.c ausearch-nvpair.c ausearch-avc.c ausearch-lol.c ausearch-contid.c
aureport_LDADD = -L${top_builddir}/lib -laudit -L${top_builddir}/auparse -lauparse -L${top_builddir}/common -laucommon

-ausearch_SOURCES = ausearch.c auditd-config.c ausearch-llist.c ausearch-options.c ausearch-report.c ausearch-match.c ausearch-string.c ausearch-parse.c ausearch-int.c ausearch-time.c ausearch-nvpair.c ausearch-lookup.c ausearch-avc.c ausearch-lol.c ausearch-checkpt.c
+ausearch_SOURCES = ausearch.c auditd-config.c ausearch-llist.c ausearch-options.c ausearch-report.c ausearch-match.c ausearch-string.c ausearch-parse.c ausearch-int.c ausearch-time.c ausearch-nvpair.c ausearch-lookup.c ausearch-avc.c ausearch-lol.c ausearch-checkpt.c ausearch-contid.c
ausearch_LDADD = -L${top_builddir}/lib -laudit -L${top_builddir}/auparse -lauparse -L${top_builddir}/common -laucommon

autrace_SOURCES = autrace.c delete_all.c auditctl-llist.c
diff --git a/src/aureport-options.c b/src/aureport-options.c
index 29d267f2d1cb..0aa742c9a1fe 100644
--- a/src/aureport-options.c
+++ b/src/aureport-options.c
@@ -36,6 +36,7 @@
#include "ausearch-time.h"
#include "libaudit.h"
#include "auparse-defs.h"
+#include "ausearch-contid.h"


/* Global vars that will be accessed by the main program */
@@ -62,7 +63,7 @@ const char *event_vmname = NULL;
long long event_exit = 0;
int event_exit_is_set = 0;
int event_ppid = -1, event_session_id = -2;
-unsigned long long event_contid = -1;
+clist *event_contid = NULL;
int event_debug = 0, event_machine = -1;

/* These are used by aureport */
diff --git a/src/ausearch-contid.c b/src/ausearch-contid.c
new file mode 100644
index 000000000000..87a94497ced1
--- /dev/null
+++ b/src/ausearch-contid.c
@@ -0,0 +1,172 @@
+/*
+ * ausearch-contid.c - Minimal linked list library for contid
+ * adapted from ausearch-string.c
+ * Copyright (c) 2005,2008,2014,2019 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This software may be freely redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1335, USA.
+ *
+ * Authors:
+ * Steve Grubb <[email protected]>
+ * Richard Guy Briggs <[email protected]>
+ */
+
+#include <stdlib.h>
+#include "ausearch-contid.h"
+
+
+void clist_create(clist *l)
+{
+ l->head = NULL;
+ l->cur = NULL;
+ l->cnt = 0;
+}
+
+void clist_last(clist *l)
+{
+ register cnode *cur;
+
+ if (l->head == NULL)
+ return;
+
+ // Try using cur so that we don't have to start at beginnning
+ if (l->cur)
+ cur = l->cur;
+ else
+ cur = l->head;
+
+ // Loop until no next value
+ while (cur->next)
+ cur = cur->next;
+ l->cur = cur;
+}
+
+cnode *clist_next(clist *l)
+{
+ if (l->cur == NULL)
+ return NULL;
+ l->cur = l->cur->next;
+ return l->cur;
+}
+
+void clist_append(clist *l, cnode *node)
+{
+ cnode *newnode;
+
+ newnode = malloc(sizeof(cnode));
+
+ newnode->id = node->id;
+ newnode->hits = node->hits;
+ newnode->next = NULL;
+
+ // Make sure cursor is at the end
+ clist_last(l);
+
+ // if we are at top, fix this up
+ if (l->head == NULL)
+ l->head = newnode;
+ else // Otherwise add pointer to newnode
+ l->cur->next = newnode;
+
+ // make newnode current
+ l->cur = newnode;
+ l->cnt++;
+}
+
+void clist_clear(clist *l)
+{
+ cnode *nextnode;
+ register cnode *current;
+
+ current = l->head;
+ while (current) {
+ nextnode = current->next;
+ free(current);
+ current = nextnode;
+ }
+ l->head = NULL;
+ l->cur = NULL;
+ l->cnt = 0;
+}
+
+/* This function dominates the timing of aureport. Needs to be more efficient */
+int clist_add_if_uniq(clist *l, const unsigned long long id)
+{
+ cnode cn;
+ register cnode *cur;
+
+ if (id == (unsigned long long)-1)
+ return -1;
+
+ cur = l->head;
+ while (cur) {
+ if (id == cur->id) {
+ cur->hits++;
+ l->cur = cur;
+ return 0;
+ }
+ cur = cur->next;
+ }
+
+ /* No matches, append to the end */
+ cn.id = id;
+ cn.hits = 1;
+ clist_append(l, &cn);
+ return 1;
+}
+
+// If lprev would be NULL, use l->head
+static void swap_nodes(cnode *lprev, cnode *left, cnode *right)
+{
+ cnode *t = right->next;
+
+ if (lprev)
+ lprev->next = right;
+ right->next = left;
+ left->next = t;
+}
+
+// This will sort the list from most hits to least
+void clist_sort_by_hits(clist *l)
+{
+ register cnode *cur, *prev;
+
+ if (l->cnt <= 1)
+ return;
+
+ prev = cur = l->head;
+
+ while (cur && cur->next) {
+ /* If the next node is bigger */
+ if (cur->hits < cur->next->hits) {
+ if (cur == l->head) {
+ // Update the actual list head
+ l->head = cur->next;
+ prev = NULL;
+ }
+ swap_nodes(prev, cur, cur->next);
+
+ // start over
+ prev = cur = l->head;
+ continue;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ // End with cur pointing at first record
+ l->cur = l->head;
+}
+
diff --git a/src/ausearch-contid.h b/src/ausearch-contid.h
new file mode 100644
index 000000000000..edc534943398
--- /dev/null
+++ b/src/ausearch-contid.h
@@ -0,0 +1,60 @@
+/*
+ * ausearch-contid.h - Header file for ausearch-contid.c
+ * adapted from ausearch-string.h
+ * Copyright (c) 2005,2008,2019 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This software may be freely redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1335, USA.
+ *
+ * Authors:
+ * Steve Grubb <[email protected]>
+ * Richard Guy Briggs <[email protected]>
+ */
+
+#ifndef AUCONTID_HEADER
+#define AUCONTID_HEADER
+
+#include "config.h"
+
+/* This is the node of the linked list. message & item are the only elements
+ * at this time. Any data elements that are per item goes here. */
+typedef struct _cnode {
+ unsigned long long id;// The audit container id
+ unsigned int hits; // Number of times this contid was attempted to be added
+ struct _cnode *next; // Next contid node pointer
+} cnode;
+
+/* This is the linked list head. Only data elements that are 1 per
+ * event goes here. */
+typedef struct {
+ cnode *head; // List head
+ cnode *cur; // Pointer to current node
+ unsigned int cnt; // How many items in this list
+} clist;
+
+void clist_create(clist *l);
+static inline void clist_first(clist *l) { l->cur = l->head; }
+void clist_last(clist *l);
+cnode *clist_next(clist *l);
+static inline cnode *clist_get_cur(clist *l) { return l->cur; }
+void clist_append(clist *l, cnode *node);
+void clist_clear(clist *l);
+
+/* append a contid if its not already on the list */
+int clist_add_if_uniq(clist *l, const unsigned long long id);
+void clist_sort_by_hits(clist *l);
+
+#endif
diff --git a/src/ausearch-llist.c b/src/ausearch-llist.c
index ade727a9e102..6624398a1b5c 100644
--- a/src/ausearch-llist.c
+++ b/src/ausearch-llist.c
@@ -60,7 +60,7 @@ void list_create(llist *l)
l->s.arch = 0;
l->s.syscall = 0;
l->s.session_id = -2;
- l->s.contid = -1;
+ l->s.contid = NULL;
l->s.uuid = NULL;
l->s.vmname = NULL;
l->s.tuid = NULL;
@@ -212,7 +212,11 @@ void list_clear(llist* l)
l->s.arch = 0;
l->s.syscall = 0;
l->s.session_id = -2;
- l->s.contid = -1;
+ if (l->s.contid) {
+ clist_clear(l->s.contid);
+ free(l->s.contid);
+ l->s.contid = NULL;
+ }
free(l->s.uuid);
l->s.uuid = NULL;
free(l->s.vmname);
diff --git a/src/ausearch-llist.h b/src/ausearch-llist.h
index 2d1f52237ce6..f2f004b09630 100644
--- a/src/ausearch-llist.h
+++ b/src/ausearch-llist.h
@@ -31,6 +31,7 @@
#include <sys/types.h>
#include "ausearch-string.h"
#include "ausearch-avc.h"
+#include "ausearch-contid.h"
#include "ausearch-common.h"


@@ -56,7 +57,7 @@ typedef struct
int arch; // arch
int syscall; // syscall
uint32_t session_id; // Login session id
- __u64 contid; // Container id
+ clist *contid; // Container id
long long exit; // Syscall exit code
int exit_is_set; // Syscall exit code is valid
char *hostname; // remote hostname
diff --git a/src/ausearch-match.c b/src/ausearch-match.c
index 47c12581a963..e852f1c28d45 100644
--- a/src/ausearch-match.c
+++ b/src/ausearch-match.c
@@ -37,6 +37,7 @@ static int strmatch(const char *needle, const char *haystack);
static int user_match(llist *l);
static int group_match(llist *l);
static int context_match(llist *l);
+static int contid_match(llist *l);

static void load_interpretations(const llist *l)
{
@@ -113,8 +114,7 @@ int match(llist *l)
if ((event_session_id != -2) &&
(event_session_id != l->s.session_id))
return 0;
- if ((event_contid != -1) &&
- (event_contid != l->s.contid))
+ if (contid_match(l) == 0)
return 0;
if (event_exit_is_set) {
if (l->s.exit_is_set == 0)
@@ -417,3 +417,35 @@ static int context_match(llist *l)
return 1;
}

+/*
+ * This function compares container ids. It returns a 0 if no match and a 1 if
+ * there is a match
+ */
+static int contid_match(llist *l)
+{
+ if (event_contid) {
+ const cnode *ecn;
+ clist *ecptr = event_contid;
+
+ clist_first(ecptr);
+ ecn = clist_get_cur(ecptr);
+ if (l->s.contid) {
+ while (ecn) {
+ const cnode *cn;
+ clist *cptr = l->s.contid;
+
+ clist_first(cptr);
+ cn = clist_get_cur(cptr);
+ while (cn) {
+ if (cn->id == ecn->id)
+ return 1;
+ cn = clist_next(cptr);
+ }
+ ecn = clist_next(ecptr);
+ }
+ }
+ return 0;
+ }
+ return 1;
+}
+
diff --git a/src/ausearch-options.c b/src/ausearch-options.c
index b45793e88109..0cc5974f8f43 100644
--- a/src/ausearch-options.c
+++ b/src/ausearch-options.c
@@ -60,7 +60,7 @@ int event_syscall = -1, event_machine = -1;
int event_ua = 0, event_ga = 0, event_se = 0;
int just_one = 0;
uint32_t event_session_id = -2;
-unsigned long long event_contid = -1;
+clist *event_contid = NULL;
long long event_exit = 0;
int event_exit_is_set = 0;
int line_buffered = 0;
@@ -1201,22 +1201,52 @@ int check_params(int count, char *vars[])
size_t len = strlen(optarg);

if (isdigit(optarg[0])) {
+ __u64 contid;
+ cnode cn;
+
errno = 0;
- event_contid = strtoull(optarg, NULL, 0);
+ contid = strtoull(optarg, NULL, 0);
if (errno) {
fprintf(stderr,
"Numeric container ID conversion error (%s) for %s\n",
strerror(errno), optarg);
retval = -1;
+ } else {
+ if (!event_contid) {
+ event_contid = malloc(sizeof(clist));
+ if (!event_contid) {
+ retval = -1;
+ break;
+ }
+ clist_create(event_contid);
+ }
+ cn.id = contid;
+ cn.hits = 0;
+ clist_append(event_contid, &cn);
}
} else if (len >= 2 && *(optarg) == '-' &&
(isdigit(optarg[1]))) {
+ __u64 contid;
+ cnode cn;
+
errno = 0;
- event_contid = strtoll(optarg, NULL, 0);
+ contid = strtoll(optarg, NULL, 0);
if (errno) {
retval = -1;
fprintf(stderr, "Error converting %s\n",
optarg);
+ } else {
+ if (!event_contid) {
+ event_contid = malloc(sizeof(clist));
+ if (!event_contid) {
+ retval = -1;
+ break;
+ }
+ clist_create(event_contid);
+ }
+ cn.id = contid;
+ cn.hits = 0;
+ clist_append(event_contid, &cn);
}
} else {
fprintf(stderr,
diff --git a/src/ausearch-options.h b/src/ausearch-options.h
index 085d492d101c..ac4f97d00a83 100644
--- a/src/ausearch-options.h
+++ b/src/ausearch-options.h
@@ -29,6 +29,7 @@
#include <stdint.h>
#include "ausearch-common.h"
#include "ausearch-int.h"
+#include "ausearch-contid.h"

/* Global variables that describe what search is to be performed */
extern const char *event_key;
@@ -40,7 +41,7 @@ extern int line_buffered;
extern int event_debug;
extern pid_t event_ppid;
extern uint32_t event_session_id;
-extern unsigned long long event_contid;
+extern clist *event_contid;
extern ilist *event_type;

/* Data type to govern output format */
diff --git a/src/ausearch-parse.c b/src/ausearch-parse.c
index 374b369be7b7..93482be3606e 100644
--- a/src/ausearch-parse.c
+++ b/src/ausearch-parse.c
@@ -79,6 +79,18 @@ static int audit_avc_init(search_items *s)
return 0;
}

+static int audit_contid_init(search_items *s)
+{
+ if (s->contid == NULL) {
+ //create
+ s->contid = malloc(sizeof(clist));
+ if (s->contid == NULL)
+ return -1;
+ clist_create(s->contid);
+ }
+ return 0;
+}
+
/*
* This function will take the list and extract the searchable fields from it.
* It returns 0 on success and 1 on failure.
@@ -1489,22 +1501,57 @@ static int parse_container_op(const lnode *n, search_items *s)
// skip op
// skip opid
// get contid
- if (event_contid != -1) {
+ if (event_contid) {
+ cnode cn;
+ char *comma;
+
str = strstr(term, "contid=");
- if (str == NULL)
+ if (!str)
return 46;
- ptr = str + 7;
- term = strchr(ptr, ' ');
- if (term == NULL)
+ if (audit_contid_init(s) < 0)
+ return 48;
+ str += 7;
+ term = strchr(str, ' ');
+ if (!term)
return 47;
*term = 0;
- errno = 0;
- s->contid = strtoull(ptr, NULL, 10);
- if (errno)
- return 48;
- *term = ' ';
+ if (strcmp(str, "-1"))
+ cn.id = strtoull(str, NULL, 10);
+ else
+ cn.id = ULLONG_MAX;
+ cn.hits = 1;
+ clist_append(s->contid, &cn);
+ if (term)
+ *term = ' ';
+ // old-contid
+ str = strstr(term, "old-contid=");
+ if (!str)
+ return 49;
+ str += 11;
+ term = strchr(str, ' ');
+ if (term)
+ *term = 0;
+ comma = strchr(str, ',');
+ if (comma)
+ *comma = 0;
+ do {
+ if (str[0] == '^')
+ str++;
+ if (strcmp(str, "-1"))
+ cn.id = strtoull(str, NULL, 10);
+ else
+ cn.id = ULLONG_MAX;
+ cn.hits = 1;
+ clist_append(s->contid, &cn);
+ if (comma) {
+ str = comma + 1;
+ *comma = ',';
+ comma = strchr(str, ',');
+ }
+ } while (comma);
+ if (term)
+ *term = ' ';
}
- // skip old-contid
return 0;
}

@@ -1513,20 +1560,39 @@ static int parse_container_id(const lnode *n, search_items *s)
char *ptr, *str, *term = n->message;

// get contid
- if (event_contid != -1) {
+ if (event_contid) {
+ cnode cn;
+ char *comma;
+
str = strstr(term, "contid=");
- if (str == NULL)
- return 49;
- ptr = str + 7;
- term = strchr(ptr, ' ');
- if (term)
+ if (!str)
return 50;
- *term = 0;
- errno = 0;
- s->contid = strtoull(ptr, NULL, 10);
- if (errno)
+ if (audit_contid_init(s) < 0)
return 51;
- *term = ' ';
+ str += 7;
+ term = strchr(str, ' ');
+ if (term)
+ *term = 0;
+ comma = strchr(str, ',');
+ if (comma)
+ *comma = 0;
+ do {
+ if (str[0] == '^')
+ str++;
+ if (strcmp(str, "-1"))
+ cn.id = strtoull(str, NULL, 10);
+ else
+ cn.id = ULLONG_MAX;
+ cn.hits = 1;
+ clist_append(s->contid, &cn);
+ if (comma) {
+ str = comma + 1;
+ *comma = ',';
+ comma = strchr(str, ',');
+ }
+ } while (comma);
+ if (term)
+ *term = ' ';
}
return 0;
}
--
1.8.3.1

2020-06-27 15:23:32

by Richard Guy Briggs

[permalink] [raw]
Subject: [PATCH ghau51/ghau40 v9 11/11] libaudit: add support to get and set capcontid on a task

Add support to be able to set a capability to allow a task to set the
audit container identifier of descendants.

See: https://github.com/linux-audit/audit-userspace/issues/51
See: https://github.com/linux-audit/audit-kernel/issues/90
See: https://github.com/linux-audit/audit-testsuite/issues/64
See: https://github.com/linux-audit/audit-kernel/wiki/RFE-Audit-Container-ID

Add the audit_get_capcontid() and audit_set_capcontid() calls analogous
to CAP_AUDIT_CONTROL for descendant user namespaces.

Signed-off-by: Richard Guy Briggs <[email protected]>
---
auparse/normalize.c | 1 +
auparse/normalize_record_map.h | 1 +
docs/Makefile.am | 1 +
docs/audit_get_capcontid.3 | 25 ++++++++++++++++
docs/audit_set_capcontid.3 | 24 +++++++++++++++
lib/libaudit.c | 68 ++++++++++++++++++++++++++++++++++++++++++
lib/libaudit.h | 4 +++
lib/msg_typetab.h | 1 +
lib/netlink.c | 1 +
src/ausearch-lol.c | 2 ++
src/ausearch-parse.c | 1 +
11 files changed, 129 insertions(+)
create mode 100644 docs/audit_get_capcontid.3
create mode 100644 docs/audit_set_capcontid.3

diff --git a/auparse/normalize.c b/auparse/normalize.c
index 2d7878ce9ba9..8bcfce280d1a 100644
--- a/auparse/normalize.c
+++ b/auparse/normalize.c
@@ -911,6 +911,7 @@ static const char *normalize_determine_evkind(int type)
case AUDIT_FEATURE_CHANGE ... AUDIT_REPLACE:
case AUDIT_USER_DEVICE:
case AUDIT_SOFTWARE_UPDATE:
+ case AUDIT_SET_CAPCONTID:
kind = NORM_EVTYPE_CONFIG;
break;
case AUDIT_SECCOMP:
diff --git a/auparse/normalize_record_map.h b/auparse/normalize_record_map.h
index 7332249c7b34..2e8c87447313 100644
--- a/auparse/normalize_record_map.h
+++ b/auparse/normalize_record_map.h
@@ -26,6 +26,7 @@
_S(AUDIT_USER, "sent-message")
_S(AUDIT_LOGIN, "changed-login-id-to")
_S(AUDIT_CONTAINER_OP, "changed-container-id-to")
+_S(AUDIT_SET_CAPCONTID, "set-capcontid-to")
_S(AUDIT_USER_AUTH, "authenticated")
_S(AUDIT_USER_ACCT, "was-authorized")
_S(AUDIT_USER_MGMT, "modified-user-account")
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 209789bb2051..6b981b296d0c 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -29,6 +29,7 @@ auditd.conf.5 auditd-plugins.5 \
audit_delete_rule_data.3 audit_detect_machine.3 \
audit_encode_nv_string.3 audit_getloginuid.3 \
audit_get_reply.3 audit_get_session.3 audit_get_containerid.3 \
+audit_get_capcontid.3 audit_set_capcontid.3 \
audit_log_acct_message.3 audit_log_user_avc_message.3 \
audit_log_user_command.3 audit_log_user_comm_message.3 \
audit_log_user_message.3 audit_log_semanage_message.3 \
diff --git a/docs/audit_get_capcontid.3 b/docs/audit_get_capcontid.3
new file mode 100644
index 000000000000..652a4960a020
--- /dev/null
+++ b/docs/audit_get_capcontid.3
@@ -0,0 +1,25 @@
+.TH "AUDIT_GET_CAPCONTID" "26" "Aug 2019" "Red Hat" "Linux Audit API"
+.SH NAME
+audit_get_capcontid \- Get a program's capability container id value
+.SH SYNOPSIS
+.B #include <libaudit.h>
+.sp
+int audit_get_capcontid(pid_t pid);
+
+.SH DESCRIPTION
+This function returns the pid task's audit capability container identifier attribute.
+
+.SH "RETURN VALUE"
+
+This function returns the audit capability container identifier value if it is implemented. It will return a \-1 if the audit capability container identifier is unavailable.
+
+.SH "ERRORS"
+
+This function returns \-2 on failure. Additionally, in the event of a real error, errno would be set. The function can set errno based on failures of open, read, or strtoull.
+
+.SH "SEE ALSO"
+
+.BR audit_set_capcontid (3).
+
+.SH AUTHOR
+Richard Guy Briggs
diff --git a/docs/audit_set_capcontid.3 b/docs/audit_set_capcontid.3
new file mode 100644
index 000000000000..70ac8c7a4e95
--- /dev/null
+++ b/docs/audit_set_capcontid.3
@@ -0,0 +1,24 @@
+.TH "AUDIT_SET_CAPCONTID" "26" "Aug 2019" "Red Hat" "Linux Audit API"
+.SH NAME
+audit_set_capcontid \- Set a program's capability container id value
+.SH SYNOPSIS
+.B #include <libaudit.h>
+.sp
+int audit_set_capcontid(pid_t pid, uint32_t capcontid);
+
+.SH "DESCRIPTION"
+
+This function sets the pid task's attribute capability container id with the value of capcontid. The capcontid value may only be set by programs with the CAP_AUDIT_CONTROL capability in the initial user namespace or with capcontid. This normally means the root account or root in a container.
+.sp
+The capcontid value is part of the task structure and is inheritted by child processes within a user namespace. It is used to enable the capability to set container identifier of a child task in a descendent user namespace. Container orchestrator/engines should set this value only on children it wishes to be able to set audit container identifiers.
+
+.SH "RETURN VALUE"
+
+This function returns 0 on success and non-zero otherwise.
+
+.SH "SEE ALSO"
+
+.BR audit_get_capcontid (3).
+
+.SH AUTHOR
+Richard Guy Briggs
diff --git a/lib/libaudit.c b/lib/libaudit.c
index 1a7fed76b9b0..4a2678ca2171 100644
--- a/lib/libaudit.c
+++ b/lib/libaudit.c
@@ -992,6 +992,74 @@ uint32_t audit_get_session(void)
}

/*
+ * This function will retrieve the capability container identifier or -2 if
+ * there is an error.
+ */
+uint32_t audit_get_capcontid(pid_t pid)
+{
+ int capcontid;
+ int len, in;
+ char buf[16], fnbuf[48];
+
+ if ((audit_get_features() & AUDIT_FEATURE_BITMAP_CONTAINERID) == 0)
+ return -2;
+ errno = 0;
+ snprintf(fnbuf, sizeof(fnbuf), "/proc/%d/audit_capcontainerid", pid);
+ in = open(fnbuf, O_NOFOLLOW|O_RDONLY);
+ if (in < 0)
+ return -2;
+ do {
+ len = read(in, buf, sizeof(buf));
+ } while (len < 0 && errno == EINTR);
+ close(in);
+ if (len < 0 || len >= sizeof(buf))
+ return -2;
+ buf[len] = 0;
+ errno = 0;
+ capcontid = strtol(buf, 0, 10);
+ if (errno)
+ return -2;
+ return capcontid;
+}
+
+/*
+ * This function returns 0 on success and 1 on failure
+ */
+int audit_set_capcontid(pid_t pid, uint32_t capcontid)
+{
+ char capcontidbuf[16], fnbuf[48];
+ int o, count, rc = 0;
+
+ if ((audit_get_features() & AUDIT_FEATURE_BITMAP_CONTAINERID) == 0)
+ return -2;
+ errno = 0;
+ count = snprintf(capcontidbuf, sizeof(capcontidbuf), "%u", capcontid);
+ snprintf(fnbuf, sizeof(fnbuf), "/proc/%d/audit_capcontainerid", pid);
+ o = open(fnbuf, O_NOFOLLOW|O_WRONLY|O_TRUNC);
+ if (o >= 0) {
+ int block, offset = 0;
+
+ while (count > 0) {
+ block = write(o, &capcontidbuf[offset], (unsigned int)count);
+ if (block < 0) {
+ if (errno == EINTR)
+ continue;
+ audit_msg(LOG_ERR, "Error writing capcontid");
+ close(o);
+ return 1;
+ }
+ offset += block;
+ count -= block;
+ }
+ close(o);
+ } else {
+ audit_msg(LOG_ERR, "Error opening %s", fnbuf);
+ rc = 1;
+ }
+ return rc;
+}
+
+/*
* This function will retrieve the audit container identifier or -2 if
* there is an error.
*/
diff --git a/lib/libaudit.h b/lib/libaudit.h
index f4e820e9b097..2a140f6d0e4b 100644
--- a/lib/libaudit.h
+++ b/lib/libaudit.h
@@ -255,6 +255,10 @@ extern "C" {
#define AUDIT_SIGNAL_INFO2 1021 /* auditd signal sender info */
#endif

+#ifndef AUDIT_SET_CAPCONTID
+#define AUDIT_SET_CAPCONTID 1022 /* set capcontid of specified pid */
+#endif
+
#ifndef AUDIT_MMAP
#define AUDIT_MMAP 1323 /* Descriptor and flags in mmap */
#endif
diff --git a/lib/msg_typetab.h b/lib/msg_typetab.h
index e904ece158ce..453013bf434f 100644
--- a/lib/msg_typetab.h
+++ b/lib/msg_typetab.h
@@ -46,6 +46,7 @@ _S(AUDIT_LOGIN, "LOGIN" )
//_S(AUDIT_GET_FEATURE, "GET_FEATURE" )
//_S(AUDIT_SIGNAL_INFO2, "SIGNAL_INFO2" )
_S(AUDIT_CONTAINER_OP, "CONTAINER_OP" )
+_S(AUDIT_SET_CAPCONTID, "SET_CAPCONTID" )
_S(AUDIT_USER_AUTH, "USER_AUTH" )
_S(AUDIT_USER_ACCT, "USER_ACCT" )
_S(AUDIT_USER_MGMT, "USER_MGMT" )
diff --git a/lib/netlink.c b/lib/netlink.c
index 66a3a3b7e83c..d7c3c6124a68 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -186,6 +186,7 @@ static int adjust_reply(struct audit_reply *rep, int len)
case AUDIT_USER:
case AUDIT_LOGIN:
case AUDIT_CONTAINER_OP:
+ case AUDIT_SET_CAPCONTID:
case AUDIT_KERNEL:
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
diff --git a/src/ausearch-lol.c b/src/ausearch-lol.c
index 05fe80fe3ad6..8ad88a14f30c 100644
--- a/src/ausearch-lol.c
+++ b/src/ausearch-lol.c
@@ -250,6 +250,8 @@ static void check_events(lol *lo, time_t sec)
(cur->l->e.type > AUDIT_LOGIN &&
cur->l->e.type < AUDIT_CONTAINER_OP ) ||
(cur->l->e.type > AUDIT_CONTAINER_OP &&
+ cur->l->e.type < AUDIT_SET_CAPCONTID ) ||
+ (cur->l->e.type > AUDIT_SET_CAPCONTID &&
cur->l->e.type < AUDIT_FIRST_EVENT ) ||
cur->l->e.type == AUDIT_PROCTITLE ||
(cur->l->e.type >= AUDIT_MAC_UNLBL_ALLOW &&
diff --git a/src/ausearch-parse.c b/src/ausearch-parse.c
index 93482be3606e..9d8a5dd2d092 100644
--- a/src/ausearch-parse.c
+++ b/src/ausearch-parse.c
@@ -192,6 +192,7 @@ int extract_search_items(llist *l)
case AUDIT_MMAP:
case AUDIT_PROCTITLE:
case AUDIT_REPLACE...AUDIT_BPF:
+ case AUDIT_SET_CAPCONTID:
// Nothing to parse
break;
case AUDIT_NETFILTER_CFG:
--
1.8.3.1