1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Landlock audit helpers 4 * 5 * Copyright © 2024-2025 Microsoft Corporation 6 */ 7 8 #define _GNU_SOURCE 9 #include <errno.h> 10 #include <linux/audit.h> 11 #include <linux/limits.h> 12 #include <linux/netlink.h> 13 #include <regex.h> 14 #include <stdbool.h> 15 #include <stdint.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <sys/socket.h> 20 #include <sys/time.h> 21 #include <unistd.h> 22 23 #include "kselftest.h" 24 25 #ifndef ARRAY_SIZE 26 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 27 #endif 28 29 #define REGEX_LANDLOCK_PREFIX "^audit([0-9.:]\\+): domain=\\([0-9a-f]\\+\\)" 30 31 struct audit_filter { 32 __u32 record_type; 33 size_t exe_len; 34 char exe[PATH_MAX]; 35 }; 36 37 struct audit_message { 38 struct nlmsghdr header; 39 union { 40 struct audit_status status; 41 struct audit_features features; 42 struct audit_rule_data rule; 43 struct nlmsgerr err; 44 char data[PATH_MAX + 200]; 45 }; 46 }; 47 48 static const struct timeval audit_tv_default = { 49 /* 50 * Default socket timeout for audit_match_record() callers that expect a 51 * record to arrive. Asynchronous kauditd delivery can exceed 1 usec 52 * under heavy debug configs (KASAN, lockdep), where kauditd_thread 53 * scheduling between audit_log_end() and netlink_unicast() takes longer 54 * than the previous 1 usec timeout. 1 second is a generous ceiling: on 55 * the happy path, kauditd delivers within dozens of usec. 56 */ 57 .tv_sec = 1, 58 }; 59 60 static const struct timeval audit_tv_fast = { 61 /* 62 * Fast timeout for paths that expect no record (audit_init() drain, 63 * audit_count_records(), probes). Causes audit_recv() to return 64 * -EAGAIN once the socket buffer is empty, naturally terminating the 65 * read loop. 66 */ 67 .tv_usec = 1, 68 }; 69 70 static int audit_send(const int fd, const struct audit_message *const msg) 71 { 72 struct sockaddr_nl addr = { 73 .nl_family = AF_NETLINK, 74 }; 75 int ret; 76 77 do { 78 ret = sendto(fd, msg, msg->header.nlmsg_len, 0, 79 (struct sockaddr *)&addr, sizeof(addr)); 80 } while (ret < 0 && errno == EINTR); 81 82 if (ret < 0) 83 return -errno; 84 85 if (ret != msg->header.nlmsg_len) 86 return -E2BIG; 87 88 return 0; 89 } 90 91 static int audit_recv(const int fd, struct audit_message *msg) 92 { 93 struct sockaddr_nl addr; 94 socklen_t addrlen = sizeof(addr); 95 struct audit_message msg_tmp; 96 int err; 97 98 if (!msg) 99 msg = &msg_tmp; 100 101 do { 102 err = recvfrom(fd, msg, sizeof(*msg), 0, 103 (struct sockaddr *)&addr, &addrlen); 104 } while (err < 0 && errno == EINTR); 105 106 if (err < 0) 107 return -errno; 108 109 if (addrlen != sizeof(addr) || addr.nl_pid != 0) 110 return -EINVAL; 111 112 /* Checks Netlink error or end of messages. */ 113 if (msg->header.nlmsg_type == NLMSG_ERROR) 114 return msg->err.error; 115 116 return 0; 117 } 118 119 static int audit_request(const int fd, 120 const struct audit_message *const request, 121 struct audit_message *reply) 122 { 123 struct audit_message msg_tmp; 124 bool first_reply = true; 125 int err; 126 127 err = audit_send(fd, request); 128 if (err) 129 return err; 130 131 if (!reply) 132 reply = &msg_tmp; 133 134 do { 135 if (first_reply) 136 first_reply = false; 137 else 138 reply = &msg_tmp; 139 140 err = audit_recv(fd, reply); 141 if (err) 142 return err; 143 } while (reply->header.nlmsg_type != NLMSG_ERROR && 144 reply->err.msg.nlmsg_type != request->header.nlmsg_type); 145 146 return reply->err.error; 147 } 148 149 static int audit_filter_exe(const int audit_fd, 150 const struct audit_filter *const filter, 151 const __u16 type) 152 { 153 struct audit_message msg = { 154 .header = { 155 .nlmsg_len = NLMSG_SPACE(sizeof(msg.rule)) + 156 NLMSG_ALIGN(filter->exe_len), 157 .nlmsg_type = type, 158 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 159 }, 160 .rule = { 161 .flags = AUDIT_FILTER_EXCLUDE, 162 .action = AUDIT_NEVER, 163 .field_count = 1, 164 .fields[0] = filter->record_type, 165 .fieldflags[0] = AUDIT_NOT_EQUAL, 166 .values[0] = filter->exe_len, 167 .buflen = filter->exe_len, 168 } 169 }; 170 171 if (filter->record_type != AUDIT_EXE) 172 return -EINVAL; 173 174 memcpy(msg.rule.buf, filter->exe, filter->exe_len); 175 return audit_request(audit_fd, &msg, NULL); 176 } 177 178 static int audit_filter_drop(const int audit_fd, const __u16 type) 179 { 180 struct audit_message msg = { 181 .header = { 182 .nlmsg_len = NLMSG_SPACE(sizeof(msg.rule)), 183 .nlmsg_type = type, 184 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 185 }, 186 .rule = { 187 .flags = AUDIT_FILTER_EXCLUDE, 188 .action = AUDIT_NEVER, 189 .field_count = 1, 190 .fields[0] = AUDIT_MSGTYPE, 191 .fieldflags[0] = AUDIT_NOT_EQUAL, 192 .values[0] = AUDIT_LANDLOCK_DOMAIN, 193 } 194 }; 195 196 return audit_request(audit_fd, &msg, NULL); 197 } 198 199 static int audit_set_status(int fd, __u32 key, __u32 val) 200 { 201 const struct audit_message msg = { 202 .header = { 203 .nlmsg_len = NLMSG_SPACE(sizeof(msg.status)), 204 .nlmsg_type = AUDIT_SET, 205 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 206 }, 207 .status = { 208 .mask = key, 209 .enabled = key == AUDIT_STATUS_ENABLED ? val : 0, 210 .pid = key == AUDIT_STATUS_PID ? val : 0, 211 } 212 }; 213 214 return audit_request(fd, &msg, NULL); 215 } 216 217 /* Returns a pointer to the last filled character of @dst, which is `\0`. */ 218 static __maybe_unused char *regex_escape(const char *const src, char *dst, 219 size_t dst_size) 220 { 221 char *d = dst; 222 223 for (const char *s = src; *s; s++) { 224 switch (*s) { 225 case '$': 226 case '*': 227 case '.': 228 case '[': 229 case '\\': 230 case ']': 231 case '^': 232 if (d >= dst + dst_size - 2) 233 return (char *)-ENOMEM; 234 235 *d++ = '\\'; 236 *d++ = *s; 237 break; 238 default: 239 if (d >= dst + dst_size - 1) 240 return (char *)-ENOMEM; 241 242 *d++ = *s; 243 } 244 } 245 if (d >= dst + dst_size - 1) 246 return (char *)-ENOMEM; 247 248 *d = '\0'; 249 return d; 250 } 251 252 /* 253 * @domain_id: The domain ID extracted from the audit message (if the first part 254 * of @pattern is REGEX_LANDLOCK_PREFIX). It is set to 0 if the domain ID is 255 * not found. 256 */ 257 static int audit_match_record(int audit_fd, const __u16 type, 258 const char *const pattern, __u64 *domain_id) 259 { 260 struct audit_message msg, last_mismatch = {}; 261 int ret, err = 0; 262 int num_type_match = 0; 263 regmatch_t matches[2]; 264 regex_t regex; 265 266 ret = regcomp(®ex, pattern, 0); 267 if (ret) 268 return -EINVAL; 269 270 /* 271 * Reads records until one matches both the expected type and the 272 * pattern. Type-matching records with non-matching content are 273 * silently consumed, which handles stale domain deallocation records 274 * from a previous test emitted asynchronously by kworker threads. 275 */ 276 while (true) { 277 memset(&msg, 0, sizeof(msg)); 278 err = audit_recv(audit_fd, &msg); 279 if (err) { 280 if (num_type_match) { 281 printf("DATA: %s\n", last_mismatch.data); 282 printf("ERROR: %d record(s) matched type %u" 283 " but not pattern: %s\n", 284 num_type_match, type, pattern); 285 } 286 goto out; 287 } 288 289 if (type && msg.header.nlmsg_type != type) 290 continue; 291 292 ret = regexec(®ex, msg.data, ARRAY_SIZE(matches), matches, 293 0); 294 if (!ret) 295 break; 296 297 num_type_match++; 298 last_mismatch = msg; 299 } 300 301 if (domain_id) { 302 *domain_id = 0; 303 if (matches[1].rm_so != -1) { 304 int match_len = matches[1].rm_eo - matches[1].rm_so; 305 /* The maximal characters of a 2^64 hexadecimal number is 17. */ 306 char dom_id[18]; 307 308 if (match_len > 0 && match_len < sizeof(dom_id)) { 309 memcpy(dom_id, msg.data + matches[1].rm_so, 310 match_len); 311 dom_id[match_len] = '\0'; 312 if (domain_id) 313 *domain_id = strtoull(dom_id, NULL, 16); 314 } 315 } 316 } 317 318 out: 319 regfree(®ex); 320 return err; 321 } 322 323 static int __maybe_unused matches_log_domain_allocated(int audit_fd, pid_t pid, 324 __u64 *domain_id) 325 { 326 static const char log_template[] = REGEX_LANDLOCK_PREFIX 327 " status=allocated mode=enforcing pid=%d uid=[0-9]\\+" 328 " exe=\"[^\"]\\+\" comm=\".*_test\"$"; 329 char log_match[sizeof(log_template) + 10]; 330 int log_match_len; 331 332 log_match_len = 333 snprintf(log_match, sizeof(log_match), log_template, pid); 334 if (log_match_len >= sizeof(log_match)) 335 return -E2BIG; 336 337 return audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, 338 domain_id); 339 } 340 341 /* 342 * Matches a domain deallocation record. When expected_domain_id is non-zero, 343 * the pattern includes the specific domain ID so that stale deallocation 344 * records from a previous test (with a different domain ID) are skipped by 345 * audit_match_record(), waiting for the asynchronous kworker deallocation with 346 * the default patient timeout. 347 * 348 * When expected_domain_id is zero, the caller is probing for any dealloc record 349 * that may or may not arrive. Temporarily lowers the socket timeout to 350 * audit_tv_fast for this probe so it returns promptly when no record is 351 * pending; restores audit_tv_default after. 352 */ 353 static int __maybe_unused 354 matches_log_domain_deallocated(int audit_fd, unsigned int num_denials, 355 __u64 expected_domain_id, __u64 *domain_id) 356 { 357 static const char log_template[] = REGEX_LANDLOCK_PREFIX 358 " status=deallocated denials=%u$"; 359 static const char log_template_with_id[] = 360 "^audit([0-9.:]\\+): domain=\\(%llx\\)" 361 " status=deallocated denials=%u$"; 362 char log_match[sizeof(log_template_with_id) + 32]; 363 int log_match_len, err; 364 365 if (expected_domain_id) 366 log_match_len = snprintf(log_match, sizeof(log_match), 367 log_template_with_id, 368 (unsigned long long)expected_domain_id, 369 num_denials); 370 else 371 log_match_len = snprintf(log_match, sizeof(log_match), 372 log_template, num_denials); 373 374 if (log_match_len >= sizeof(log_match)) 375 return -E2BIG; 376 377 if (!expected_domain_id) { 378 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, 379 &audit_tv_fast, sizeof(audit_tv_fast))) 380 return -errno; 381 } 382 383 err = audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, 384 domain_id); 385 386 if (!expected_domain_id) { 387 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, 388 &audit_tv_default, sizeof(audit_tv_default)) && 389 !err) 390 err = -errno; 391 } 392 393 return err; 394 } 395 396 struct audit_records { 397 size_t access; 398 size_t domain; 399 }; 400 401 /* 402 * Counts remaining audit records by type, skipping domain deallocation records. 403 * Deallocation records are emitted asynchronously from kworker threads after a 404 * previous test's child has exited, so they can arrive after the drain in 405 * audit_init() and after the preceding audit_match_record() call. Allocation 406 * records are emitted synchronously during landlock_log_denial() in the current 407 * test's syscall context, so only those are counted in records->domain. 408 * 409 * Temporarily lowers SO_RCVTIMEO to audit_tv_fast for the read loop: this is a 410 * "no record expected" path that should terminate on the first -EAGAIN. The 411 * default patient timeout is restored on exit for subsequent 412 * audit_match_record() callers. 413 */ 414 static int audit_count_records(int audit_fd, struct audit_records *records) 415 { 416 static const char dealloc_pattern[] = REGEX_LANDLOCK_PREFIX 417 " status=deallocated "; 418 struct audit_message msg; 419 regex_t dealloc_re; 420 int ret, err = 0; 421 422 ret = regcomp(&dealloc_re, dealloc_pattern, 0); 423 if (ret) 424 return -ENOMEM; 425 426 records->access = 0; 427 records->domain = 0; 428 429 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast, 430 sizeof(audit_tv_fast))) { 431 err = -errno; 432 goto out; 433 } 434 435 do { 436 memset(&msg, 0, sizeof(msg)); 437 err = audit_recv(audit_fd, &msg); 438 if (err) { 439 if (err == -EAGAIN) 440 err = 0; 441 break; 442 } 443 444 switch (msg.header.nlmsg_type) { 445 case AUDIT_LANDLOCK_ACCESS: 446 records->access++; 447 break; 448 case AUDIT_LANDLOCK_DOMAIN: 449 ret = regexec(&dealloc_re, msg.data, 0, NULL, 0); 450 if (ret == REG_NOMATCH) { 451 records->domain++; 452 } else if (ret != 0) { 453 err = -EIO; 454 goto out; 455 } 456 break; 457 } 458 } while (true); 459 460 out: 461 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, 462 sizeof(audit_tv_default)) && 463 !err) 464 err = -errno; 465 regfree(&dealloc_re); 466 return err; 467 } 468 469 static int audit_init(void) 470 { 471 int fd, err; 472 473 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT); 474 if (fd < 0) 475 return -errno; 476 477 err = audit_set_status(fd, AUDIT_STATUS_ENABLED, 1); 478 if (err) 479 goto err_close; 480 481 err = audit_set_status(fd, AUDIT_STATUS_PID, getpid()); 482 if (err) 483 goto err_close; 484 485 /* Uses the fast timeout to drain stale records below. */ 486 err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast, 487 sizeof(audit_tv_fast)); 488 if (err) { 489 err = -errno; 490 goto err_close; 491 } 492 493 /* 494 * Drains stale audit records that accumulated in the kernel backlog 495 * while no audit daemon socket was open. This happens when non-audit 496 * Landlock tests generate records while audit_enabled is non-zero (e.g. 497 * from boot configuration), or when domain deallocation records arrive 498 * asynchronously after a previous test's socket was closed. 499 */ 500 while (audit_recv(fd, NULL) == 0) 501 ; 502 503 /* 504 * Restores the default timeout for audit_match_record() callers that 505 * expect a record to arrive. Paths that expect no record restore the 506 * fast timeout locally (audit_count_records(), the expected_domain_id 507 * == 0 probe in matches_log_domain_deallocated()). 508 */ 509 err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, 510 sizeof(audit_tv_default)); 511 if (err) { 512 err = -errno; 513 goto err_close; 514 } 515 516 return fd; 517 518 err_close: 519 close(fd); 520 return err; 521 } 522 523 static int audit_init_filter_exe(struct audit_filter *filter, const char *path) 524 { 525 char *absolute_path = NULL; 526 527 /* It is assume that there is not already filtering rules. */ 528 filter->record_type = AUDIT_EXE; 529 if (!path) { 530 int ret = readlink("/proc/self/exe", filter->exe, 531 sizeof(filter->exe) - 1); 532 if (ret < 0) 533 return -errno; 534 535 filter->exe_len = ret; 536 return 0; 537 } 538 539 absolute_path = realpath(path, NULL); 540 if (!absolute_path) 541 return -errno; 542 543 /* No need for the terminating NULL byte. */ 544 filter->exe_len = strlen(absolute_path); 545 if (filter->exe_len > sizeof(filter->exe)) 546 return -E2BIG; 547 548 memcpy(filter->exe, absolute_path, filter->exe_len); 549 free(absolute_path); 550 return 0; 551 } 552 553 static int audit_cleanup(int audit_fd, struct audit_filter *filter) 554 { 555 struct audit_filter new_filter; 556 int err = 0; 557 558 if (audit_fd < 0 || !filter) { 559 /* 560 * Simulates audit_init_with_exe_filter() when called from 561 * FIXTURE_TEARDOWN_PARENT(). 562 */ 563 audit_fd = audit_init(); 564 if (audit_fd < 0) 565 return audit_fd; 566 567 filter = &new_filter; 568 err = audit_init_filter_exe(filter, NULL); 569 if (err) 570 goto err_close; 571 } 572 573 /* Filters might not be in place. */ 574 audit_filter_exe(audit_fd, filter, AUDIT_DEL_RULE); 575 audit_filter_drop(audit_fd, AUDIT_DEL_RULE); 576 577 err = audit_set_status(audit_fd, AUDIT_STATUS_ENABLED, 0); 578 579 err_close: 580 close(audit_fd); 581 return err; 582 } 583 584 static int audit_init_with_exe_filter(struct audit_filter *filter) 585 { 586 int fd, err; 587 588 fd = audit_init(); 589 if (fd < 0) 590 return fd; 591 592 err = audit_init_filter_exe(filter, NULL); 593 if (err) 594 goto err_close; 595 596 err = audit_filter_exe(fd, filter, AUDIT_ADD_RULE); 597 if (err) 598 goto err_close; 599 600 return fd; 601 602 err_close: 603 close(fd); 604 return err; 605 } 606