Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions src/auditd-dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,14 @@ int dispatch_event(const struct audit_reply *rep, int protocol_ver)
e->hdr.type = rep->type;

if (protocol_ver == AUDISP_PROTOCOL_VER) {
if (rep->nlh == &rep->msg.nlh) {
if (rep->msg.nlh.nlmsg_len < NLMSG_HDRLEN ||
rep->msg.nlh.nlmsg_len >
NLMSG_LENGTH(sizeof(e->data))) {
free(e);
return -1;
}

/* audit_get_reply marks embedded netlink replies this
* way. Netlink length includes its header, while
* event_t contains only payload. Local V0/legacy
* events retain a payload length here. */
e->hdr.size = rep->msg.nlh.nlmsg_len - NLMSG_HDRLEN;
} else if (rep->msg.nlh.nlmsg_len > sizeof(e->data)) {
/* The kernel audit subsystem sets nlmsg_len to the payload
* size only (skb->len - NLMSG_HDRLEN), not the total
* message length. */
if (rep->msg.nlh.nlmsg_len > sizeof(e->data)) {
free(e);
return -1;
} else
e->hdr.size = rep->msg.nlh.nlmsg_len;
}
e->hdr.size = rep->msg.nlh.nlmsg_len;
memcpy(e->data, (void*)rep->msg.data, e->hdr.size);
} else if (protocol_ver == AUDISP_PROTOCOL_VER2) {
e->hdr.size = rep->len;
Expand Down
72 changes: 63 additions & 9 deletions src/test/auditd_dispatch_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ static void free_queued_event(void)
}

/*
* test_netlink_payload_length - verify netlink headers are not copied as data
* test_netlink_payload_length - kernel nlmsg_len is the payload size directly
*
* Returns: None.
* The kernel audit subsystem sets nlmsg_len = skb->len - NLMSG_HDRLEN,
* i.e. the payload size only. Verify dispatch uses it as-is.
*/
static void test_netlink_payload_length(void)
{
Expand All @@ -96,7 +97,7 @@ static void test_netlink_payload_length(void)
memset(rep.msg.data, 'a', sizeof(rep.msg.data));
rep.type = AUDIT_SYSCALL;
rep.nlh = &rep.msg.nlh;
rep.msg.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(rep.msg.data));
rep.msg.nlh.nlmsg_len = sizeof(rep.msg.data);

assert(dispatch_event(&rep, AUDISP_PROTOCOL_VER) == 0);
assert(queued_event != NULL);
Expand All @@ -107,7 +108,7 @@ static void test_netlink_payload_length(void)
}

/*
* test_invalid_netlink_length - reject malformed embedded netlink lengths
* test_invalid_netlink_length - reject oversized payloads
*
* Returns: None.
*/
Expand All @@ -117,11 +118,7 @@ static void test_invalid_netlink_length(void)

memset(&rep, 0, sizeof(rep));
rep.nlh = &rep.msg.nlh;
rep.msg.nlh.nlmsg_len = NLMSG_HDRLEN - 1;
assert(dispatch_event(&rep, AUDISP_PROTOCOL_VER) == -1);
assert(queued_event == NULL);

rep.msg.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(rep.msg.data)) + 1;
rep.msg.nlh.nlmsg_len = sizeof(rep.msg.data) + 1;
assert(dispatch_event(&rep, AUDISP_PROTOCOL_VER) == -1);
assert(queued_event == NULL);
}
Expand All @@ -146,10 +143,67 @@ static void test_synthetic_payload_length(void)
free_queued_event();
}

/*
* test_realistic_user_event - exercise a USER record like auditctl -m produces
*
* The kernel sets nlmsg_len to the payload size (not including the netlink
* header). The dispatcher must copy exactly that many bytes from msg.data.
*/
static void test_realistic_user_event(void)
{
struct audit_reply rep;
const char *payload =
"audit(1721000000.123:42): pid=1234 uid=0 auid=0 ses=1 "
"subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 "
"msg='text=dispatch-test "
"exe=\"/usr/sbin/auditctl\" "
"hostname=? addr=? terminal=pts/0 res=success'";
unsigned int plen = strlen(payload);

memset(&rep, 0, sizeof(rep));
rep.type = AUDIT_USER;
rep.nlh = &rep.msg.nlh;
rep.msg.nlh.nlmsg_len = plen;
memcpy(rep.msg.data, payload, plen);

assert(dispatch_event(&rep, AUDISP_PROTOCOL_VER) == 0);
assert(queued_event != NULL);
assert(queued_event->hdr.size == plen);
assert(memcmp(queued_event->data, payload, plen) == 0);
free_queued_event();
}

/*
* test_v2_protocol_uses_rep_len - VER2 events use rep->len and rep->message
*
* Enriched / pre-formatted events travel as AUDISP_PROTOCOL_VER2 and must
* use the explicit rep->len field rather than nlmsg_len.
*/
static void test_v2_protocol_uses_rep_len(void)
{
struct audit_reply rep;
const char *formatted = "type=USER msg=audit(1721000000.789:44): "
"op=user-msg terminal=pts/0 res=success";
unsigned int flen = strlen(formatted);

memset(&rep, 0, sizeof(rep));
rep.type = AUDIT_USER;
rep.len = flen;
rep.message = (char *)formatted;

assert(dispatch_event(&rep, AUDISP_PROTOCOL_VER2) == 0);
assert(queued_event != NULL);
assert(queued_event->hdr.size == flen);
assert(memcmp(queued_event->data, formatted, flen) == 0);
free_queued_event();
}

int main(void)
{
test_netlink_payload_length();
test_invalid_netlink_length();
test_synthetic_payload_length();
test_realistic_user_event();
test_v2_protocol_uses_rep_len();
return 0;
}
Loading