1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 4165 tz204579 * Common Development and Distribution License (the "License"). 6 4165 tz204579 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 0 stevel * Routines for writing audit records. 23 0 stevel * 24 11066 rafael * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 0 stevel * Use is subject to license terms. 26 0 stevel */ 27 0 stevel 28 0 stevel 29 0 stevel #include <sys/door.h> 30 0 stevel #include <sys/param.h> 31 0 stevel #include <sys/time.h> 32 0 stevel #include <sys/types.h> 33 0 stevel #include <sys/statvfs.h> /* for statfs */ 34 0 stevel #include <sys/vnode.h> 35 0 stevel #include <sys/file.h> 36 0 stevel #include <sys/vfs.h> 37 0 stevel #include <sys/user.h> 38 0 stevel #include <sys/uio.h> 39 0 stevel #include <sys/reboot.h> 40 0 stevel #include <sys/kmem.h> /* for KM_SLEEP */ 41 0 stevel #include <sys/resource.h> /* for RLIM_INFINITY */ 42 0 stevel #include <sys/cmn_err.h> /* panic */ 43 0 stevel #include <sys/systm.h> 44 0 stevel #include <sys/debug.h> 45 0 stevel #include <sys/sysmacros.h> 46 0 stevel #include <sys/syscall.h> 47 0 stevel #include <sys/zone.h> 48 0 stevel 49 0 stevel #include <c2/audit.h> 50 0 stevel #include <c2/audit_kernel.h> 51 0 stevel #include <c2/audit_record.h> 52 0 stevel #include <c2/audit_kevents.h> 53 0 stevel #include <c2/audit_door_infc.h> 54 0 stevel 55 0 stevel static void au_dequeue(au_kcontext_t *, au_buff_t *); 56 0 stevel static void audit_async_finish_backend(void *); 57 0 stevel static int audit_sync_block(au_kcontext_t *); 58 0 stevel /* 59 0 stevel * each of these two tables are indexed by the values AU_DBUF_COMPLETE 60 0 stevel * through AU_DBUF_LAST; the content is the next state value. The 61 0 stevel * first table determines the next state for a buffer which is not the 62 0 stevel * end of a record and the second table determines the state for a 63 0 stevel * buffer which is the end of a record. The initial state is 64 0 stevel * AU_DBUF_COMPLETE. 65 0 stevel */ 66 0 stevel static int state_if_part[] = { 67 0 stevel AU_DBUF_FIRST, AU_DBUF_MIDDLE, AU_DBUF_MIDDLE, AU_DBUF_FIRST}; 68 0 stevel static int state_if_not_part[] = { 69 0 stevel AU_DBUF_COMPLETE, AU_DBUF_LAST, AU_DBUF_LAST, AU_DBUF_COMPLETE}; 70 0 stevel /* 71 0 stevel * Write to an audit descriptor. 72 0 stevel * Add the au_membuf to the descriptor chain and free the chain passed in. 73 0 stevel */ 74 0 stevel void 75 0 stevel au_uwrite(m) 76 0 stevel token_t *m; 77 0 stevel { 78 0 stevel au_write(&(u_ad), m); 79 0 stevel } 80 0 stevel 81 0 stevel void 82 0 stevel au_write(caddr_t *d, token_t *m) 83 0 stevel { 84 0 stevel if (d == NULL) { 85 0 stevel au_toss_token(m); 86 0 stevel return; 87 0 stevel } 88 0 stevel if (m == (token_t *)0) { 89 0 stevel printf("au_write: null token\n"); 90 0 stevel return; 91 0 stevel } 92 0 stevel 93 0 stevel if (*d == NULL) 94 0 stevel *d = (caddr_t)m; 95 0 stevel else 96 0 stevel (void) au_append_rec((au_buff_t *)*d, m, AU_PACK); 97 0 stevel } 98 0 stevel 99 0 stevel /* 100 0 stevel * Close an audit descriptor. 101 0 stevel * Use the second parameter to indicate if it should be written or not. 102 0 stevel */ 103 0 stevel void 104 7753 Ton au_close(au_kcontext_t *kctx, caddr_t *d, int flag, au_event_t e_type, 105 7753 Ton au_emod_t e_mod) 106 0 stevel { 107 0 stevel token_t *dchain; /* au_membuf chain which is the tokens */ 108 0 stevel t_audit_data_t *tad = U2A(u); 109 0 stevel 110 0 stevel ASSERT(tad != NULL); 111 0 stevel ASSERT(d != NULL); 112 0 stevel ASSERT(kctx != NULL); 113 0 stevel 114 0 stevel if ((dchain = (token_t *)*d) == (token_t *)NULL) 115 0 stevel return; 116 0 stevel 117 0 stevel *d = NULL; 118 0 stevel 119 0 stevel /* 120 0 stevel * If async then defer; or if requested, defer the closing/queueing to 121 0 stevel * syscall end, unless no syscall is active or the syscall is _exit. 122 0 stevel */ 123 0 stevel if ((flag & AU_DONTBLOCK) || ((flag & AU_DEFER) && 124 0 stevel (tad->tad_scid != 0) && (tad->tad_scid != SYS_exit))) { 125 0 stevel au_close_defer(dchain, flag, e_type, e_mod); 126 0 stevel return; 127 0 stevel } 128 0 stevel au_close_time(kctx, dchain, flag, e_type, e_mod, NULL); 129 0 stevel } 130 0 stevel 131 0 stevel /* 132 0 stevel * Defer closing/queueing of an audit descriptor. For async events, queue 133 0 stevel * via softcall. Otherwise, defer by queueing the record onto the tad; at 134 0 stevel * syscall end time it will be pulled off. 135 0 stevel */ 136 0 stevel void 137 7753 Ton au_close_defer(token_t *dchain, int flag, au_event_t e_type, au_emod_t e_mod) 138 0 stevel { 139 0 stevel au_defer_info_t *attr; 140 0 stevel t_audit_data_t *tad = U2A(u); 141 0 stevel 142 0 stevel ASSERT(tad != NULL); 143 0 stevel 144 0 stevel /* If not to be written, toss the record. */ 145 0 stevel if ((flag & AU_OK) == 0) { 146 0 stevel au_toss_token(dchain); 147 0 stevel return; 148 0 stevel } 149 0 stevel 150 0 stevel attr = kmem_alloc(sizeof (au_defer_info_t), KM_NOSLEEP); 151 0 stevel /* If no mem available, failing silently is the best recourse */ 152 0 stevel if (attr == NULL) { 153 0 stevel au_toss_token(dchain); 154 0 stevel return; 155 0 stevel } 156 0 stevel 157 0 stevel attr->audi_next = NULL; 158 0 stevel attr->audi_ad = dchain; 159 0 stevel attr->audi_e_type = e_type; 160 0 stevel attr->audi_e_mod = e_mod; 161 0 stevel attr->audi_flag = flag; 162 0 stevel gethrestime(&attr->audi_atime); 163 0 stevel 164 0 stevel /* 165 0 stevel * All async events must be queued via softcall to avoid possible 166 0 stevel * sleeping in high interrupt context. softcall will ensure it's 167 0 stevel * done on a dedicated software-level interrupt thread. 168 0 stevel */ 169 0 stevel if (flag & AU_DONTBLOCK) { 170 0 stevel softcall(audit_async_finish_backend, attr); 171 0 stevel audit_async_done(NULL, 0); 172 0 stevel return; 173 0 stevel } 174 0 stevel 175 0 stevel /* 176 0 stevel * If not an async event, defer by queuing onto the tad until 177 0 stevel * syscall end. No locking is needed because the tad is per-thread. 178 0 stevel */ 179 0 stevel if (tad->tad_defer_head) 180 0 stevel tad->tad_defer_tail->audi_next = attr; 181 0 stevel else 182 0 stevel tad->tad_defer_head = attr; 183 0 stevel tad->tad_defer_tail = attr; 184 0 stevel } 185 0 stevel 186 0 stevel 187 0 stevel /* 188 0 stevel * Save the time in the event header. If time is not specified (i.e., pointer 189 0 stevel * is NULL), use the current time. This code is fairly ugly since it needs 190 0 stevel * to support both 32- and 64-bit environments and can be called indirectly 191 0 stevel * from both au_close() (for kernel audit) and from audit() (userland audit). 192 0 stevel */ 193 0 stevel /*ARGSUSED*/ 194 0 stevel static void 195 0 stevel au_save_time(adr_t *hadrp, timestruc_t *time, int size) 196 0 stevel { 197 0 stevel struct { 198 0 stevel uint32_t sec; 199 0 stevel uint32_t usec; 200 0 stevel } tv; 201 0 stevel timestruc_t now; 202 0 stevel 203 0 stevel if (time == NULL) { 204 0 stevel gethrestime(&now); 205 0 stevel time = &now; 206 0 stevel } 207 0 stevel 208 0 stevel #ifdef _LP64 209 0 stevel if (size) 210 0 stevel adr_int64(hadrp, (int64_t *)time, 2); 211 0 stevel else 212 0 stevel #endif 213 0 stevel { 214 0 stevel tv.sec = (uint32_t)time->tv_sec; 215 0 stevel tv.usec = (uint32_t)time->tv_nsec; 216 0 stevel adr_int32(hadrp, (int32_t *)&tv, 2); 217 0 stevel } 218 0 stevel } 219 0 stevel 220 0 stevel 221 0 stevel /* 222 0 stevel * Close an audit descriptor. 223 0 stevel * If time of event is specified, use it in the record, otherwise use the 224 0 stevel * current time. 225 0 stevel */ 226 0 stevel void 227 7753 Ton au_close_time(au_kcontext_t *kctx, token_t *dchain, int flag, au_event_t e_type, 228 7753 Ton au_emod_t e_mod, timestruc_t *etime) 229 0 stevel { 230 0 stevel token_t *record; /* au_membuf chain == the record */ 231 0 stevel int byte_count; 232 0 stevel token_t *m; /* for potential sequence token */ 233 0 stevel adr_t hadr; /* handle for header token */ 234 0 stevel adr_t sadr; /* handle for sequence token */ 235 0 stevel size_t zone_length; /* length of zonename token */ 236 0 stevel 237 0 stevel ASSERT(dchain != NULL); 238 0 stevel 239 0 stevel /* If not to be written, toss the record */ 240 0 stevel if ((flag & AU_OK) == 0) { 241 0 stevel au_toss_token(dchain); 242 0 stevel return; 243 0 stevel } 244 0 stevel /* if auditing not enabled, then don't generate an audit record */ 245 0 stevel ASSERT(kctx != NULL); 246 0 stevel 247 0 stevel if ((kctx->auk_auditstate != AUC_AUDITING) && 248 0 stevel (kctx->auk_auditstate != AUC_INIT_AUDIT)) { 249 0 stevel /* 250 0 stevel * at system boot, neither is set yet we want to generate 251 0 stevel * an audit record. 252 0 stevel */ 253 0 stevel if (e_type != AUE_SYSTEMBOOT) { 254 0 stevel au_toss_token(dchain); 255 0 stevel return; 256 0 stevel } 257 0 stevel } 258 0 stevel 259 0 stevel /* Count up the bytes used in the record. */ 260 0 stevel byte_count = au_token_size(dchain); 261 0 stevel 262 0 stevel /* 263 0 stevel * add in size of header token (always present). 264 0 stevel */ 265 0 stevel byte_count += sizeof (char) + sizeof (int32_t) + 266 0 stevel sizeof (char) + 2 * sizeof (short) + sizeof (timestruc_t); 267 0 stevel 268 0 stevel if (kctx->auk_hostaddr_valid) 269 5992 gww byte_count += sizeof (int32_t) + 270 5992 gww kctx->auk_info.ai_termid.at_type; 271 0 stevel 272 0 stevel /* 273 0 stevel * add in size of zonename token (zero if !AUDIT_ZONENAME) 274 0 stevel */ 275 0 stevel if (kctx->auk_policy & AUDIT_ZONENAME) { 276 4165 tz204579 zone_length = au_zonename_length(NULL); 277 0 stevel byte_count += zone_length; 278 0 stevel } else { 279 0 stevel zone_length = 0; 280 0 stevel } 281 0 stevel /* add in size of (optional) trailer token */ 282 0 stevel if (kctx->auk_policy & AUDIT_TRAIL) 283 0 stevel byte_count += 7; 284 0 stevel 285 0 stevel /* add in size of (optional) sequence token */ 286 0 stevel if (kctx->auk_policy & AUDIT_SEQ) 287 0 stevel byte_count += 5; 288 0 stevel 289 0 stevel /* build the header */ 290 0 stevel if (kctx->auk_hostaddr_valid) 291 0 stevel record = au_to_header_ex(byte_count, e_type, e_mod); 292 0 stevel else 293 0 stevel record = au_to_header(byte_count, e_type, e_mod); 294 0 stevel 295 0 stevel /* 296 0 stevel * If timestamp was specified, save it in header now. Otherwise, 297 0 stevel * save reference to header so we can update time/data later 298 0 stevel * and artificially adjust pointer to the time/date field of header. 299 0 stevel */ 300 0 stevel adr_start(&hadr, memtod(record, char *)); 301 0 stevel hadr.adr_now += sizeof (char) + sizeof (int32_t) + 302 0 stevel sizeof (char) + 2 * sizeof (short); 303 0 stevel if (kctx->auk_hostaddr_valid) 304 0 stevel hadr.adr_now += sizeof (int32_t) + 305 0 stevel kctx->auk_info.ai_termid.at_type; 306 0 stevel if (etime != NULL) { 307 0 stevel au_save_time(&hadr, etime, 1); 308 0 stevel hadr.adr_now = (char *)NULL; 309 0 stevel } 310 0 stevel 311 0 stevel /* append body of audit record */ 312 0 stevel (void) au_append_rec(record, dchain, AU_PACK); 313 0 stevel 314 0 stevel /* add (optional) zonename token */ 315 0 stevel if (zone_length > 0) { 316 4165 tz204579 m = au_to_zonename(zone_length, NULL); 317 0 stevel (void) au_append_rec(record, m, AU_PACK); 318 0 stevel } 319 0 stevel 320 0 stevel /* Add an (optional) sequence token. NULL offset if none */ 321 0 stevel if (kctx->auk_policy & AUDIT_SEQ) { 322 0 stevel /* get the sequence token */ 323 0 stevel m = au_to_seq(); 324 0 stevel 325 0 stevel /* link to audit record (i.e. don't pack the data) */ 326 0 stevel (void) au_append_rec(record, m, AU_LINK); 327 0 stevel 328 0 stevel /* 329 0 stevel * advance to count field of sequence token by skipping 330 0 stevel * the token type byte. 331 0 stevel */ 332 0 stevel adr_start(&sadr, memtod(m, char *)); 333 0 stevel sadr.adr_now += 1; 334 0 stevel } else { 335 0 stevel sadr.adr_now = NULL; 336 0 stevel } 337 0 stevel /* add (optional) trailer token */ 338 0 stevel if (kctx->auk_policy & AUDIT_TRAIL) { 339 0 stevel (void) au_append_rec(record, au_to_trailer(byte_count), 340 0 stevel AU_PACK); 341 0 stevel } 342 0 stevel 343 0 stevel /* 344 0 stevel * 1 - use 64 bit version of audit tokens for 64 bit kernels. 345 0 stevel * 0 - use 32 bit version of audit tokens for 32 bit kernels. 346 0 stevel */ 347 0 stevel #ifdef _LP64 348 0 stevel au_enqueue(kctx, record, &hadr, &sadr, 1, flag & AU_DONTBLOCK); 349 0 stevel #else 350 0 stevel au_enqueue(kctx, record, &hadr, &sadr, 0, flag & AU_DONTBLOCK); 351 0 stevel #endif 352 0 stevel AS_INC(as_totalsize, byte_count, kctx); 353 0 stevel } 354 0 stevel 355 0 stevel /*ARGSUSED*/ 356 0 stevel void 357 0 stevel au_enqueue(au_kcontext_t *kctx, au_buff_t *m, adr_t *hadrp, adr_t *sadrp, 358 0 stevel int size, int dontblock) 359 0 stevel { 360 0 stevel if (kctx == NULL) 361 0 stevel return; 362 0 stevel 363 0 stevel mutex_enter(&(kctx->auk_queue.lock)); 364 0 stevel 365 0 stevel if (!dontblock && (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) && 366 0 stevel audit_sync_block(kctx)) { 367 0 stevel mutex_exit(&(kctx->auk_queue.lock)); 368 0 stevel au_free_rec(m); 369 0 stevel return; 370 0 stevel } 371 0 stevel 372 0 stevel /* Fill in date and time if needed */ 373 0 stevel if (hadrp->adr_now) { 374 0 stevel au_save_time(hadrp, NULL, size); 375 0 stevel } 376 0 stevel 377 0 stevel /* address will be non-zero only if AUDIT_SEQ set */ 378 0 stevel if (sadrp->adr_now) { 379 0 stevel kctx->auk_sequence++; 380 0 stevel adr_int32(sadrp, (int32_t *)&(kctx->auk_sequence), 1); 381 0 stevel } 382 0 stevel 383 0 stevel if (kctx->auk_queue.head) 384 0 stevel kctx->auk_queue.tail->next_rec = m; 385 0 stevel else 386 0 stevel kctx->auk_queue.head = m; 387 0 stevel 388 0 stevel kctx->auk_queue.tail = m; 389 0 stevel 390 0 stevel if (++(kctx->auk_queue.cnt) > 391 0 stevel kctx->auk_queue.lowater && kctx->auk_queue.rd_block) 392 0 stevel cv_broadcast(&(kctx->auk_queue.read_cv)); 393 0 stevel 394 0 stevel mutex_exit(&(kctx->auk_queue.lock)); 395 0 stevel 396 0 stevel /* count # audit records put onto kernel audit queue */ 397 0 stevel AS_INC(as_enqueue, 1, kctx); 398 0 stevel } 399 0 stevel 400 0 stevel /* 401 0 stevel * Dequeue and free buffers upto and including "freeto" 402 0 stevel * Keeps the queue lock long but acquires it only once when doing 403 0 stevel * bulk dequeueing. 404 0 stevel */ 405 0 stevel static void 406 0 stevel au_dequeue(au_kcontext_t *kctx, au_buff_t *freeto) 407 0 stevel { 408 0 stevel au_buff_t *m, *l, *lastl; 409 0 stevel int n = 0; 410 0 stevel 411 0 stevel ASSERT(kctx != NULL); 412 0 stevel 413 0 stevel mutex_enter(&(kctx->auk_queue.lock)); 414 0 stevel 415 0 stevel ASSERT(kctx->auk_queue.head != NULL); 416 0 stevel ASSERT(freeto != NULL); 417 0 stevel 418 0 stevel l = m = kctx->auk_queue.head; 419 0 stevel 420 0 stevel do { 421 0 stevel n++; 422 0 stevel lastl = l; 423 0 stevel l = l->next_rec; 424 0 stevel } while (l != NULL && freeto != lastl); 425 0 stevel 426 0 stevel kctx->auk_queue.cnt -= n; 427 0 stevel lastl->next_rec = NULL; 428 0 stevel kctx->auk_queue.head = l; 429 0 stevel 430 0 stevel /* Freeto must exist in the list */ 431 0 stevel ASSERT(freeto == lastl); 432 0 stevel 433 0 stevel if (kctx->auk_queue.cnt <= kctx->auk_queue.lowater && 434 0 stevel kctx->auk_queue.wt_block) 435 0 stevel cv_broadcast(&(kctx->auk_queue.write_cv)); 436 0 stevel 437 0 stevel mutex_exit(&(kctx->auk_queue.lock)); 438 0 stevel 439 0 stevel while (m) { 440 0 stevel l = m->next_rec; 441 0 stevel au_free_rec(m); 442 0 stevel m = l; 443 0 stevel } 444 0 stevel AS_INC(as_written, n, kctx); 445 0 stevel } 446 0 stevel 447 0 stevel /* 448 0 stevel * audit_sync_block() 449 0 stevel * If we've reached the high water mark, we look at the policy to see 450 0 stevel * if we sleep or we should drop the audit record. 451 0 stevel * This function is called with the auk_queue.lock held and the check 452 0 stevel * performed one time already as an optimization. Caller should unlock. 453 0 stevel * Returns 1 if the caller needs to free the record. 454 0 stevel */ 455 0 stevel static int 456 0 stevel audit_sync_block(au_kcontext_t *kctx) 457 0 stevel { 458 0 stevel ASSERT(MUTEX_HELD(&(kctx->auk_queue.lock))); 459 0 stevel /* 460 0 stevel * Loop while we are at the high watermark. 461 0 stevel */ 462 0 stevel do { 463 0 stevel if ((kctx->auk_auditstate != AUC_AUDITING) || 464 0 stevel (kctx->auk_policy & AUDIT_CNT)) { 465 0 stevel 466 0 stevel /* just count # of dropped audit records */ 467 0 stevel AS_INC(as_dropped, 1, kctx); 468 0 stevel 469 0 stevel return (1); 470 0 stevel } 471 0 stevel 472 0 stevel /* kick reader awake if its asleep */ 473 0 stevel if (kctx->auk_queue.rd_block && 474 0 stevel kctx->auk_queue.cnt > kctx->auk_queue.lowater) 475 0 stevel cv_broadcast(&(kctx->auk_queue.read_cv)); 476 0 stevel 477 0 stevel /* keep count of # times blocked */ 478 0 stevel AS_INC(as_wblocked, 1, kctx); 479 0 stevel 480 0 stevel /* sleep now, until woken by reader */ 481 0 stevel kctx->auk_queue.wt_block++; 482 0 stevel cv_wait(&(kctx->auk_queue.write_cv), &(kctx->auk_queue.lock)); 483 0 stevel kctx->auk_queue.wt_block--; 484 0 stevel } while (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater); 485 0 stevel 486 0 stevel return (0); 487 0 stevel } 488 0 stevel 489 0 stevel /* 490 0 stevel * audit_async_block() 491 0 stevel * if we've reached the high water mark, we look at the ahlt policy to see 492 0 stevel * if we reboot we should drop the audit record. 493 0 stevel * Returns 1 if blocked. 494 0 stevel */ 495 0 stevel static int 496 0 stevel audit_async_block(au_kcontext_t *kctx, caddr_t *rpp) 497 0 stevel { 498 0 stevel ASSERT(kctx != NULL); 499 0 stevel 500 0 stevel mutex_enter(&(kctx->auk_queue.lock)); 501 0 stevel /* see if we've reached high water mark */ 502 0 stevel if (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater) { 503 0 stevel mutex_exit(&(kctx->auk_queue.lock)); 504 0 stevel 505 0 stevel audit_async_drop(rpp, AU_BACKEND); 506 0 stevel return (1); 507 0 stevel } 508 0 stevel mutex_exit(&(kctx->auk_queue.lock)); 509 0 stevel return (0); 510 0 stevel } 511 0 stevel 512 0 stevel /* 513 0 stevel * au_door_upcall. auditdoor() may change vp without notice, so 514 0 stevel * some locking seems in order. 515 0 stevel * 516 0 stevel */ 517 0 stevel #define AGAIN_TICKS 10 518 0 stevel 519 0 stevel static int 520 0 stevel au_door_upcall(au_kcontext_t *kctx, au_dbuf_t *aubuf) 521 0 stevel { 522 0 stevel int rc; 523 0 stevel door_arg_t darg; 524 0 stevel int retry = 1; 525 0 stevel int ticks_to_wait; 526 0 stevel 527 0 stevel darg.data_ptr = (char *)aubuf; 528 0 stevel darg.data_size = AU_DBUF_HEADER + aubuf->aub_size; 529 0 stevel 530 0 stevel darg.desc_ptr = NULL; 531 0 stevel darg.desc_num = 0; 532 0 stevel 533 0 stevel while (retry == 1) { 534 0 stevel /* non-zero means return results expected */ 535 0 stevel darg.rbuf = (char *)aubuf; 536 0 stevel darg.rsize = darg.data_size; 537 0 stevel 538 0 stevel retry = 0; 539 0 stevel mutex_enter(&(kctx->auk_svc_lock)); 540 6997 jwadams rc = door_upcall(kctx->auk_current_vp, &darg, NULL, 541 6997 jwadams SIZE_MAX, 0); 542 6263 seb if (rc != 0) { 543 0 stevel mutex_exit(&(kctx->auk_svc_lock)); 544 0 stevel if (rc == EAGAIN) 545 0 stevel ticks_to_wait = AGAIN_TICKS; 546 0 stevel else 547 0 stevel return (rc); 548 0 stevel 549 0 stevel mutex_enter(&(kctx->auk_eagain_mutex)); 550 11066 rafael (void) cv_reltimedwait(&(kctx->auk_eagain_cv), 551 11066 rafael &(kctx->auk_eagain_mutex), ticks_to_wait, 552 11066 rafael TR_CLOCK_TICK); 553 0 stevel mutex_exit(&(kctx->auk_eagain_mutex)); 554 0 stevel 555 0 stevel retry = 1; 556 0 stevel } else 557 0 stevel mutex_exit(&(kctx->auk_svc_lock)); /* no retry */ 558 0 stevel } /* end while (retry == 1) */ 559 0 stevel if (darg.rbuf == NULL) 560 0 stevel return (-1); 561 0 stevel 562 0 stevel /* return code from door server */ 563 0 stevel return (*(int *)darg.rbuf); 564 0 stevel } 565 0 stevel 566 0 stevel /* 567 0 stevel * Write an audit control message to the door handle. The message 568 0 stevel * structure depends on message_code and at present the only control 569 0 stevel * message defined is for a policy change. These are infrequent, 570 0 stevel * so no memory is held for control messages. 571 0 stevel */ 572 0 stevel int 573 0 stevel au_doormsg(au_kcontext_t *kctx, uint32_t message_code, void *message) 574 0 stevel { 575 0 stevel int rc; 576 0 stevel au_dbuf_t *buf; 577 0 stevel size_t alloc_size; 578 0 stevel 579 0 stevel switch (message_code) { 580 0 stevel case AU_DBUF_POLICY: 581 0 stevel alloc_size = AU_DBUF_HEADER + sizeof (uint32_t); 582 0 stevel buf = kmem_alloc(alloc_size, KM_SLEEP); 583 0 stevel buf->aub_size = sizeof (uint32_t); 584 0 stevel *(uint32_t *)buf->aub_buf = *(uint32_t *)message; 585 0 stevel break; 586 0 stevel case AU_DBUF_SHUTDOWN: 587 0 stevel alloc_size = AU_DBUF_HEADER; 588 0 stevel buf = kmem_alloc(alloc_size, KM_SLEEP); 589 0 stevel buf->aub_size = 0; 590 0 stevel break; 591 0 stevel default: 592 0 stevel return (1); 593 0 stevel } 594 0 stevel 595 0 stevel buf->aub_type = AU_DBUF_NOTIFY | message_code; 596 0 stevel rc = au_door_upcall(kctx, buf); 597 0 stevel kmem_free(buf, alloc_size); 598 0 stevel 599 0 stevel return (rc); 600 0 stevel } 601 0 stevel 602 0 stevel /* 603 0 stevel * Write audit information to the door handle. au_doorio is called with 604 0 stevel * one or more complete audit records on the queue and outputs those 605 0 stevel * records in buffers of up to auk_queue.buflen in size. 606 0 stevel */ 607 0 stevel int 608 0 stevel au_doorio(au_kcontext_t *kctx) { 609 0 stevel off_t off; /* space used in buffer */ 610 0 stevel ssize_t used; /* space used in au_membuf */ 611 0 stevel token_t *cAR; /* current AR being processed */ 612 0 stevel token_t *cMB; /* current au_membuf being processed */ 613 0 stevel token_t *sp; /* last AR processed */ 614 0 stevel char *bp; /* start of free space in staging buffer */ 615 0 stevel unsigned char *cp; /* ptr to data to be moved */ 616 0 stevel int error; /* return from door upcall */ 617 0 stevel 618 0 stevel /* 619 0 stevel * size (data left in au_membuf - space in buffer) 620 0 stevel */ 621 0 stevel ssize_t sz; 622 0 stevel ssize_t len; /* len of data to move, size of AR */ 623 0 stevel ssize_t curr_sz = 0; /* amount of data written during now */ 624 0 stevel /* 625 0 stevel * partial_state is AU_DBUF_COMPLETE...LAST; see audit_door_infc.h 626 0 stevel */ 627 0 stevel int part = 0; /* partial audit record written */ 628 0 stevel int partial_state = AU_DBUF_COMPLETE; 629 0 stevel /* 630 0 stevel * Has the write buffer changed length due to a auditctl(2)? 631 0 stevel * Initial allocation is from audit_start.c/audit_init() 632 0 stevel */ 633 0 stevel if (kctx->auk_queue.bufsz != kctx->auk_queue.buflen) { 634 0 stevel kmem_free(kctx->auk_dbuffer, AU_DBUF_HEADER + 635 0 stevel kctx->auk_queue.buflen); 636 0 stevel 637 0 stevel kctx->auk_dbuffer = kmem_alloc(AU_DBUF_HEADER + 638 0 stevel kctx->auk_queue.bufsz, KM_SLEEP); 639 0 stevel 640 0 stevel /* omit the 64 bit header */ 641 0 stevel kctx->auk_queue.buflen = kctx->auk_queue.bufsz; 642 0 stevel } 643 0 stevel if (!kctx->auk_queue.head) 644 0 stevel goto nodata; 645 0 stevel 646 0 stevel sp = NULL; /* no record copied */ 647 0 stevel off = 0; /* no space used in buffer */ 648 0 stevel used = 0; /* no data processed in au_membuf */ 649 0 stevel cAR = kctx->auk_queue.head; /* start at head of queue */ 650 0 stevel cMB = cAR; /* start with first au_membuf of record */ 651 0 stevel 652 0 stevel /* start at beginning of buffer */ 653 0 stevel bp = &(kctx->auk_dbuffer->aub_buf[0]); 654 0 stevel 655 0 stevel while (cMB) { 656 0 stevel part = 1; /* indicate audit record being processed */ 657 0 stevel 658 0 stevel cp = memtod(cMB, unsigned char *); /* buffer ptr */ 659 0 stevel 660 0 stevel sz = (ssize_t)cMB->len - used; /* data left in au_membuf */ 661 0 stevel /* len to move */ 662 0 stevel len = (ssize_t)MIN(sz, kctx->auk_queue.buflen - off); 663 0 stevel 664 0 stevel /* move the data */ 665 0 stevel bcopy(cp + used, bp + off, len); 666 0 stevel used += len; /* update used au_membuf */ 667 0 stevel off += len; /* update offset into buffer */ 668 0 stevel 669 0 stevel if (used >= (ssize_t)cMB->len) { 670 0 stevel /* advance to next au_membuf */ 671 0 stevel used = 0; 672 0 stevel cMB = cMB->next_buf; 673 0 stevel } 674 0 stevel if (cMB == NULL) { 675 0 stevel /* advance to next audit record */ 676 0 stevel sp = cAR; 677 0 stevel cAR = cAR->next_rec; 678 0 stevel cMB = cAR; 679 0 stevel part = 0; /* have a complete record */ 680 0 stevel } 681 0 stevel error = 0; 682 0 stevel if ((kctx->auk_queue.buflen == off) || (part == 0)) { 683 0 stevel if (part) 684 0 stevel partial_state = state_if_part[partial_state]; 685 0 stevel else 686 0 stevel partial_state = 687 0 stevel state_if_not_part[partial_state]; 688 0 stevel 689 0 stevel kctx->auk_dbuffer->aub_type = partial_state; 690 0 stevel kctx->auk_dbuffer->aub_size = off; 691 0 stevel error = au_door_upcall(kctx, kctx->auk_dbuffer); 692 0 stevel if (error != 0) 693 0 stevel goto nodata; 694 0 stevel /* 695 0 stevel * if we've successfully written an audit record, 696 0 stevel * free records up to last full record copied 697 0 stevel */ 698 0 stevel if (sp) 699 0 stevel au_dequeue(kctx, sp); 700 0 stevel 701 0 stevel /* Update size */ 702 0 stevel curr_sz += off; 703 0 stevel 704 0 stevel /* reset auk_dbuffer pointers */ 705 0 stevel sp = NULL; 706 0 stevel off = 0; 707 0 stevel } 708 0 stevel } /* while(cMB) */ 709 0 stevel nodata: 710 0 stevel return (error); 711 0 stevel } 712 0 stevel 713 0 stevel /* 714 0 stevel * Clean up thread audit state to clear out asynchronous audit record 715 0 stevel * generation error recovery processing. Note that this is done on a 716 0 stevel * per-thread basis and thus does not need any locking. 717 0 stevel */ 718 0 stevel void 719 0 stevel audit_async_done(caddr_t *rpp, int flags) 720 0 stevel { 721 0 stevel t_audit_data_t *tad = U2A(u); 722 0 stevel 723 0 stevel /* clean up the tad unless called from softcall backend */ 724 0 stevel if (!(flags & AU_BACKEND)) { 725 0 stevel ASSERT(tad != NULL); 726 0 stevel ASSERT(tad->tad_ctrl & PAD_ERRJMP); 727 0 stevel 728 0 stevel tad->tad_ctrl &= ~PAD_ERRJMP; 729 0 stevel tad->tad_errjmp = NULL; 730 0 stevel } 731 0 stevel 732 0 stevel /* clean out partial audit record */ 733 0 stevel if ((rpp != NULL) && (*rpp != NULL)) { 734 0 stevel au_toss_token((au_buff_t *)*rpp); 735 0 stevel *rpp = NULL; 736 0 stevel } 737 0 stevel } 738 0 stevel 739 0 stevel /* 740 0 stevel * implement the audit policy for asynchronous events generated within 741 0 stevel * the kernel. 742 0 stevel * XXX might need locks around audit_policy check. 743 0 stevel */ 744 0 stevel void 745 0 stevel audit_async_drop(caddr_t *rpp, int flags) 746 0 stevel { 747 0 stevel au_kcontext_t *kctx; 748 0 stevel 749 0 stevel /* could not generate audit record, clean up */ 750 0 stevel audit_async_done((caddr_t *)rpp, flags); 751 0 stevel 752 4197 paulson kctx = GET_KCTX_GZ; 753 4197 paulson 754 0 stevel /* just drop the record and return */ 755 0 stevel if (((audit_policy & AUDIT_AHLT) == 0) || 756 0 stevel (kctx->auk_auditstate == AUC_INIT_AUDIT)) { 757 0 stevel /* just count # of dropped audit records */ 758 0 stevel AS_INC(as_dropped, 1, kctx); 759 0 stevel return; 760 0 stevel } 761 0 stevel 762 0 stevel /* 763 0 stevel * There can be a lot of data in the audit queue. We 764 0 stevel * will first sync the file systems then attempt to 765 0 stevel * shutdown the kernel so that a memory dump is 766 0 stevel * performed. 767 0 stevel */ 768 0 stevel sync(); 769 0 stevel sync(); 770 0 stevel 771 0 stevel /* 772 0 stevel * now shut down. What a cruel world it has been 773 0 stevel */ 774 0 stevel panic("non-attributable halt. should dump core"); 775 0 stevel /* No return */ 776 0 stevel } 777 0 stevel 778 0 stevel int 779 7753 Ton audit_async_start(label_t *jb, au_event_t event, int sorf) 780 0 stevel { 781 0 stevel t_audit_data_t *tad = U2A(u); 782 0 stevel au_state_t estate; 783 0 stevel int success = 0, failure = 0; 784 4197 paulson au_kcontext_t *kctx = GET_KCTX_GZ; 785 0 stevel 786 0 stevel /* if audit state off, then no audit record generation */ 787 0 stevel if ((kctx->auk_auditstate != AUC_AUDITING) && 788 0 stevel (kctx->auk_auditstate != AUC_INIT_AUDIT)) 789 0 stevel return (1); 790 0 stevel 791 0 stevel /* 792 0 stevel * preselect asynchronous event 793 0 stevel * XXX should we check for out-of-range??? 794 0 stevel */ 795 0 stevel estate = kctx->auk_ets[event]; 796 0 stevel 797 0 stevel if (sorf & AUM_SUCC) 798 0 stevel success = kctx->auk_info.ai_mask.as_success & estate; 799 0 stevel if (sorf & AUM_FAIL) 800 0 stevel failure = kctx->auk_info.ai_mask.as_failure & estate; 801 0 stevel 802 0 stevel if ((success | failure) == NULL) 803 0 stevel return (1); 804 0 stevel 805 0 stevel ASSERT(tad->tad_errjmp == NULL); 806 0 stevel tad->tad_errjmp = (void *)jb; 807 0 stevel tad->tad_ctrl |= PAD_ERRJMP; 808 0 stevel 809 0 stevel return (0); 810 0 stevel } 811 0 stevel 812 0 stevel /* 813 0 stevel * Complete auditing of an async event. The AU_DONTBLOCK flag to au_close will 814 0 stevel * result in the backend routine being invoked from softcall, so all the real 815 0 stevel * work can be done in a safe context. 816 0 stevel */ 817 0 stevel void 818 7753 Ton audit_async_finish(caddr_t *ad, au_event_t aid, au_emod_t amod) 819 0 stevel { 820 0 stevel au_kcontext_t *kctx; 821 0 stevel 822 4197 paulson kctx = GET_KCTX_GZ; 823 0 stevel 824 0 stevel au_close(kctx, ad, AU_DONTBLOCK | AU_OK, aid, PAD_NONATTR|amod); 825 0 stevel } 826 0 stevel 827 0 stevel /* 828 0 stevel * Backend routine to complete an async audit. Invoked from softcall. 829 0 stevel * (Note: the blocking and the queuing below both involve locking which can't 830 0 stevel * be done safely in high interrupt context due to the chance of sleeping on 831 0 stevel * the corresponding adaptive mutex. Hence the softcall.) 832 0 stevel */ 833 0 stevel static void 834 0 stevel audit_async_finish_backend(void *addr) 835 0 stevel { 836 0 stevel au_kcontext_t *kctx; 837 0 stevel au_defer_info_t *attr = (au_defer_info_t *)addr; 838 0 stevel 839 0 stevel if (attr == NULL) 840 0 stevel return; /* won't happen unless softcall is broken */ 841 0 stevel 842 4197 paulson kctx = GET_KCTX_GZ; 843 0 stevel 844 0 stevel if (audit_async_block(kctx, (caddr_t *)&attr->audi_ad)) { 845 0 stevel kmem_free(attr, sizeof (au_defer_info_t)); 846 0 stevel return; 847 0 stevel } 848 0 stevel 849 0 stevel /* 850 0 stevel * Call au_close_time to complete the audit with the saved values. 851 0 stevel * 852 0 stevel * For the exit-prom event, use the current time instead of the 853 0 stevel * saved time as a better approximation. (Because the time saved via 854 0 stevel * gethrestime during prom-exit handling would not yet be caught up 855 0 stevel * after the system was idled in the debugger for a period of time.) 856 0 stevel */ 857 0 stevel if (attr->audi_e_type == AUE_EXITPROM) { 858 0 stevel au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag, 859 0 stevel attr->audi_e_type, attr->audi_e_mod, NULL); 860 0 stevel } else { 861 0 stevel au_close_time(kctx, (token_t *)attr->audi_ad, attr->audi_flag, 862 0 stevel attr->audi_e_type, attr->audi_e_mod, &attr->audi_atime); 863 0 stevel } 864 0 stevel 865 0 stevel AS_INC(as_generated, 1, kctx); 866 0 stevel AS_INC(as_nonattrib, 1, kctx); 867 0 stevel 868 0 stevel kmem_free(attr, sizeof (au_defer_info_t)); 869 0 stevel } 870