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 /* 218 * @domain_id: The domain ID extracted from the audit message (if the first part 219 * of @pattern is REGEX_LANDLOCK_PREFIX). It is set to 0 if the domain ID is 220 * not found. 221 */ 222 static int audit_match_record(int audit_fd, const __u16 type, 223 const char *const pattern, __u64 *domain_id) 224 { 225 struct audit_message msg, last_mismatch = {}; 226 int ret, err = 0; 227 int num_type_match = 0; 228 regmatch_t matches[2]; 229 regex_t regex; 230 231 ret = regcomp(®ex, pattern, 0); 232 if (ret) 233 return -EINVAL; 234 235 /* 236 * Reads records until one matches both the expected type and the 237 * pattern. Type-matching records with non-matching content are 238 * silently consumed, which handles stale domain deallocation records 239 * from a previous test emitted asynchronously by kworker threads. 240 */ 241 while (true) { 242 memset(&msg, 0, sizeof(msg)); 243 err = audit_recv(audit_fd, &msg); 244 if (err) { 245 if (num_type_match) { 246 printf("DATA: %s\n", last_mismatch.data); 247 printf("ERROR: %d record(s) matched type %u" 248 " but not pattern: %s\n", 249 num_type_match, type, pattern); 250 } 251 goto out; 252 } 253 254 if (type && msg.header.nlmsg_type != type) 255 continue; 256 257 ret = regexec(®ex, msg.data, ARRAY_SIZE(matches), matches, 258 0); 259 if (!ret) 260 break; 261 262 num_type_match++; 263 last_mismatch = msg; 264 } 265 266 if (domain_id) { 267 *domain_id = 0; 268 if (matches[1].rm_so != -1) { 269 int match_len = matches[1].rm_eo - matches[1].rm_so; 270 /* The maximal characters of a 2^64 hexadecimal number is 17. */ 271 char dom_id[18]; 272 273 if (match_len > 0 && match_len < sizeof(dom_id)) { 274 memcpy(dom_id, msg.data + matches[1].rm_so, 275 match_len); 276 dom_id[match_len] = '\0'; 277 if (domain_id) 278 *domain_id = strtoull(dom_id, NULL, 16); 279 } 280 } 281 } 282 283 out: 284 regfree(®ex); 285 return err; 286 } 287 288 static int __maybe_unused matches_log_domain_allocated(int audit_fd, pid_t pid, 289 __u64 *domain_id) 290 { 291 static const char log_template[] = REGEX_LANDLOCK_PREFIX 292 " status=allocated mode=enforcing pid=%d uid=[0-9]\\+" 293 " exe=\"[^\"]\\+\" comm=\".*_test\"$"; 294 char log_match[sizeof(log_template) + 10]; 295 int log_match_len; 296 297 log_match_len = 298 snprintf(log_match, sizeof(log_match), log_template, pid); 299 if (log_match_len >= sizeof(log_match)) 300 return -E2BIG; 301 302 return audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, 303 domain_id); 304 } 305 306 /* 307 * Matches a domain deallocation record. When expected_domain_id is non-zero, 308 * the pattern includes the specific domain ID so that stale deallocation 309 * records from a previous test (with a different domain ID) are skipped by 310 * audit_match_record(), waiting for the asynchronous kworker deallocation with 311 * the default patient timeout. 312 * 313 * When expected_domain_id is zero, the caller is probing for any dealloc record 314 * that may or may not arrive. Temporarily lowers the socket timeout to 315 * audit_tv_fast for this probe so it returns promptly when no record is 316 * pending; restores audit_tv_default after. 317 */ 318 static int __maybe_unused 319 matches_log_domain_deallocated(int audit_fd, unsigned int num_denials, 320 __u64 expected_domain_id, __u64 *domain_id) 321 { 322 static const char log_template[] = REGEX_LANDLOCK_PREFIX 323 " status=deallocated denials=%u$"; 324 static const char log_template_with_id[] = 325 "^audit([0-9.:]\\+): domain=\\(%llx\\)" 326 " status=deallocated denials=%u$"; 327 char log_match[sizeof(log_template_with_id) + 32]; 328 int log_match_len, err; 329 330 if (expected_domain_id) 331 log_match_len = snprintf(log_match, sizeof(log_match), 332 log_template_with_id, 333 (unsigned long long)expected_domain_id, 334 num_denials); 335 else 336 log_match_len = snprintf(log_match, sizeof(log_match), 337 log_template, num_denials); 338 339 if (log_match_len >= sizeof(log_match)) 340 return -E2BIG; 341 342 if (!expected_domain_id) { 343 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, 344 &audit_tv_fast, sizeof(audit_tv_fast))) 345 return -errno; 346 } 347 348 err = audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, 349 domain_id); 350 351 if (!expected_domain_id) { 352 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, 353 &audit_tv_default, sizeof(audit_tv_default)) && 354 !err) 355 err = -errno; 356 } 357 358 return err; 359 } 360 361 struct audit_records { 362 size_t access; 363 size_t domain; 364 }; 365 366 /* 367 * Counts remaining audit records by type, skipping domain deallocation records. 368 * Deallocation records are emitted asynchronously from kworker threads after a 369 * previous test's child has exited, so they can arrive after the drain in 370 * audit_init() and after the preceding audit_match_record() call. Allocation 371 * records are emitted synchronously during landlock_log_denial() in the current 372 * test's syscall context, so only those are counted in records->domain. 373 * 374 * Temporarily lowers SO_RCVTIMEO to audit_tv_fast for the read loop: this is a 375 * "no record expected" path that should terminate on the first -EAGAIN. The 376 * default patient timeout is restored on exit for subsequent 377 * audit_match_record() callers. 378 */ 379 static int audit_count_records(int audit_fd, struct audit_records *records) 380 { 381 static const char dealloc_pattern[] = REGEX_LANDLOCK_PREFIX 382 " status=deallocated "; 383 struct audit_message msg; 384 regex_t dealloc_re; 385 int ret, err = 0; 386 387 ret = regcomp(&dealloc_re, dealloc_pattern, 0); 388 if (ret) 389 return -ENOMEM; 390 391 records->access = 0; 392 records->domain = 0; 393 394 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast, 395 sizeof(audit_tv_fast))) { 396 err = -errno; 397 goto out; 398 } 399 400 do { 401 memset(&msg, 0, sizeof(msg)); 402 err = audit_recv(audit_fd, &msg); 403 if (err) { 404 if (err == -EAGAIN) 405 err = 0; 406 break; 407 } 408 409 switch (msg.header.nlmsg_type) { 410 case AUDIT_LANDLOCK_ACCESS: 411 records->access++; 412 break; 413 case AUDIT_LANDLOCK_DOMAIN: 414 ret = regexec(&dealloc_re, msg.data, 0, NULL, 0); 415 if (ret == REG_NOMATCH) { 416 records->domain++; 417 } else if (ret != 0) { 418 err = -EIO; 419 goto out; 420 } 421 break; 422 } 423 } while (true); 424 425 out: 426 if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, 427 sizeof(audit_tv_default)) && 428 !err) 429 err = -errno; 430 regfree(&dealloc_re); 431 return err; 432 } 433 434 static int audit_init(void) 435 { 436 int fd, err; 437 438 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT); 439 if (fd < 0) 440 return -errno; 441 442 err = audit_set_status(fd, AUDIT_STATUS_ENABLED, 1); 443 if (err) 444 goto err_close; 445 446 err = audit_set_status(fd, AUDIT_STATUS_PID, getpid()); 447 if (err) 448 goto err_close; 449 450 /* Uses the fast timeout to drain stale records below. */ 451 err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast, 452 sizeof(audit_tv_fast)); 453 if (err) { 454 err = -errno; 455 goto err_close; 456 } 457 458 /* 459 * Drains stale audit records that accumulated in the kernel backlog 460 * while no audit daemon socket was open. This happens when non-audit 461 * Landlock tests generate records while audit_enabled is non-zero (e.g. 462 * from boot configuration), or when domain deallocation records arrive 463 * asynchronously after a previous test's socket was closed. 464 */ 465 while (audit_recv(fd, NULL) == 0) 466 ; 467 468 /* 469 * Restores the default timeout for audit_match_record() callers that 470 * expect a record to arrive. Paths that expect no record restore the 471 * fast timeout locally (audit_count_records(), the expected_domain_id 472 * == 0 probe in matches_log_domain_deallocated()). 473 */ 474 err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, 475 sizeof(audit_tv_default)); 476 if (err) { 477 err = -errno; 478 goto err_close; 479 } 480 481 return fd; 482 483 err_close: 484 close(fd); 485 return err; 486 } 487 488 static int audit_init_filter_exe(struct audit_filter *filter, const char *path) 489 { 490 char *absolute_path = NULL; 491 492 /* It is assume that there is not already filtering rules. */ 493 filter->record_type = AUDIT_EXE; 494 if (!path) { 495 int ret = readlink("/proc/self/exe", filter->exe, 496 sizeof(filter->exe) - 1); 497 if (ret < 0) 498 return -errno; 499 500 filter->exe_len = ret; 501 return 0; 502 } 503 504 absolute_path = realpath(path, NULL); 505 if (!absolute_path) 506 return -errno; 507 508 /* No need for the terminating NULL byte. */ 509 filter->exe_len = strlen(absolute_path); 510 if (filter->exe_len > sizeof(filter->exe)) 511 return -E2BIG; 512 513 memcpy(filter->exe, absolute_path, filter->exe_len); 514 free(absolute_path); 515 return 0; 516 } 517 518 static int audit_cleanup(int audit_fd, struct audit_filter *filter) 519 { 520 struct audit_filter new_filter; 521 int err = 0; 522 523 if (audit_fd < 0 || !filter) { 524 /* 525 * Simulates audit_init_with_exe_filter() when called from 526 * FIXTURE_TEARDOWN_PARENT(). 527 */ 528 audit_fd = audit_init(); 529 if (audit_fd < 0) 530 return audit_fd; 531 532 filter = &new_filter; 533 err = audit_init_filter_exe(filter, NULL); 534 if (err) 535 goto err_close; 536 } 537 538 /* Filters might not be in place. */ 539 audit_filter_exe(audit_fd, filter, AUDIT_DEL_RULE); 540 audit_filter_drop(audit_fd, AUDIT_DEL_RULE); 541 542 err = audit_set_status(audit_fd, AUDIT_STATUS_ENABLED, 0); 543 544 err_close: 545 close(audit_fd); 546 return err; 547 } 548 549 static int audit_init_with_exe_filter(struct audit_filter *filter) 550 { 551 int fd, err; 552 553 fd = audit_init(); 554 if (fd < 0) 555 return fd; 556 557 err = audit_init_filter_exe(filter, NULL); 558 if (err) 559 goto err_close; 560 561 err = audit_filter_exe(fd, filter, AUDIT_ADD_RULE); 562 if (err) 563 goto err_close; 564 565 return fd; 566 567 err_close: 568 close(fd); 569 return err; 570 } 571