0
|
1 |
/*
|
|
2 |
* CDDL HEADER START
|
|
3 |
*
|
|
4 |
* The contents of this file are subject to the terms of the
|
|
5 |
* Common Development and Distribution License, Version 1.0 only
|
|
6 |
* (the "License"). You may not use this file except in compliance
|
|
7 |
* with the License.
|
|
8 |
*
|
|
9 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
10 |
* or http://www.opensolaris.org/os/licensing.
|
|
11 |
* See the License for the specific language governing permissions
|
|
12 |
* and limitations under the License.
|
|
13 |
*
|
|
14 |
* When distributing Covered Code, include this CDDL HEADER in each
|
|
15 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
16 |
* If applicable, add the following below this CDDL HEADER, with the
|
|
17 |
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
18 |
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
19 |
*
|
|
20 |
* CDDL HEADER END
|
|
21 |
*/
|
|
22 |
/*
|
898
|
23 |
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
0
|
24 |
* Use is subject to license terms.
|
|
25 |
*/
|
|
26 |
|
|
27 |
/*
|
|
28 |
* This file contains the audit hook support code for auditing.
|
|
29 |
*/
|
|
30 |
|
|
31 |
#pragma ident "%Z%%M% %I% %E% SMI"
|
|
32 |
|
|
33 |
#include <sys/types.h>
|
|
34 |
#include <sys/proc.h>
|
|
35 |
#include <sys/vnode.h>
|
|
36 |
#include <sys/vfs.h>
|
|
37 |
#include <sys/file.h>
|
|
38 |
#include <sys/user.h>
|
|
39 |
#include <sys/stropts.h>
|
|
40 |
#include <sys/systm.h>
|
|
41 |
#include <sys/pathname.h>
|
|
42 |
#include <sys/syscall.h>
|
|
43 |
#include <sys/fcntl.h>
|
|
44 |
#include <sys/ipc_impl.h>
|
|
45 |
#include <sys/msg_impl.h>
|
|
46 |
#include <sys/sem_impl.h>
|
|
47 |
#include <sys/shm_impl.h>
|
|
48 |
#include <sys/kmem.h> /* for KM_SLEEP */
|
|
49 |
#include <sys/socket.h>
|
|
50 |
#include <sys/cmn_err.h> /* snprintf... */
|
|
51 |
#include <sys/debug.h>
|
|
52 |
#include <sys/thread.h>
|
|
53 |
#include <netinet/in.h>
|
|
54 |
#include <c2/audit.h> /* needs to be included before user.h */
|
|
55 |
#include <c2/audit_kernel.h> /* for M_DONTWAIT */
|
|
56 |
#include <c2/audit_kevents.h>
|
|
57 |
#include <c2/audit_record.h>
|
|
58 |
#include <sys/strsubr.h>
|
|
59 |
#include <sys/tihdr.h>
|
|
60 |
#include <sys/tiuser.h>
|
|
61 |
#include <sys/timod.h>
|
|
62 |
#include <sys/model.h> /* for model_t */
|
|
63 |
#include <sys/disp.h> /* for servicing_interrupt() */
|
|
64 |
#include <sys/devpolicy.h>
|
|
65 |
#include <sys/crypto/ioctladmin.h>
|
898
|
66 |
#include <inet/kssl/kssl.h>
|
0
|
67 |
|
|
68 |
static void add_return_token(caddr_t *, unsigned int scid, int err, int rval);
|
|
69 |
|
|
70 |
static void audit_pathbuild(struct pathname *pnp);
|
|
71 |
|
|
72 |
/*
|
|
73 |
* ROUTINE: AUDIT_NEWPROC
|
|
74 |
* PURPOSE: initialize the child p_audit_data structure
|
|
75 |
* CALLBY: GETPROC
|
|
76 |
* NOTE: All threads for the parent process are locked at this point.
|
|
77 |
* We are essentially running singled threaded for this reason.
|
|
78 |
* GETPROC is called when system creates a new process.
|
|
79 |
* By the time AUDIT_NEWPROC is called, the child proc
|
|
80 |
* structure has already been initialized. What we need
|
|
81 |
* to do is to allocate the child p_audit_data and
|
|
82 |
* initialize it with the content of current parent process.
|
|
83 |
*/
|
|
84 |
|
|
85 |
void
|
|
86 |
audit_newproc(struct proc *cp) /* initialized child proc structure */
|
|
87 |
{
|
|
88 |
p_audit_data_t *pad; /* child process audit data */
|
|
89 |
p_audit_data_t *opad; /* parent process audit data */
|
|
90 |
|
|
91 |
pad = kmem_cache_alloc(au_pad_cache, KM_SLEEP);
|
|
92 |
|
|
93 |
P2A(cp) = pad;
|
|
94 |
|
|
95 |
opad = P2A(curproc);
|
|
96 |
|
|
97 |
/*
|
|
98 |
* copy the audit data. Note that all threads of current
|
|
99 |
* process have been "held". Thus there is no race condition
|
|
100 |
* here with mutiple threads trying to alter the cwrd
|
|
101 |
* structure (such as releasing it).
|
|
102 |
*
|
|
103 |
* The audit context in the cred is "duplicated" for the new
|
|
104 |
* proc by elsewhere crhold'ing the parent's cred which it shares.
|
|
105 |
*
|
|
106 |
* We still want to hold things since auditon() [A_SETUMASK,
|
|
107 |
* A_SETSMASK] could be walking through the processes to
|
|
108 |
* update things.
|
|
109 |
*/
|
|
110 |
mutex_enter(&opad->pad_lock); /* lock opad structure during copy */
|
|
111 |
pad->pad_data = opad->pad_data; /* copy parent's process audit data */
|
|
112 |
au_pathhold(pad->pad_root);
|
|
113 |
au_pathhold(pad->pad_cwd);
|
|
114 |
mutex_exit(&opad->pad_lock); /* current proc will keep cwrd open */
|
|
115 |
|
|
116 |
/*
|
|
117 |
* finish auditing of parent here so that it will be done
|
|
118 |
* before child has a chance to run. We include the child
|
|
119 |
* pid since the return value in the return token is a dummy
|
|
120 |
* one and contains no useful information (it is included to
|
|
121 |
* make the audit record structure consistant).
|
|
122 |
*
|
|
123 |
* tad_flag is set if auditing is on
|
|
124 |
*/
|
|
125 |
if (((t_audit_data_t *)T2A(curthread))->tad_flag)
|
|
126 |
au_uwrite(au_to_arg32(0, "child PID", (uint32_t)cp->p_pid));
|
|
127 |
|
|
128 |
/*
|
|
129 |
* finish up audit record generation here because child process
|
|
130 |
* is set to run before parent process. We distinguish here
|
|
131 |
* between FORK, FORK1, or VFORK by the saved system call ID.
|
|
132 |
*/
|
|
133 |
audit_finish(0, ((t_audit_data_t *)T2A(curthread))->tad_scid, 0, 0);
|
|
134 |
}
|
|
135 |
|
|
136 |
/*
|
|
137 |
* ROUTINE: AUDIT_PFREE
|
|
138 |
* PURPOSE: deallocate the per-process udit data structure
|
|
139 |
* CALLBY: EXIT
|
|
140 |
* FORK_FAIL
|
|
141 |
* NOTE: all lwp except current one have stopped in SEXITLWPS
|
|
142 |
* why we are single threaded?
|
|
143 |
* . all lwp except current one have stopped in SEXITLWPS.
|
|
144 |
*/
|
|
145 |
void
|
|
146 |
audit_pfree(struct proc *p) /* proc structure to be freed */
|
|
147 |
|
|
148 |
{ /* AUDIT_PFREE */
|
|
149 |
|
|
150 |
p_audit_data_t *pad;
|
|
151 |
|
|
152 |
pad = P2A(p);
|
|
153 |
|
|
154 |
/* better be a per process audit data structure */
|
|
155 |
ASSERT(pad != (p_audit_data_t *)0);
|
|
156 |
|
|
157 |
if (pad == pad0) {
|
|
158 |
return;
|
|
159 |
}
|
|
160 |
|
|
161 |
/* deallocate all auditing resources for this process */
|
|
162 |
au_pathrele(pad->pad_root);
|
|
163 |
au_pathrele(pad->pad_cwd);
|
|
164 |
|
|
165 |
/*
|
|
166 |
* Since the pad structure is completely overwritten after alloc,
|
|
167 |
* we don't bother to clear it.
|
|
168 |
*/
|
|
169 |
|
|
170 |
kmem_cache_free(au_pad_cache, pad);
|
|
171 |
}
|
|
172 |
|
|
173 |
/*
|
|
174 |
* ROUTINE: AUDIT_THREAD_CREATE
|
|
175 |
* PURPOSE: allocate per-process thread audit data structure
|
|
176 |
* CALLBY: THREAD_CREATE
|
|
177 |
* NOTE: This is called just after *t was bzero'd.
|
|
178 |
* We are single threaded in this routine.
|
|
179 |
* TODO:
|
|
180 |
* QUESTION:
|
|
181 |
*/
|
|
182 |
|
|
183 |
void
|
|
184 |
audit_thread_create(kthread_id_t t)
|
|
185 |
{
|
|
186 |
t_audit_data_t *tad; /* per-thread audit data */
|
|
187 |
|
|
188 |
tad = kmem_zalloc(sizeof (struct t_audit_data), KM_SLEEP);
|
|
189 |
|
|
190 |
T2A(t) = tad; /* set up thread audit data ptr */
|
|
191 |
tad->tad_thread = t; /* back ptr to thread: DEBUG */
|
|
192 |
}
|
|
193 |
|
|
194 |
/*
|
|
195 |
* ROUTINE: AUDIT_THREAD_FREE
|
|
196 |
* PURPOSE: free the per-thread audit data structure
|
|
197 |
* CALLBY: THREAD_FREE
|
|
198 |
* NOTE: most thread data is clear after return
|
|
199 |
*/
|
|
200 |
void
|
|
201 |
audit_thread_free(kthread_t *t)
|
|
202 |
{
|
|
203 |
t_audit_data_t *tad;
|
|
204 |
au_defer_info_t *attr;
|
|
205 |
|
|
206 |
tad = T2A(t);
|
|
207 |
|
|
208 |
/* thread audit data must still be set */
|
|
209 |
|
|
210 |
if (tad == tad0) {
|
|
211 |
return;
|
|
212 |
}
|
|
213 |
|
|
214 |
if (tad == NULL) {
|
|
215 |
return;
|
|
216 |
}
|
|
217 |
|
|
218 |
t->t_audit_data = 0;
|
|
219 |
|
|
220 |
/* must not have any audit record residual */
|
|
221 |
ASSERT(tad->tad_ad == NULL);
|
|
222 |
|
|
223 |
/* saved path must be empty */
|
|
224 |
ASSERT(tad->tad_aupath == NULL);
|
|
225 |
|
|
226 |
if (tad->tad_atpath)
|
|
227 |
au_pathrele(tad->tad_atpath);
|
|
228 |
|
|
229 |
attr = tad->tad_defer_head;
|
|
230 |
while (attr != NULL) {
|
|
231 |
au_defer_info_t *tmp_attr = attr;
|
|
232 |
|
|
233 |
au_free_rec(attr->audi_ad);
|
|
234 |
|
|
235 |
attr = attr->audi_next;
|
|
236 |
kmem_free(tmp_attr, sizeof (au_defer_info_t));
|
|
237 |
}
|
|
238 |
|
|
239 |
kmem_free(tad, sizeof (*tad));
|
|
240 |
}
|
|
241 |
|
|
242 |
/*
|
|
243 |
* ROUTINE: AUDIT_SAVEPATH
|
|
244 |
* PURPOSE:
|
|
245 |
* CALLBY: LOOKUPPN
|
|
246 |
*
|
|
247 |
* NOTE: We have reached the end of a path in fs/lookup.c.
|
|
248 |
* We get two pieces of information here:
|
|
249 |
* the vnode of the last component (vp) and
|
|
250 |
* the status of the last access (flag).
|
|
251 |
* TODO:
|
|
252 |
* QUESTION:
|
|
253 |
*/
|
|
254 |
|
|
255 |
/*ARGSUSED*/
|
|
256 |
int
|
|
257 |
audit_savepath(
|
|
258 |
struct pathname *pnp, /* pathname to lookup */
|
|
259 |
struct vnode *vp, /* vnode of the last component */
|
|
260 |
int flag, /* status of the last access */
|
|
261 |
cred_t *cr) /* cred of requestor */
|
|
262 |
{
|
|
263 |
|
|
264 |
t_audit_data_t *tad; /* current thread */
|
|
265 |
p_audit_data_t *pad; /* current process */
|
|
266 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
267 |
|
|
268 |
if (kctx == NULL) {
|
|
269 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
270 |
ASSERT(zstate != ZONE_IS_READY);
|
|
271 |
return (0);
|
|
272 |
}
|
|
273 |
|
|
274 |
tad = U2A(u);
|
|
275 |
ASSERT(tad != (t_audit_data_t *)0);
|
|
276 |
pad = P2A(curproc);
|
|
277 |
ASSERT(pad != (p_audit_data_t *)0);
|
|
278 |
|
|
279 |
/*
|
|
280 |
* this event being audited or do we need path information
|
|
281 |
* later? This might be for a chdir/chroot or open (add path
|
|
282 |
* to file pointer. If the path has already been found for an
|
|
283 |
* open/creat then we don't need to process the path.
|
|
284 |
*
|
|
285 |
* S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
286 |
* chroot, chdir, open, creat system call processing. It determines
|
|
287 |
* if audit_savepath() will discard the path or we need it later.
|
|
288 |
* PAD_PATHFND means path already included in this audit record. It
|
|
289 |
* is used in cases where multiple path lookups are done per
|
|
290 |
* system call. The policy flag, AUDIT_PATH, controls if multiple
|
|
291 |
* paths are allowed.
|
|
292 |
* S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
293 |
* exit processing to inhibit any paths that may be added due to
|
|
294 |
* closes.
|
|
295 |
*/
|
|
296 |
if ((tad->tad_flag == 0 && !(tad->tad_ctrl & PAD_SAVPATH)) ||
|
|
297 |
((tad->tad_ctrl & PAD_PATHFND) &&
|
|
298 |
!(kctx->auk_policy & AUDIT_PATH)) ||
|
|
299 |
(tad->tad_ctrl & PAD_NOPATH)) {
|
|
300 |
return (0);
|
|
301 |
}
|
|
302 |
|
|
303 |
audit_pathbuild(pnp);
|
|
304 |
tad->tad_vn = vp;
|
|
305 |
|
|
306 |
/*
|
|
307 |
* are we auditing only if error, or if it is not open or create
|
|
308 |
* otherwise audit_setf will do it
|
|
309 |
*/
|
|
310 |
|
|
311 |
if (tad->tad_flag) {
|
|
312 |
if (flag && (tad->tad_scid == SYS_open ||
|
|
313 |
tad->tad_scid == SYS_open64 ||
|
|
314 |
tad->tad_scid == SYS_creat ||
|
|
315 |
tad->tad_scid == SYS_creat64 ||
|
|
316 |
tad->tad_scid == SYS_fsat)) {
|
|
317 |
tad->tad_ctrl |= PAD_TRUE_CREATE;
|
|
318 |
}
|
|
319 |
|
|
320 |
/* add token to audit record for this name */
|
|
321 |
au_uwrite(au_to_path(tad->tad_aupath));
|
|
322 |
|
|
323 |
/* add the attributes of the object */
|
|
324 |
if (vp) {
|
|
325 |
/*
|
|
326 |
* only capture attributes when there is no error
|
|
327 |
* lookup will not return the vnode of the failing
|
|
328 |
* component.
|
|
329 |
*
|
|
330 |
* if there was a lookup error, then don't add
|
|
331 |
* attribute. if lookup in vn_create(),
|
|
332 |
* then don't add attribute,
|
|
333 |
* it will be added at end of vn_create().
|
|
334 |
*/
|
|
335 |
if (!flag && !(tad->tad_ctrl & PAD_NOATTRB))
|
|
336 |
audit_attributes(vp);
|
|
337 |
}
|
|
338 |
}
|
|
339 |
|
|
340 |
/* free up space if we're not going to save path (open, crate) */
|
|
341 |
if ((tad->tad_ctrl & PAD_SAVPATH) == 0) {
|
|
342 |
if (tad->tad_aupath != NULL) {
|
|
343 |
au_pathrele(tad->tad_aupath);
|
|
344 |
tad->tad_aupath = NULL;
|
|
345 |
tad->tad_vn = NULL;
|
|
346 |
}
|
|
347 |
}
|
|
348 |
if (tad->tad_ctrl & PAD_MLD)
|
|
349 |
tad->tad_ctrl |= PAD_PATHFND;
|
|
350 |
|
|
351 |
return (0);
|
|
352 |
}
|
|
353 |
|
|
354 |
static void
|
|
355 |
audit_pathbuild(struct pathname *pnp)
|
|
356 |
{
|
|
357 |
char *pp; /* pointer to path */
|
|
358 |
int len; /* length of incoming segment */
|
|
359 |
int newsect; /* path requires a new section */
|
|
360 |
struct audit_path *pfxapp; /* prefix for path */
|
|
361 |
struct audit_path *newapp; /* new audit_path */
|
|
362 |
t_audit_data_t *tad; /* current thread */
|
|
363 |
p_audit_data_t *pad; /* current process */
|
|
364 |
|
|
365 |
tad = U2A(u);
|
|
366 |
ASSERT(tad != NULL);
|
|
367 |
pad = P2A(curproc);
|
|
368 |
ASSERT(pad != NULL);
|
|
369 |
|
|
370 |
len = (pnp->pn_path - pnp->pn_buf) + 1; /* +1 for terminator */
|
|
371 |
ASSERT(len > 0);
|
|
372 |
|
|
373 |
/* adjust for path prefix: tad_aupath, ATPATH, CRD, or CWD */
|
|
374 |
mutex_enter(&pad->pad_lock);
|
|
375 |
if (tad->tad_aupath != NULL) {
|
|
376 |
pfxapp = tad->tad_aupath;
|
|
377 |
} else if (tad->tad_scid == SYS_fsat && pnp->pn_buf[0] != '/') {
|
|
378 |
ASSERT(tad->tad_atpath != NULL);
|
|
379 |
pfxapp = tad->tad_atpath;
|
|
380 |
} else if (tad->tad_ctrl & PAD_ABSPATH) {
|
|
381 |
pfxapp = pad->pad_root;
|
|
382 |
} else {
|
|
383 |
pfxapp = pad->pad_cwd;
|
|
384 |
}
|
|
385 |
au_pathhold(pfxapp);
|
|
386 |
mutex_exit(&pad->pad_lock);
|
|
387 |
|
|
388 |
/* get an expanded buffer to hold the anchored path */
|
|
389 |
newsect = tad->tad_ctrl & PAD_ATPATH;
|
|
390 |
newapp = au_pathdup(pfxapp, newsect, len);
|
|
391 |
au_pathrele(pfxapp);
|
|
392 |
|
|
393 |
pp = newapp->audp_sect[newapp->audp_cnt] - len;
|
|
394 |
if (!newsect) {
|
|
395 |
/* overlay previous NUL terminator */
|
|
396 |
*(pp - 1) = '/';
|
|
397 |
}
|
|
398 |
|
|
399 |
/* now add string of processed path */
|
|
400 |
bcopy(pnp->pn_buf, pp, len);
|
|
401 |
pp[len - 1] = '\0';
|
|
402 |
|
|
403 |
/* perform path simplification as necessary */
|
|
404 |
audit_fixpath(newapp, len);
|
|
405 |
|
|
406 |
if (tad->tad_aupath)
|
|
407 |
au_pathrele(tad->tad_aupath);
|
|
408 |
tad->tad_aupath = newapp;
|
|
409 |
|
|
410 |
/* for case where multiple lookups in one syscall (rename) */
|
|
411 |
tad->tad_ctrl &= ~(PAD_ABSPATH | PAD_ATPATH);
|
|
412 |
}
|
|
413 |
|
|
414 |
|
|
415 |
|
|
416 |
/*ARGSUSED*/
|
|
417 |
|
|
418 |
/*
|
|
419 |
* ROUTINE: AUDIT_ADDCOMPONENT
|
|
420 |
* PURPOSE: extend the path by the component accepted
|
|
421 |
* CALLBY: LOOKUPPN
|
|
422 |
* NOTE: This function is called only when there is an error in
|
|
423 |
* parsing a path component
|
|
424 |
* TODO: Add the error component to audit record
|
|
425 |
* QUESTION: what is this for
|
|
426 |
*/
|
|
427 |
|
|
428 |
void
|
|
429 |
audit_addcomponent(struct pathname *pnp)
|
|
430 |
{
|
|
431 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
432 |
t_audit_data_t *tad;
|
|
433 |
|
|
434 |
if (kctx == NULL) {
|
|
435 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
436 |
ASSERT(zstate != ZONE_IS_READY);
|
|
437 |
return;
|
|
438 |
}
|
|
439 |
|
|
440 |
tad = U2A(u);
|
|
441 |
/*
|
|
442 |
* S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
443 |
* chroot, chdir, open, creat system call processing. It determines
|
|
444 |
* if audit_savepath() will discard the path or we need it later.
|
|
445 |
* PAD_PATHFND means path already included in this audit record. It
|
|
446 |
* is used in cases where multiple path lookups are done per
|
|
447 |
* system call. The policy flag, AUDIT_PATH, controls if multiple
|
|
448 |
* paths are allowed.
|
|
449 |
* S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
450 |
* exit processing to inhibit any paths that may be added due to
|
|
451 |
* closes.
|
|
452 |
*/
|
|
453 |
if ((tad->tad_flag == 0 && !(tad->tad_ctrl & PAD_SAVPATH)) ||
|
|
454 |
((tad->tad_ctrl & PAD_PATHFND) &&
|
|
455 |
!(kctx->auk_policy & AUDIT_PATH)) ||
|
|
456 |
(tad->tad_ctrl & PAD_NOPATH)) {
|
|
457 |
return;
|
|
458 |
}
|
|
459 |
|
|
460 |
return;
|
|
461 |
|
|
462 |
} /* AUDIT_ADDCOMPONENT */
|
|
463 |
|
|
464 |
|
|
465 |
|
|
466 |
|
|
467 |
|
|
468 |
|
|
469 |
|
|
470 |
|
|
471 |
/*
|
|
472 |
* ROUTINE: AUDIT_ANCHORPATH
|
|
473 |
* PURPOSE:
|
|
474 |
* CALLBY: LOOKUPPN
|
|
475 |
* NOTE:
|
|
476 |
* anchor path at "/". We have seen a symbolic link or entering for the
|
|
477 |
* first time we will throw away any saved path if path is anchored.
|
|
478 |
*
|
|
479 |
* flag = 0, path is relative.
|
|
480 |
* flag = 1, path is absolute. Free any saved path and set flag to PAD_ABSPATH.
|
|
481 |
*
|
|
482 |
* If the (new) path is absolute, then we have to throw away whatever we have
|
|
483 |
* already accumulated since it is being superceeded by new path which is
|
|
484 |
* anchored at the root.
|
|
485 |
* Note that if the path is relative, this function does nothing
|
|
486 |
* TODO:
|
|
487 |
* QUESTION:
|
|
488 |
*/
|
|
489 |
/*ARGSUSED*/
|
|
490 |
void
|
|
491 |
audit_anchorpath(struct pathname *pnp, int flag)
|
|
492 |
{
|
|
493 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
494 |
t_audit_data_t *tad;
|
|
495 |
|
|
496 |
if (kctx == NULL) {
|
|
497 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
498 |
ASSERT(zstate != ZONE_IS_READY);
|
|
499 |
return;
|
|
500 |
}
|
|
501 |
|
|
502 |
tad = U2A(u);
|
|
503 |
|
|
504 |
/*
|
|
505 |
* this event being audited or do we need path information
|
|
506 |
* later? This might be for a chdir/chroot or open (add path
|
|
507 |
* to file pointer. If the path has already been found for an
|
|
508 |
* open/creat then we don't need to process the path.
|
|
509 |
*
|
|
510 |
* S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
511 |
* chroot, chdir, open, creat system call processing. It determines
|
|
512 |
* if audit_savepath() will discard the path or we need it later.
|
|
513 |
* PAD_PATHFND means path already included in this audit record. It
|
|
514 |
* is used in cases where multiple path lookups are done per
|
|
515 |
* system call. The policy flag, AUDIT_PATH, controls if multiple
|
|
516 |
* paths are allowed.
|
|
517 |
* S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
518 |
* exit processing to inhibit any paths that may be added due to
|
|
519 |
* closes.
|
|
520 |
*/
|
|
521 |
if ((tad->tad_flag == 0 && !(tad->tad_ctrl & PAD_SAVPATH)) ||
|
|
522 |
((tad->tad_ctrl & PAD_PATHFND) &&
|
|
523 |
!(kctx->auk_policy & AUDIT_PATH)) ||
|
|
524 |
(tad->tad_ctrl & PAD_NOPATH)) {
|
|
525 |
return;
|
|
526 |
}
|
|
527 |
|
|
528 |
if (flag) {
|
|
529 |
tad->tad_ctrl |= PAD_ABSPATH;
|
|
530 |
if (tad->tad_aupath != NULL) {
|
|
531 |
au_pathrele(tad->tad_aupath);
|
|
532 |
tad->tad_aupath = NULL;
|
|
533 |
tad->tad_vn = NULL;
|
|
534 |
}
|
|
535 |
}
|
|
536 |
}
|
|
537 |
|
|
538 |
|
|
539 |
/*
|
|
540 |
* symbolic link. Save previous components.
|
|
541 |
*
|
|
542 |
* the path seen so far looks like this
|
|
543 |
*
|
|
544 |
* +-----------------------+----------------+
|
|
545 |
* | path processed so far | remaining path |
|
|
546 |
* +-----------------------+----------------+
|
|
547 |
* \-----------------------/
|
|
548 |
* save this string if
|
|
549 |
* symbolic link relative
|
|
550 |
* (but don't include symlink component)
|
|
551 |
*/
|
|
552 |
|
|
553 |
/*ARGSUSED*/
|
|
554 |
|
|
555 |
|
|
556 |
/*
|
|
557 |
* ROUTINE: AUDIT_SYMLINK
|
|
558 |
* PURPOSE:
|
|
559 |
* CALLBY: LOOKUPPN
|
|
560 |
* NOTE:
|
|
561 |
* TODO:
|
|
562 |
* QUESTION:
|
|
563 |
*/
|
|
564 |
void
|
|
565 |
audit_symlink(struct pathname *pnp, struct pathname *sympath)
|
|
566 |
{
|
|
567 |
char *sp; /* saved initial pp */
|
|
568 |
char *cp; /* start of symlink path */
|
|
569 |
uint_t len_path; /* processed path before symlink */
|
|
570 |
t_audit_data_t *tad;
|
|
571 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
572 |
|
|
573 |
if (kctx == NULL) {
|
|
574 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
575 |
ASSERT(zstate != ZONE_IS_READY);
|
|
576 |
return;
|
|
577 |
}
|
|
578 |
|
|
579 |
tad = U2A(u);
|
|
580 |
|
|
581 |
/*
|
|
582 |
* this event being audited or do we need path information
|
|
583 |
* later? This might be for a chdir/chroot or open (add path
|
|
584 |
* to file pointer. If the path has already been found for an
|
|
585 |
* open/creat then we don't need to process the path.
|
|
586 |
*
|
|
587 |
* S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
588 |
* chroot, chdir, open, creat system call processing. It determines
|
|
589 |
* if audit_savepath() will discard the path or we need it later.
|
|
590 |
* PAD_PATHFND means path already included in this audit record. It
|
|
591 |
* is used in cases where multiple path lookups are done per
|
|
592 |
* system call. The policy flag, AUDIT_PATH, controls if multiple
|
|
593 |
* paths are allowed.
|
|
594 |
* S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with
|
|
595 |
* exit processing to inhibit any paths that may be added due to
|
|
596 |
* closes.
|
|
597 |
*/
|
|
598 |
if ((tad->tad_flag == 0 &&
|
|
599 |
!(tad->tad_ctrl & PAD_SAVPATH)) ||
|
|
600 |
((tad->tad_ctrl & PAD_PATHFND) &&
|
|
601 |
!(kctx->auk_policy & AUDIT_PATH)) ||
|
|
602 |
(tad->tad_ctrl & PAD_NOPATH)) {
|
|
603 |
return;
|
|
604 |
}
|
|
605 |
|
|
606 |
/*
|
|
607 |
* if symbolic link is anchored at / then do nothing.
|
|
608 |
* When we cycle back to begin: in lookuppn() we will
|
|
609 |
* call audit_anchorpath() with a flag indicating if the
|
|
610 |
* path is anchored at / or is relative. We will release
|
|
611 |
* any saved path at that point.
|
|
612 |
*
|
|
613 |
* Note In the event that an error occurs in pn_combine then
|
|
614 |
* we want to remain pointing at the component that caused the
|
|
615 |
* path to overflow the pnp structure.
|
|
616 |
*/
|
|
617 |
if (sympath->pn_buf[0] == '/')
|
|
618 |
return;
|
|
619 |
|
|
620 |
/* backup over last component */
|
|
621 |
sp = cp = pnp->pn_path;
|
|
622 |
while (*--cp != '/' && cp > pnp->pn_buf)
|
|
623 |
;
|
|
624 |
|
|
625 |
len_path = cp - pnp->pn_buf;
|
|
626 |
|
|
627 |
/* is there anything to save? */
|
|
628 |
if (len_path) {
|
|
629 |
pnp->pn_path = cp;
|
|
630 |
audit_pathbuild(pnp);
|
|
631 |
pnp->pn_path = sp;
|
|
632 |
}
|
|
633 |
}
|
|
634 |
|
|
635 |
/*
|
|
636 |
* file_is_public : determine whether events for the file (corresponding to
|
|
637 |
* the specified file attr) should be audited or ignored.
|
|
638 |
*
|
|
639 |
* returns: 1 - if audit policy and file attributes indicate that
|
|
640 |
* file is effectively public. read events for
|
|
641 |
* the file should not be audited.
|
|
642 |
* 0 - otherwise
|
|
643 |
*
|
|
644 |
* The required attributes to be considered a public object are:
|
|
645 |
* - owned by root, AND
|
|
646 |
* - world-readable (permissions for other include read), AND
|
|
647 |
* - NOT world-writeable (permissions for other don't
|
|
648 |
* include write)
|
|
649 |
* (mode doesn't need to be checked for symlinks)
|
|
650 |
*/
|
|
651 |
int
|
|
652 |
file_is_public(struct vattr *attr)
|
|
653 |
{
|
|
654 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
655 |
|
|
656 |
if (kctx == NULL) {
|
|
657 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
658 |
ASSERT(zstate != ZONE_IS_READY);
|
|
659 |
return (0);
|
|
660 |
}
|
|
661 |
|
|
662 |
if (!(kctx->auk_policy & AUDIT_PUBLIC) && (attr->va_uid == 0) &&
|
|
663 |
((attr->va_type == VLNK) ||
|
|
664 |
((attr->va_mode & (VREAD>>6)) != 0) &&
|
|
665 |
((attr->va_mode & (VWRITE>>6)) == 0))) {
|
|
666 |
return (1);
|
|
667 |
}
|
|
668 |
return (0);
|
|
669 |
}
|
|
670 |
|
|
671 |
|
|
672 |
/*
|
|
673 |
* ROUTINE: AUDIT_ATTRIBUTES
|
|
674 |
* PURPOSE: Audit the attributes so we can tell why the error occured
|
|
675 |
* CALLBY: AUDIT_SAVEPATH
|
|
676 |
* AUDIT_VNCREATE_FINISH
|
|
677 |
* AUS_FCHOWN...audit_event.c...audit_path.c
|
|
678 |
* NOTE:
|
|
679 |
* TODO:
|
|
680 |
* QUESTION:
|
|
681 |
*/
|
|
682 |
void
|
|
683 |
audit_attributes(struct vnode *vp)
|
|
684 |
{
|
|
685 |
struct vattr attr;
|
|
686 |
struct t_audit_data *tad;
|
|
687 |
|
|
688 |
tad = U2A(u);
|
|
689 |
|
|
690 |
if (vp) {
|
|
691 |
attr.va_mask = AT_ALL;
|
|
692 |
if (VOP_GETATTR(vp, &attr, 0, CRED()) != 0)
|
|
693 |
return;
|
|
694 |
|
|
695 |
if (file_is_public(&attr) && (tad->tad_ctrl & PAD_PUBLIC_EV)) {
|
|
696 |
/*
|
|
697 |
* This is a public object and a "public" event
|
|
698 |
* (i.e., read only) -- either by definition
|
|
699 |
* (e.g., stat, access...) or by virtue of write access
|
|
700 |
* not being requested (e.g. mmap).
|
|
701 |
* Flag it in the tad to prevent this audit at the end.
|
|
702 |
*/
|
|
703 |
tad->tad_ctrl |= PAD_NOAUDIT;
|
|
704 |
} else {
|
|
705 |
au_uwrite(au_to_attr(&attr));
|
|
706 |
}
|
|
707 |
}
|
|
708 |
}
|
|
709 |
|
|
710 |
|
|
711 |
/*
|
|
712 |
* ROUTINE: AUDIT_FALLOC
|
|
713 |
* PURPOSE: allocating a new file structure
|
|
714 |
* CALLBY: FALLOC
|
|
715 |
* NOTE: file structure already initialized
|
|
716 |
* TODO:
|
|
717 |
* QUESTION:
|
|
718 |
*/
|
|
719 |
|
|
720 |
void
|
|
721 |
audit_falloc(struct file *fp)
|
|
722 |
{ /* AUDIT_FALLOC */
|
|
723 |
|
|
724 |
f_audit_data_t *fad;
|
|
725 |
|
|
726 |
/* allocate per file audit structure if there a'int any */
|
|
727 |
ASSERT(F2A(fp) == NULL);
|
|
728 |
|
|
729 |
fad = kmem_zalloc(sizeof (struct f_audit_data), KM_SLEEP);
|
|
730 |
|
|
731 |
F2A(fp) = fad;
|
|
732 |
|
|
733 |
fad->fad_thread = curthread; /* file audit data back ptr; DEBUG */
|
|
734 |
}
|
|
735 |
|
|
736 |
/*
|
|
737 |
* ROUTINE: AUDIT_UNFALLOC
|
|
738 |
* PURPOSE: deallocate file audit data structure
|
|
739 |
* CALLBY: CLOSEF
|
|
740 |
* UNFALLOC
|
|
741 |
* NOTE:
|
|
742 |
* TODO:
|
|
743 |
* QUESTION:
|
|
744 |
*/
|
|
745 |
|
|
746 |
void
|
|
747 |
audit_unfalloc(struct file *fp)
|
|
748 |
{
|
|
749 |
f_audit_data_t *fad;
|
|
750 |
|
|
751 |
fad = F2A(fp);
|
|
752 |
|
|
753 |
if (!fad) {
|
|
754 |
return;
|
|
755 |
}
|
|
756 |
if (fad->fad_aupath != NULL) {
|
|
757 |
au_pathrele(fad->fad_aupath);
|
|
758 |
}
|
|
759 |
fp->f_audit_data = 0;
|
|
760 |
kmem_free(fad, sizeof (struct f_audit_data));
|
|
761 |
}
|
|
762 |
|
|
763 |
/*
|
|
764 |
* ROUTINE: AUDIT_EXIT
|
|
765 |
* PURPOSE:
|
|
766 |
* CALLBY: EXIT
|
|
767 |
* NOTE:
|
|
768 |
* TODO:
|
|
769 |
* QUESTION: why cmw code as offset by 2 but not here
|
|
770 |
*/
|
|
771 |
/* ARGSUSED */
|
|
772 |
void
|
|
773 |
audit_exit(int code, int what)
|
|
774 |
{
|
|
775 |
struct t_audit_data *tad;
|
|
776 |
tad = U2A(u);
|
|
777 |
|
|
778 |
/*
|
|
779 |
* tad_scid will be set by audit_start even if we are not auditing
|
|
780 |
* the event.
|
|
781 |
*/
|
|
782 |
if (tad->tad_scid == SYS_exit) {
|
|
783 |
/*
|
|
784 |
* if we are auditing the exit system call, then complete
|
|
785 |
* audit record generation (no return from system call).
|
|
786 |
*/
|
|
787 |
if (tad->tad_flag && tad->tad_event == AUE_EXIT)
|
|
788 |
audit_finish(0, SYS_exit, 0, 0);
|
|
789 |
return;
|
|
790 |
}
|
|
791 |
|
|
792 |
/*
|
|
793 |
* Anyone auditing the system call that was aborted?
|
|
794 |
*/
|
|
795 |
if (tad->tad_flag) {
|
|
796 |
au_uwrite(au_to_text("event aborted"));
|
|
797 |
audit_finish(0, tad->tad_scid, 0, 0);
|
|
798 |
}
|
|
799 |
|
|
800 |
/*
|
|
801 |
* Generate an audit record for process exit if preselected.
|
|
802 |
*/
|
|
803 |
(void) audit_start(0, SYS_exit, 0, 0);
|
|
804 |
audit_finish(0, SYS_exit, 0, 0);
|
|
805 |
}
|
|
806 |
|
|
807 |
/*
|
|
808 |
* ROUTINE: AUDIT_CORE_START
|
|
809 |
* PURPOSE:
|
|
810 |
* CALLBY: PSIG
|
|
811 |
* NOTE:
|
|
812 |
* TODO:
|
|
813 |
*/
|
|
814 |
void
|
|
815 |
audit_core_start(int sig)
|
|
816 |
{
|
|
817 |
au_event_t event;
|
|
818 |
au_state_t estate;
|
|
819 |
t_audit_data_t *tad;
|
|
820 |
au_kcontext_t *kctx;
|
|
821 |
|
|
822 |
tad = U2A(u);
|
|
823 |
|
|
824 |
ASSERT(tad != (t_audit_data_t *)0);
|
|
825 |
|
|
826 |
ASSERT(tad->tad_scid == 0);
|
|
827 |
ASSERT(tad->tad_event == 0);
|
|
828 |
ASSERT(tad->tad_evmod == 0);
|
|
829 |
ASSERT(tad->tad_ctrl == 0);
|
|
830 |
ASSERT(tad->tad_flag == 0);
|
|
831 |
ASSERT(tad->tad_aupath == NULL);
|
|
832 |
|
|
833 |
kctx = SET_KCTX_PZ;
|
|
834 |
|
|
835 |
if (kctx == NULL) {
|
|
836 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
837 |
ASSERT(zstate != ZONE_IS_READY);
|
|
838 |
return;
|
|
839 |
}
|
|
840 |
|
|
841 |
/* get basic event for system call */
|
|
842 |
event = AUE_CORE;
|
|
843 |
estate = kctx->auk_ets[event];
|
|
844 |
|
|
845 |
if ((tad->tad_flag = auditme(kctx, tad, estate)) == 0)
|
|
846 |
return;
|
|
847 |
|
|
848 |
/* reset the flags for non-user attributable events */
|
|
849 |
tad->tad_ctrl = PAD_CORE;
|
|
850 |
tad->tad_scid = 0;
|
|
851 |
|
|
852 |
/* if auditing not enabled, then don't generate an audit record */
|
|
853 |
|
|
854 |
if (!((kctx->auk_auditstate == AUC_AUDITING ||
|
|
855 |
kctx->auk_auditstate == AUC_INIT_AUDIT) ||
|
|
856 |
kctx->auk_auditstate == AUC_NOSPACE)) {
|
|
857 |
tad->tad_flag = 0;
|
|
858 |
tad->tad_ctrl = 0;
|
|
859 |
return;
|
|
860 |
}
|
|
861 |
|
|
862 |
tad->tad_event = event;
|
|
863 |
tad->tad_evmod = 0;
|
|
864 |
|
|
865 |
ASSERT(tad->tad_ad == NULL);
|
|
866 |
|
|
867 |
au_write(&(u_ad), au_to_arg32(1, "signal", (uint32_t)sig));
|
|
868 |
}
|
|
869 |
|
|
870 |
/*
|
|
871 |
* ROUTINE: AUDIT_CORE_FINISH
|
|
872 |
* PURPOSE:
|
|
873 |
* CALLBY: PSIG
|
|
874 |
* NOTE:
|
|
875 |
* TODO:
|
|
876 |
* QUESTION:
|
|
877 |
*/
|
|
878 |
|
|
879 |
/*ARGSUSED*/
|
|
880 |
void
|
|
881 |
audit_core_finish(int code)
|
|
882 |
{
|
|
883 |
int flag;
|
|
884 |
t_audit_data_t *tad;
|
|
885 |
au_kcontext_t *kctx;
|
|
886 |
|
|
887 |
tad = U2A(u);
|
|
888 |
|
|
889 |
ASSERT(tad != (t_audit_data_t *)0);
|
|
890 |
|
|
891 |
if ((flag = tad->tad_flag) == 0) {
|
|
892 |
tad->tad_event = 0;
|
|
893 |
tad->tad_evmod = 0;
|
|
894 |
tad->tad_ctrl = 0;
|
|
895 |
ASSERT(tad->tad_aupath == NULL);
|
|
896 |
return;
|
|
897 |
}
|
|
898 |
tad->tad_flag = 0;
|
|
899 |
|
|
900 |
kctx = SET_KCTX_PZ;
|
|
901 |
if (kctx == NULL) {
|
|
902 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
903 |
ASSERT(zstate != ZONE_IS_READY);
|
|
904 |
return;
|
|
905 |
}
|
|
906 |
|
|
907 |
/* kludge for error 0, should use `code==CLD_DUMPED' instead */
|
|
908 |
if (flag = audit_success(kctx, tad, 0)) {
|
|
909 |
cred_t *cr = CRED();
|
|
910 |
const auditinfo_addr_t *ainfo = crgetauinfo(cr);
|
|
911 |
|
|
912 |
ASSERT(ainfo != NULL);
|
|
913 |
|
|
914 |
/*
|
|
915 |
* Add a subject token (no locks since our private copy of
|
|
916 |
* credential
|
|
917 |
*/
|
|
918 |
AUDIT_SETSUBJ(&(u_ad), cr, ainfo);
|
|
919 |
|
|
920 |
/* Add an optional group token */
|
|
921 |
AUDIT_SETGROUP(&(u_ad), cr, kctx);
|
|
922 |
|
|
923 |
/* Add a return token (should use f argument) */
|
|
924 |
add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0);
|
|
925 |
|
|
926 |
AS_INC(as_generated, 1, kctx);
|
|
927 |
AS_INC(as_kernel, 1, kctx);
|
|
928 |
}
|
|
929 |
|
|
930 |
/* Close up everything */
|
|
931 |
au_close(kctx, &(u_ad), flag, tad->tad_event, tad->tad_evmod);
|
|
932 |
|
|
933 |
/* free up any space remaining with the path's */
|
|
934 |
if (tad->tad_aupath != NULL) {
|
|
935 |
au_pathrele(tad->tad_aupath);
|
|
936 |
tad->tad_aupath = NULL;
|
|
937 |
tad->tad_vn = NULL;
|
|
938 |
}
|
|
939 |
tad->tad_event = 0;
|
|
940 |
tad->tad_evmod = 0;
|
|
941 |
tad->tad_ctrl = 0;
|
|
942 |
}
|
|
943 |
|
|
944 |
/*ARGSUSED*/
|
|
945 |
void
|
|
946 |
audit_stropen(struct vnode *vp, dev_t *devp, int flag, cred_t *crp)
|
|
947 |
{
|
|
948 |
}
|
|
949 |
|
|
950 |
/*ARGSUSED*/
|
|
951 |
void
|
|
952 |
audit_strclose(struct vnode *vp, int flag, cred_t *crp)
|
|
953 |
{
|
|
954 |
}
|
|
955 |
|
|
956 |
/*ARGSUSED*/
|
|
957 |
void
|
|
958 |
audit_strioctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
|
|
959 |
int copyflag, cred_t *crp, int *rvalp)
|
|
960 |
{
|
|
961 |
}
|
|
962 |
|
|
963 |
|
|
964 |
/*ARGSUSED*/
|
|
965 |
void
|
|
966 |
audit_strgetmsg(struct vnode *vp, struct strbuf *mctl, struct strbuf *mdata,
|
|
967 |
unsigned char *pri, int *flag, int fmode)
|
|
968 |
{
|
|
969 |
struct stdata *stp;
|
|
970 |
t_audit_data_t *tad = U2A(u);
|
|
971 |
|
|
972 |
ASSERT(tad != (t_audit_data_t *)0);
|
|
973 |
|
|
974 |
stp = vp->v_stream;
|
|
975 |
|
|
976 |
/* lock stdata from audit_sock */
|
|
977 |
mutex_enter(&stp->sd_lock);
|
|
978 |
|
|
979 |
/* proceed ONLY if user is being audited */
|
|
980 |
if (!tad->tad_flag) {
|
|
981 |
/*
|
|
982 |
* this is so we will not add audit data onto
|
|
983 |
* a thread that is not being audited.
|
|
984 |
*/
|
|
985 |
stp->sd_t_audit_data = NULL;
|
|
986 |
mutex_exit(&stp->sd_lock);
|
|
987 |
return;
|
|
988 |
}
|
|
989 |
|
|
990 |
stp->sd_t_audit_data = (caddr_t)curthread;
|
|
991 |
mutex_exit(&stp->sd_lock);
|
|
992 |
}
|
|
993 |
|
|
994 |
/*ARGSUSED*/
|
|
995 |
void
|
|
996 |
audit_strputmsg(struct vnode *vp, struct strbuf *mctl, struct strbuf *mdata,
|
|
997 |
unsigned char pri, int flag, int fmode)
|
|
998 |
{
|
|
999 |
struct stdata *stp;
|
|
1000 |
t_audit_data_t *tad = U2A(u);
|
|
1001 |
|
|
1002 |
ASSERT(tad != (t_audit_data_t *)0);
|
|
1003 |
|
|
1004 |
stp = vp->v_stream;
|
|
1005 |
|
|
1006 |
/* lock stdata from audit_sock */
|
|
1007 |
mutex_enter(&stp->sd_lock);
|
|
1008 |
|
|
1009 |
/* proceed ONLY if user is being audited */
|
|
1010 |
if (!tad->tad_flag) {
|
|
1011 |
/*
|
|
1012 |
* this is so we will not add audit data onto
|
|
1013 |
* a thread that is not being audited.
|
|
1014 |
*/
|
|
1015 |
stp->sd_t_audit_data = NULL;
|
|
1016 |
mutex_exit(&stp->sd_lock);
|
|
1017 |
return;
|
|
1018 |
}
|
|
1019 |
|
|
1020 |
stp->sd_t_audit_data = (caddr_t)curthread;
|
|
1021 |
mutex_exit(&stp->sd_lock);
|
|
1022 |
}
|
|
1023 |
|
|
1024 |
/*
|
|
1025 |
* ROUTINE: AUDIT_CLOSEF
|
|
1026 |
* PURPOSE:
|
|
1027 |
* CALLBY: CLOSEF
|
|
1028 |
* NOTE:
|
|
1029 |
* release per file audit resources when file structure is being released.
|
|
1030 |
*
|
|
1031 |
* IMPORTANT NOTE: Since we generate an audit record here, we may sleep
|
|
1032 |
* on the audit queue if it becomes full. This means
|
|
1033 |
* audit_closef can not be called when f_count == 0. Since
|
|
1034 |
* f_count == 0 indicates the file structure is free, another
|
|
1035 |
* process could attempt to use the file while we were still
|
|
1036 |
* asleep waiting on the audit queue. This would cause the
|
|
1037 |
* per file audit data to be corrupted when we finally do
|
|
1038 |
* wakeup.
|
|
1039 |
* TODO:
|
|
1040 |
* QUESTION:
|
|
1041 |
*/
|
|
1042 |
|
|
1043 |
void
|
|
1044 |
audit_closef(struct file *fp)
|
|
1045 |
{ /* AUDIT_CLOSEF */
|
|
1046 |
f_audit_data_t *fad;
|
|
1047 |
t_audit_data_t *tad;
|
|
1048 |
int success;
|
|
1049 |
au_state_t estate;
|
|
1050 |
struct vnode *vp;
|
|
1051 |
token_t *ad = NULL;
|
|
1052 |
struct vattr attr;
|
|
1053 |
short evmod = 0;
|
|
1054 |
const auditinfo_addr_t *ainfo;
|
|
1055 |
int getattr_ret;
|
|
1056 |
cred_t *cr;
|
|
1057 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
1058 |
|
|
1059 |
if (kctx == NULL) {
|
|
1060 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
1061 |
ASSERT(zstate != ZONE_IS_READY);
|
|
1062 |
return;
|
|
1063 |
}
|
|
1064 |
|
|
1065 |
fad = F2A(fp);
|
|
1066 |
estate = kctx->auk_ets[AUE_CLOSE];
|
|
1067 |
tad = U2A(u);
|
|
1068 |
cr = CRED();
|
|
1069 |
|
|
1070 |
/* audit record already generated by system call envelope */
|
|
1071 |
if (tad->tad_event == AUE_CLOSE) {
|
|
1072 |
/* so close audit event will have bits set */
|
|
1073 |
tad->tad_evmod |= (short)fad->fad_flags;
|
|
1074 |
return;
|
|
1075 |
}
|
|
1076 |
|
|
1077 |
/* if auditing not enabled, then don't generate an audit record */
|
|
1078 |
if (!((kctx->auk_auditstate == AUC_AUDITING ||
|
|
1079 |
kctx->auk_auditstate == AUC_INIT_AUDIT) ||
|
|
1080 |
kctx->auk_auditstate == AUC_NOSPACE))
|
|
1081 |
return;
|
|
1082 |
|
|
1083 |
ainfo = crgetauinfo(cr);
|
|
1084 |
if (ainfo == NULL)
|
|
1085 |
return;
|
|
1086 |
|
|
1087 |
success = ainfo->ai_mask.as_success & estate;
|
|
1088 |
|
|
1089 |
/* not selected for this event */
|
|
1090 |
if (success == 0)
|
|
1091 |
return;
|
|
1092 |
|
|
1093 |
/*
|
|
1094 |
* can't use audit_attributes here since we use a private audit area
|
|
1095 |
* to build the audit record instead of the one off the thread.
|
|
1096 |
*/
|
|
1097 |
if ((vp = fp->f_vnode) != NULL) {
|
|
1098 |
attr.va_mask = AT_ALL;
|
|
1099 |
getattr_ret = VOP_GETATTR(vp, &attr, 0, CRED());
|
|
1100 |
}
|
|
1101 |
|
|
1102 |
/*
|
|
1103 |
* When write was not used and the file can be considered public,
|
|
1104 |
* then skip the audit.
|
|
1105 |
*/
|
|
1106 |
if ((getattr_ret == 0) && ((fp->f_flag & FWRITE) == 0)) {
|
|
1107 |
if (file_is_public(&attr)) {
|
|
1108 |
return;
|
|
1109 |
}
|
|
1110 |
}
|
|
1111 |
|
|
1112 |
evmod = (short)fad->fad_flags;
|
|
1113 |
if (fad->fad_aupath != NULL) {
|
|
1114 |
au_write((caddr_t *)&(ad), au_to_path(fad->fad_aupath));
|
|
1115 |
} else {
|
|
1116 |
#ifdef _LP64
|
|
1117 |
au_write((caddr_t *)&(ad), au_to_arg64(
|
|
1118 |
1, "no path: fp", (uint64_t)fp));
|
|
1119 |
#else
|
|
1120 |
au_write((caddr_t *)&(ad), au_to_arg32(
|
|
1121 |
1, "no path: fp", (uint32_t)fp));
|
|
1122 |
#endif
|
|
1123 |
}
|
|
1124 |
|
|
1125 |
if (getattr_ret == 0) {
|
|
1126 |
au_write((caddr_t *)&(ad), au_to_attr(&attr));
|
|
1127 |
}
|
|
1128 |
|
|
1129 |
/* Add a subject token */
|
|
1130 |
AUDIT_SETSUBJ((caddr_t *)&(ad), cr, ainfo);
|
|
1131 |
|
|
1132 |
/* add an optional group token */
|
|
1133 |
AUDIT_SETGROUP((caddr_t *)&(ad), cr, kctx);
|
|
1134 |
|
|
1135 |
/* add a return token */
|
|
1136 |
add_return_token((caddr_t *)&(ad), tad->tad_scid, 0, 0);
|
|
1137 |
|
|
1138 |
AS_INC(as_generated, 1, kctx);
|
|
1139 |
AS_INC(as_kernel, 1, kctx);
|
|
1140 |
|
|
1141 |
/*
|
|
1142 |
* Close up everything
|
|
1143 |
* Note: path space recovery handled by normal system
|
|
1144 |
* call envelope if not at last close.
|
|
1145 |
* Note there is no failure at this point since
|
|
1146 |
* this represents closes due to exit of process,
|
|
1147 |
* thus we always indicate successful closes.
|
|
1148 |
*/
|
|
1149 |
au_close(kctx, (caddr_t *)&(ad), AU_OK | AU_DEFER,
|
|
1150 |
AUE_CLOSE, evmod);
|
|
1151 |
}
|
|
1152 |
|
|
1153 |
/*
|
|
1154 |
* ROUTINE: AUDIT_SET
|
|
1155 |
* PURPOSE: Audit the file path and file attributes.
|
|
1156 |
* CALLBY: SETF
|
|
1157 |
* NOTE: SETF associate a file pointer with user area's open files.
|
|
1158 |
* TODO:
|
|
1159 |
* call audit_finish directly ???
|
|
1160 |
* QUESTION:
|
|
1161 |
*/
|
|
1162 |
|
|
1163 |
/*ARGSUSED*/
|
|
1164 |
void
|
|
1165 |
audit_setf(file_t *fp, int fd)
|
|
1166 |
{
|
|
1167 |
f_audit_data_t *fad;
|
|
1168 |
t_audit_data_t *tad;
|
|
1169 |
|
|
1170 |
if (fp == NULL)
|
|
1171 |
return;
|
|
1172 |
|
|
1173 |
tad = T2A(curthread);
|
|
1174 |
fad = F2A(fp);
|
|
1175 |
|
|
1176 |
if (!(tad->tad_scid == SYS_open || tad->tad_scid == SYS_creat ||
|
|
1177 |
tad->tad_scid == SYS_open64 || tad->tad_scid == SYS_creat64 ||
|
|
1178 |
tad->tad_scid == SYS_fsat))
|
|
1179 |
return;
|
|
1180 |
|
|
1181 |
/* no path */
|
|
1182 |
if (tad->tad_aupath == 0)
|
|
1183 |
return;
|
|
1184 |
|
|
1185 |
/*
|
|
1186 |
* assign path information associated with file audit data
|
|
1187 |
* use tad hold
|
|
1188 |
*/
|
|
1189 |
fad->fad_aupath = tad->tad_aupath;
|
|
1190 |
tad->tad_aupath = NULL;
|
|
1191 |
tad->tad_vn = NULL;
|
|
1192 |
|
|
1193 |
if (!(tad->tad_ctrl & PAD_TRUE_CREATE)) {
|
|
1194 |
/* adjust event type */
|
|
1195 |
switch (tad->tad_event) {
|
|
1196 |
case AUE_OPEN_RC:
|
|
1197 |
tad->tad_event = AUE_OPEN_R;
|
|
1198 |
tad->tad_ctrl |= PAD_PUBLIC_EV;
|
|
1199 |
break;
|
|
1200 |
case AUE_OPEN_RTC:
|
|
1201 |
tad->tad_event = AUE_OPEN_RT;
|
|
1202 |
break;
|
|
1203 |
case AUE_OPEN_WC:
|
|
1204 |
tad->tad_event = AUE_OPEN_W;
|
|
1205 |
break;
|
|
1206 |
case AUE_OPEN_WTC:
|
|
1207 |
tad->tad_event = AUE_OPEN_WT;
|
|
1208 |
break;
|
|
1209 |
case AUE_OPEN_RWC:
|
|
1210 |
tad->tad_event = AUE_OPEN_RW;
|
|
1211 |
break;
|
|
1212 |
case AUE_OPEN_RWTC:
|
|
1213 |
tad->tad_event = AUE_OPEN_RWT;
|
|
1214 |
break;
|
|
1215 |
default:
|
|
1216 |
break;
|
|
1217 |
}
|
|
1218 |
}
|
|
1219 |
}
|
|
1220 |
|
|
1221 |
|
|
1222 |
/*
|
|
1223 |
* ROUTINE: AUDIT_COPEN
|
|
1224 |
* PURPOSE:
|
|
1225 |
* CALLBY: COPEN
|
|
1226 |
* NOTE:
|
|
1227 |
* TODO:
|
|
1228 |
* QUESTION:
|
|
1229 |
*/
|
|
1230 |
/*ARGSUSED*/
|
|
1231 |
void
|
|
1232 |
audit_copen(int fd, file_t *fp, vnode_t *vp)
|
|
1233 |
{
|
|
1234 |
}
|
|
1235 |
|
|
1236 |
void
|
|
1237 |
audit_ipc(int type, int id, void *vp)
|
|
1238 |
{
|
|
1239 |
/* if not auditing this event, then do nothing */
|
|
1240 |
if (ad_flag == 0)
|
|
1241 |
return;
|
|
1242 |
|
|
1243 |
switch (type) {
|
|
1244 |
case AT_IPC_MSG:
|
|
1245 |
au_uwrite(au_to_ipc(AT_IPC_MSG, id));
|
|
1246 |
au_uwrite(au_to_ipc_perm(&(((kmsqid_t *)vp)->msg_perm)));
|
|
1247 |
break;
|
|
1248 |
case AT_IPC_SEM:
|
|
1249 |
au_uwrite(au_to_ipc(AT_IPC_SEM, id));
|
|
1250 |
au_uwrite(au_to_ipc_perm(&(((ksemid_t *)vp)->sem_perm)));
|
|
1251 |
break;
|
|
1252 |
case AT_IPC_SHM:
|
|
1253 |
au_uwrite(au_to_ipc(AT_IPC_SHM, id));
|
|
1254 |
au_uwrite(au_to_ipc_perm(&(((kshmid_t *)vp)->shm_perm)));
|
|
1255 |
break;
|
|
1256 |
}
|
|
1257 |
}
|
|
1258 |
|
|
1259 |
void
|
|
1260 |
audit_ipcget(int type, void *vp)
|
|
1261 |
{
|
|
1262 |
/* if not auditing this event, then do nothing */
|
|
1263 |
if (ad_flag == 0)
|
|
1264 |
return;
|
|
1265 |
|
|
1266 |
switch (type) {
|
|
1267 |
case NULL:
|
|
1268 |
au_uwrite(au_to_ipc_perm((struct kipc_perm *)vp));
|
|
1269 |
break;
|
|
1270 |
case AT_IPC_MSG:
|
|
1271 |
au_uwrite(au_to_ipc_perm(&(((kmsqid_t *)vp)->msg_perm)));
|
|
1272 |
break;
|
|
1273 |
case AT_IPC_SEM:
|
|
1274 |
au_uwrite(au_to_ipc_perm(&(((ksemid_t *)vp)->sem_perm)));
|
|
1275 |
break;
|
|
1276 |
case AT_IPC_SHM:
|
|
1277 |
au_uwrite(au_to_ipc_perm(&(((kshmid_t *)vp)->shm_perm)));
|
|
1278 |
break;
|
|
1279 |
}
|
|
1280 |
}
|
|
1281 |
|
|
1282 |
/*
|
|
1283 |
* ROUTINE: AUDIT_REBOOT
|
|
1284 |
* PURPOSE:
|
|
1285 |
* CALLBY:
|
|
1286 |
* NOTE:
|
|
1287 |
* At this point we know that the system call reboot will not return. We thus
|
|
1288 |
* have to complete the audit record generation and put it onto the queue.
|
|
1289 |
* This might be fairly useless if the auditing daemon is already dead....
|
|
1290 |
* TODO:
|
|
1291 |
* QUESTION: who calls audit_reboot
|
|
1292 |
*/
|
|
1293 |
|
|
1294 |
void
|
|
1295 |
audit_reboot(void)
|
|
1296 |
{
|
|
1297 |
int flag;
|
|
1298 |
t_audit_data_t *tad;
|
|
1299 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
1300 |
|
|
1301 |
if (kctx == NULL) {
|
|
1302 |
zone_status_t zstate = zone_status_get(curproc->p_zone);
|
|
1303 |
ASSERT(zstate != ZONE_IS_READY);
|
|
1304 |
return;
|
|
1305 |
}
|
|
1306 |
|
|
1307 |
tad = U2A(u);
|
|
1308 |
|
|
1309 |
/* if not auditing this event, then do nothing */
|
|
1310 |
if (tad->tad_flag == 0)
|
|
1311 |
return;
|
|
1312 |
|
|
1313 |
/* do preselection on success/failure */
|
|
1314 |
if (flag = audit_success(kctx, tad, 0)) {
|
|
1315 |
/* add a process token */
|
|
1316 |
|
|
1317 |
cred_t *cr = CRED();
|
|
1318 |
const auditinfo_addr_t *ainfo = crgetauinfo(cr);
|
|
1319 |
|
|
1320 |
if (ainfo == NULL)
|
|
1321 |
return;
|
|
1322 |
|
|
1323 |
AUDIT_SETSUBJ(&(u_ad), cr, ainfo);
|
|
1324 |
|
|
1325 |
/* add an optional group token */
|
|
1326 |
AUDIT_SETGROUP(&(u_ad), cr, kctx);
|
|
1327 |
|
|
1328 |
/* add a return token */
|
|
1329 |
add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0);
|
|
1330 |
|
|
1331 |
AS_INC(as_generated, 1, kctx);
|
|
1332 |
AS_INC(as_kernel, 1, kctx);
|
|
1333 |
}
|
|
1334 |
|
|
1335 |
/*
|
|
1336 |
* Flow control useless here since we're going
|
|
1337 |
* to drop everything in the queue anyway. Why
|
|
1338 |
* block and wait. There aint anyone left alive to
|
|
1339 |
* read the records remaining anyway.
|
|
1340 |
*/
|
|
1341 |
|
|
1342 |
/* Close up everything */
|
|
1343 |
au_close(kctx, &(u_ad), flag | AU_DONTBLOCK,
|
|
1344 |
tad->tad_event, tad->tad_evmod);
|
|
1345 |
}
|
|
1346 |
|
|
1347 |
void
|
|
1348 |
audit_setfsat_path(int argnum)
|
|
1349 |
{
|
|
1350 |
klwp_id_t clwp = ttolwp(curthread);
|
|
1351 |
struct file *fp;
|
|
1352 |
uint32_t fd;
|
|
1353 |
t_audit_data_t *tad;
|
|
1354 |
struct f_audit_data *fad;
|
|
1355 |
p_audit_data_t *pad; /* current process */
|
|
1356 |
|
|
1357 |
struct b {
|
|
1358 |
long arg1;
|
|
1359 |
long arg2;
|
|
1360 |
long arg3;
|
|
1361 |
long arg4;
|
|
1362 |
long arg5;
|
|
1363 |
} *uap1;
|
|
1364 |
|
|
1365 |
if (clwp == NULL)
|
|
1366 |
return;
|
|
1367 |
uap1 = (struct b *)&clwp->lwp_ap[1];
|
|
1368 |
|
|
1369 |
tad = U2A(u);
|
|
1370 |
|
|
1371 |
ASSERT(tad != NULL);
|
|
1372 |
|
|
1373 |
if (tad->tad_scid != SYS_fsat)
|
|
1374 |
return;
|
|
1375 |
|
|
1376 |
switch (argnum) {
|
|
1377 |
case 1:
|
|
1378 |
fd = (uint32_t)uap1->arg1;
|
|
1379 |
break;
|
|
1380 |
case 2:
|
|
1381 |
fd = (uint32_t)uap1->arg2;
|
|
1382 |
break;
|
|
1383 |
case 3:
|
|
1384 |
fd = (uint32_t)uap1->arg3;
|
|
1385 |
break;
|
|
1386 |
case 4:
|
|
1387 |
fd = (uint32_t)uap1->arg4;
|
|
1388 |
break;
|
|
1389 |
case 5:
|
|
1390 |
fd = (uint32_t)uap1->arg5;
|
|
1391 |
break;
|
|
1392 |
default:
|
|
1393 |
return;
|
|
1394 |
}
|
|
1395 |
|
|
1396 |
if (tad->tad_atpath != NULL) {
|
|
1397 |
au_pathrele(tad->tad_atpath);
|
|
1398 |
tad->tad_atpath = NULL;
|
|
1399 |
}
|
|
1400 |
if (fd != AT_FDCWD) {
|
|
1401 |
if ((fp = getf(fd)) == NULL)
|
|
1402 |
return;
|
|
1403 |
|
|
1404 |
fad = F2A(fp);
|
|
1405 |
ASSERT(fad);
|
|
1406 |
au_pathhold(fad->fad_aupath);
|
|
1407 |
tad->tad_atpath = fad->fad_aupath;
|
|
1408 |
releasef(fd);
|
|
1409 |
} else {
|
|
1410 |
pad = P2A(curproc);
|
|
1411 |
mutex_enter(&pad->pad_lock);
|
|
1412 |
au_pathhold(pad->pad_cwd);
|
|
1413 |
tad->tad_atpath = pad->pad_cwd;
|
|
1414 |
mutex_exit(&pad->pad_lock);
|
|
1415 |
}
|
|
1416 |
}
|
|
1417 |
|
|
1418 |
void
|
|
1419 |
audit_symlink_create(vnode_t *dvp, char *sname, char *target, int error)
|
|
1420 |
{
|
|
1421 |
t_audit_data_t *tad;
|
|
1422 |
vnode_t *vp;
|
|
1423 |
|
|
1424 |
tad = U2A(u);
|
|
1425 |
|
|
1426 |
/* if not auditing this event, then do nothing */
|
|
1427 |
if (tad->tad_flag == 0)
|
|
1428 |
return;
|
|
1429 |
|
|
1430 |
au_uwrite(au_to_text(target));
|
|
1431 |
|
|
1432 |
if (error)
|
|
1433 |
return;
|
|
1434 |
|
|
1435 |
error = VOP_LOOKUP(dvp, sname, &vp, NULL, NO_FOLLOW, NULL, CRED());
|
|
1436 |
if (error == 0) {
|
|
1437 |
audit_attributes(vp);
|
|
1438 |
VN_RELE(vp);
|
|
1439 |
}
|
|
1440 |
}
|
|
1441 |
|
|
1442 |
/*
|
|
1443 |
* ROUTINE: AUDIT_VNCREATE_START
|
|
1444 |
* PURPOSE: set flag so path name lookup in create will not add attribute
|
|
1445 |
* CALLBY: VN_CREATE
|
|
1446 |
* NOTE:
|
|
1447 |
* TODO:
|
|
1448 |
* QUESTION:
|
|
1449 |
*/
|
|
1450 |
|
|
1451 |
void
|
|
1452 |
audit_vncreate_start()
|
|
1453 |
{
|
|
1454 |
t_audit_data_t *tad;
|
|
1455 |
|
|
1456 |
tad = U2A(u);
|
|
1457 |
tad->tad_ctrl |= PAD_NOATTRB;
|
|
1458 |
}
|
|
1459 |
|
|
1460 |
/*
|
|
1461 |
* ROUTINE: AUDIT_VNCREATE_FINISH
|
|
1462 |
* PURPOSE:
|
|
1463 |
* CALLBY: VN_CREATE
|
|
1464 |
* NOTE:
|
|
1465 |
* TODO:
|
|
1466 |
* QUESTION:
|
|
1467 |
*/
|
|
1468 |
void
|
|
1469 |
audit_vncreate_finish(struct vnode *vp, int error)
|
|
1470 |
{
|
|
1471 |
t_audit_data_t *tad;
|
|
1472 |
|
|
1473 |
if (error)
|
|
1474 |
return;
|
|
1475 |
|
|
1476 |
tad = U2A(u);
|
|
1477 |
|
|
1478 |
/* if not auditing this event, then do nothing */
|
|
1479 |
if (tad->tad_flag == 0)
|
|
1480 |
return;
|
|
1481 |
|
|
1482 |
if (tad->tad_ctrl & PAD_TRUE_CREATE) {
|
|
1483 |
audit_attributes(vp);
|
|
1484 |
}
|
|
1485 |
|
|
1486 |
if (tad->tad_ctrl & PAD_CORE) {
|
|
1487 |
audit_attributes(vp);
|
|
1488 |
tad->tad_ctrl &= ~PAD_CORE;
|
|
1489 |
}
|
|
1490 |
|
|
1491 |
if (!error && ((tad->tad_event == AUE_MKNOD) ||
|
|
1492 |
(tad->tad_event == AUE_MKDIR))) {
|
|
1493 |
audit_attributes(vp);
|
|
1494 |
}
|
|
1495 |
|
|
1496 |
/* for case where multiple lookups in one syscall (rename) */
|
|
1497 |
tad->tad_ctrl &= ~PAD_NOATTRB;
|
|
1498 |
}
|
|
1499 |
|
|
1500 |
|
|
1501 |
|
|
1502 |
|
|
1503 |
|
|
1504 |
|
|
1505 |
|
|
1506 |
|
|
1507 |
/*
|
|
1508 |
* ROUTINE: AUDIT_EXEC
|
|
1509 |
* PURPOSE: Records the function arguments and environment variables
|
|
1510 |
* CALLBY: EXEC_ARGS
|
|
1511 |
* NOTE:
|
|
1512 |
* TODO:
|
|
1513 |
* QUESTION:
|
|
1514 |
*/
|
|
1515 |
|
|
1516 |
/*ARGSUSED*/
|
|
1517 |
void
|
|
1518 |
audit_exec(
|
|
1519 |
const char *argstr, /* argument strings */
|
|
1520 |
const char *envstr, /* environment strings */
|
|
1521 |
ssize_t argc, /* total # arguments */
|
|
1522 |
ssize_t envc) /* total # environment variables */
|
|
1523 |
{
|
|
1524 |
t_audit_data_t *tad;
|
|
1525 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
1526 |
|
|
1527 |
ASSERT(kctx != NULL);
|
|
1528 |
|
|
1529 |
tad = U2A(u);
|
|
1530 |
|
|
1531 |
/* if not auditing this event, then do nothing */
|
|
1532 |
if (!tad->tad_flag)
|
|
1533 |
return;
|
|
1534 |
|
|
1535 |
/* return if not interested in argv or environment variables */
|
|
1536 |
if (!(kctx->auk_policy & (AUDIT_ARGV|AUDIT_ARGE)))
|
|
1537 |
return;
|
|
1538 |
|
|
1539 |
if (kctx->auk_policy & AUDIT_ARGV) {
|
|
1540 |
au_uwrite(au_to_exec_args(argstr, argc));
|
|
1541 |
}
|
|
1542 |
|
|
1543 |
if (kctx->auk_policy & AUDIT_ARGE) {
|
|
1544 |
au_uwrite(au_to_exec_env(envstr, envc));
|
|
1545 |
}
|
|
1546 |
}
|
|
1547 |
|
|
1548 |
/*
|
|
1549 |
* ROUTINE: AUDIT_ENTERPROM
|
|
1550 |
* PURPOSE:
|
|
1551 |
* CALLBY: KBDINPUT
|
|
1552 |
* ZSA_XSINT
|
|
1553 |
* NOTE:
|
|
1554 |
* TODO:
|
|
1555 |
* QUESTION:
|
|
1556 |
*/
|
|
1557 |
void
|
|
1558 |
audit_enterprom(int flg)
|
|
1559 |
{
|
|
1560 |
token_t *rp = NULL;
|
|
1561 |
int sorf;
|
|
1562 |
|
|
1563 |
if (flg)
|
|
1564 |
sorf = AUM_SUCC;
|
|
1565 |
else
|
|
1566 |
sorf = AUM_FAIL;
|
|
1567 |
|
|
1568 |
AUDIT_ASYNC_START(rp, AUE_ENTERPROM, sorf);
|
|
1569 |
|
|
1570 |
au_write((caddr_t *)&(rp), au_to_text("kmdb"));
|
|
1571 |
|
|
1572 |
if (flg)
|
|
1573 |
au_write((caddr_t *)&(rp), au_to_return32(0, 0));
|
|
1574 |
else
|
|
1575 |
au_write((caddr_t *)&(rp), au_to_return32(ECANCELED, 0));
|
|
1576 |
|
|
1577 |
AUDIT_ASYNC_FINISH(rp, AUE_ENTERPROM, NULL);
|
|
1578 |
}
|
|
1579 |
|
|
1580 |
|
|
1581 |
/*
|
|
1582 |
* ROUTINE: AUDIT_EXITPROM
|
|
1583 |
* PURPOSE:
|
|
1584 |
* CALLBY: KBDINPUT
|
|
1585 |
* ZSA_XSINT
|
|
1586 |
* NOTE:
|
|
1587 |
* TODO:
|
|
1588 |
* QUESTION:
|
|
1589 |
*/
|
|
1590 |
void
|
|
1591 |
audit_exitprom(int flg)
|
|
1592 |
{
|
|
1593 |
int sorf;
|
|
1594 |
token_t *rp = NULL;
|
|
1595 |
|
|
1596 |
if (flg)
|
|
1597 |
sorf = AUM_SUCC;
|
|
1598 |
else
|
|
1599 |
sorf = AUM_FAIL;
|
|
1600 |
|
|
1601 |
AUDIT_ASYNC_START(rp, AUE_EXITPROM, sorf);
|
|
1602 |
|
|
1603 |
au_write((caddr_t *)&(rp), au_to_text("kmdb"));
|
|
1604 |
|
|
1605 |
if (flg)
|
|
1606 |
au_write((caddr_t *)&(rp), au_to_return32(0, 0));
|
|
1607 |
else
|
|
1608 |
au_write((caddr_t *)&(rp), au_to_return32(ECANCELED, 0));
|
|
1609 |
|
|
1610 |
AUDIT_ASYNC_FINISH(rp, AUE_EXITPROM, NULL);
|
|
1611 |
}
|
|
1612 |
|
|
1613 |
struct fcntla {
|
|
1614 |
int fdes;
|
|
1615 |
int cmd;
|
|
1616 |
intptr_t arg;
|
|
1617 |
};
|
|
1618 |
|
|
1619 |
/*
|
|
1620 |
* ROUTINE: AUDIT_C2_REVOKE
|
|
1621 |
* PURPOSE:
|
|
1622 |
* CALLBY: FCNTL
|
|
1623 |
* NOTE:
|
|
1624 |
* TODO:
|
|
1625 |
* QUESTION: are we keeping this func
|
|
1626 |
*/
|
|
1627 |
|
|
1628 |
/*ARGSUSED*/
|
|
1629 |
int
|
|
1630 |
audit_c2_revoke(struct fcntla *uap, rval_t *rvp)
|
|
1631 |
{
|
|
1632 |
return (0);
|
|
1633 |
}
|
|
1634 |
|
|
1635 |
|
|
1636 |
/*
|
|
1637 |
* ROUTINE: AUDIT_CHDIREC
|
|
1638 |
* PURPOSE:
|
|
1639 |
* CALLBY: CHDIREC
|
|
1640 |
* NOTE: The main function of CHDIREC
|
|
1641 |
* TODO: Move the audit_chdirec hook above the VN_RELE in vncalls.c
|
|
1642 |
* QUESTION:
|
|
1643 |
*/
|
|
1644 |
|
|
1645 |
/*ARGSUSED*/
|
|
1646 |
void
|
|
1647 |
audit_chdirec(vnode_t *vp, vnode_t **vpp)
|
|
1648 |
{
|
|
1649 |
int chdir;
|
|
1650 |
int fchdir;
|
|
1651 |
struct audit_path **appp;
|
|
1652 |
struct file *fp;
|
|
1653 |
f_audit_data_t *fad;
|
|
1654 |
p_audit_data_t *pad = P2A(curproc);
|
|
1655 |
t_audit_data_t *tad = T2A(curthread);
|
|
1656 |
|
|
1657 |
struct a {
|
|
1658 |
long fd;
|
|
1659 |
} *uap = (struct a *)ttolwp(curthread)->lwp_ap;
|
|
1660 |
|
|
1661 |
if ((tad->tad_scid == SYS_chdir) || (tad->tad_scid == SYS_chroot)) {
|
|
1662 |
chdir = tad->tad_scid == SYS_chdir;
|
|
1663 |
if (tad->tad_aupath) {
|
|
1664 |
mutex_enter(&pad->pad_lock);
|
|
1665 |
if (chdir)
|
|
1666 |
appp = &(pad->pad_cwd);
|
|
1667 |
else
|
|
1668 |
appp = &(pad->pad_root);
|
|
1669 |
au_pathrele(*appp);
|
|
1670 |
/* use tad hold */
|
|
1671 |
*appp = tad->tad_aupath;
|
|
1672 |
tad->tad_aupath = NULL;
|
|
1673 |
mutex_exit(&pad->pad_lock);
|
|
1674 |
}
|
|
1675 |
} else if ((tad->tad_scid == SYS_fchdir) ||
|
|
1676 |
(tad->tad_scid == SYS_fchroot)) {
|
|
1677 |
fchdir = tad->tad_scid == SYS_fchdir;
|
|
1678 |
if ((fp = getf(uap->fd)) == NULL)
|
|
1679 |
return;
|
|
1680 |
fad = F2A(fp);
|
|
1681 |
if (fad->fad_aupath) {
|
|
1682 |
au_pathhold(fad->fad_aupath);
|
|
1683 |
mutex_enter(&pad->pad_lock);
|
|
1684 |
if (fchdir)
|
|
1685 |
appp = &(pad->pad_cwd);
|
|
1686 |
else
|
|
1687 |
appp = &(pad->pad_root);
|
|
1688 |
au_pathrele(*appp);
|
|
1689 |
*appp = fad->fad_aupath;
|
|
1690 |
mutex_exit(&pad->pad_lock);
|
|
1691 |
if (tad->tad_flag) {
|
|
1692 |
au_uwrite(au_to_path(fad->fad_aupath));
|
|
1693 |
audit_attributes(fp->f_vnode);
|
|
1694 |
}
|
|
1695 |
}
|
|
1696 |
releasef(uap->fd);
|
|
1697 |
}
|
|
1698 |
}
|
|
1699 |
|
|
1700 |
/*
|
|
1701 |
* ROUTINE: AUDIT_GETF
|
|
1702 |
* PURPOSE:
|
|
1703 |
* CALLBY: GETF_INTERNAL
|
|
1704 |
* NOTE: The main function of GETF_INTERNAL is to associate a given
|
|
1705 |
* file descriptor with a file structure and increment the
|
|
1706 |
* file pointer reference count.
|
|
1707 |
* TODO: remove pass in of fpp.
|
|
1708 |
* increment a reference count so that even if a thread with same process delete
|
|
1709 |
* the same object, it will not panic our system
|
|
1710 |
* QUESTION:
|
|
1711 |
* where to decrement the f_count?????????????????
|
|
1712 |
* seems like I need to set a flag if f_count incrmented through audit_getf
|
|
1713 |
*/
|
|
1714 |
|
|
1715 |
/*ARGSUSED*/
|
|
1716 |
int
|
|
1717 |
audit_getf(int fd)
|
|
1718 |
{
|
|
1719 |
#ifdef NOTYET
|
|
1720 |
t_audit_data_t *tad;
|
|
1721 |
|
|
1722 |
tad = T2A(curthread);
|
|
1723 |
|
|
1724 |
if (!(tad->tad_scid == SYS_open || tad->tad_scid == SYS_creat))
|
|
1725 |
return;
|
|
1726 |
#endif
|
|
1727 |
return (0);
|
|
1728 |
}
|
|
1729 |
|
|
1730 |
/*
|
|
1731 |
* Audit hook for stream based socket and tli request.
|
|
1732 |
* Note that we do not have user context while executing
|
|
1733 |
* this code so we had to record them earlier during the
|
|
1734 |
* putmsg/getmsg to figure out which user we are dealing with.
|
|
1735 |
*/
|
|
1736 |
|
|
1737 |
/*ARGSUSED*/
|
|
1738 |
void
|
|
1739 |
audit_sock(
|
|
1740 |
int type, /* type of tihdr.h header requests */
|
|
1741 |
queue_t *q, /* contains the process and thread audit data */
|
|
1742 |
mblk_t *mp, /* contains the tihdr.h header structures */
|
|
1743 |
int from) /* timod or sockmod request */
|
|
1744 |
{
|
|
1745 |
int32_t len;
|
|
1746 |
int32_t offset;
|
|
1747 |
struct sockaddr_in *sock_data;
|
|
1748 |
struct T_conn_req *conn_req;
|
|
1749 |
struct T_conn_ind *conn_ind;
|
|
1750 |
struct T_unitdata_req *unitdata_req;
|
|
1751 |
struct T_unitdata_ind *unitdata_ind;
|
|
1752 |
au_state_t estate;
|
|
1753 |
t_audit_data_t *tad;
|
|
1754 |
caddr_t saved_thread_ptr;
|
|
1755 |
au_mask_t amask;
|
|
1756 |
const auditinfo_addr_t *ainfo;
|
|
1757 |
au_kcontext_t *kctx;
|
|
1758 |
zone_status_t zstate;
|
|
1759 |
|
|
1760 |
if (q->q_stream == NULL)
|
|
1761 |
return;
|
|
1762 |
mutex_enter(&q->q_stream->sd_lock);
|
|
1763 |
/* are we being audited */
|
|
1764 |
saved_thread_ptr = q->q_stream->sd_t_audit_data;
|
|
1765 |
/* no pointer to thread, nothing to do */
|
|
1766 |
if (saved_thread_ptr == NULL) {
|
|
1767 |
mutex_exit(&q->q_stream->sd_lock);
|
|
1768 |
return;
|
|
1769 |
}
|
|
1770 |
/* only allow one addition of a record token */
|
|
1771 |
q->q_stream->sd_t_audit_data = NULL;
|
|
1772 |
/*
|
|
1773 |
* thread is not the one being audited, then nothing to do
|
|
1774 |
* This could be the stream thread handling the module
|
|
1775 |
* service routine. In this case, the context for the audit
|
|
1776 |
* record can no longer be assumed. Simplest to just drop
|
|
1777 |
* the operation.
|
|
1778 |
*/
|
|
1779 |
if (curthread != (kthread_id_t)saved_thread_ptr) {
|
|
1780 |
mutex_exit(&q->q_stream->sd_lock);
|
|
1781 |
return;
|
|
1782 |
}
|
|
1783 |
if (curthread->t_sysnum >= SYS_so_socket &&
|
|
1784 |
curthread->t_sysnum <= SYS_sockconfig) {
|
|
1785 |
mutex_exit(&q->q_stream->sd_lock);
|
|
1786 |
return;
|
|
1787 |
}
|
|
1788 |
mutex_exit(&q->q_stream->sd_lock);
|
|
1789 |
/*
|
|
1790 |
* we know that the thread that did the put/getmsg is the
|
|
1791 |
* one running. Now we can get the TAD and see if we should
|
|
1792 |
* add an audit token.
|
|
1793 |
*/
|
|
1794 |
tad = U2A(u);
|
|
1795 |
|
|
1796 |
kctx = SET_KCTX_PZ;
|
|
1797 |
if (kctx == NULL) {
|
|
1798 |
zstate = zone_status_get(curproc->p_zone);
|
|
1799 |
ASSERT(zstate != ZONE_IS_READY);
|
|
1800 |
return;
|
|
1801 |
}
|
|
1802 |
|
|
1803 |
/* proceed ONLY if user is being audited */
|
|
1804 |
if (!tad->tad_flag)
|
|
1805 |
return;
|
|
1806 |
|
|
1807 |
ainfo = crgetauinfo(CRED());
|
|
1808 |
if (ainfo == NULL)
|
|
1809 |
return;
|
|
1810 |
amask = ainfo->ai_mask;
|
|
1811 |
|
|
1812 |
/*
|
|
1813 |
* Figure out the type of stream networking request here.
|
|
1814 |
* Note that getmsg and putmsg are always preselected
|
|
1815 |
* because during the beginning of the system call we have
|
|
1816 |
* not yet figure out which of the socket or tli request
|
|
1817 |
* we are looking at until we are here. So we need to check
|
|
1818 |
* against that specific request and reset the type of event.
|
|
1819 |
*/
|
|
1820 |
switch (type) {
|
|
1821 |
case T_CONN_REQ: /* connection request */
|
|
1822 |
conn_req = (struct T_conn_req *)mp->b_rptr;
|
|
1823 |
if (conn_req->DEST_offset < sizeof (struct T_conn_req))
|
|
1824 |
return;
|
|
1825 |
offset = conn_req->DEST_offset;
|
|
1826 |
len = conn_req->DEST_length;
|
|
1827 |
estate = kctx->auk_ets[AUE_SOCKCONNECT];
|
|
1828 |
if (amask.as_success & estate || amask.as_failure & estate) {
|
|
1829 |
tad->tad_event = AUE_SOCKCONNECT;
|
|
1830 |
break;
|
|
1831 |
} else {
|
|
1832 |
return;
|
|
1833 |
}
|
|
1834 |
case T_CONN_IND: /* connectionless receive request */
|
|
1835 |
conn_ind = (struct T_conn_ind *)mp->b_rptr;
|
|
1836 |
if (conn_ind->SRC_offset < sizeof (struct T_conn_ind))
|
|
1837 |
return;
|
|
1838 |
offset = conn_ind->SRC_offset;
|
|
1839 |
len = conn_ind->SRC_length;
|
|
1840 |
estate = kctx->auk_ets[AUE_SOCKACCEPT];
|
|
1841 |
if (amask.as_success & estate || amask.as_failure & estate) {
|
|
1842 |
tad->tad_event = AUE_SOCKACCEPT;
|
|
1843 |
break;
|
|
1844 |
} else {
|
|
1845 |
return;
|
|
1846 |
}
|
|
1847 |
case T_UNITDATA_REQ: /* connectionless send request */
|
|
1848 |
unitdata_req = (struct T_unitdata_req *)mp->b_rptr;
|
|
1849 |
if (unitdata_req->DEST_offset < sizeof (struct T_unitdata_req))
|
|
1850 |
return;
|
|
1851 |
offset = unitdata_req->DEST_offset;
|
|
1852 |
len = unitdata_req->DEST_length;
|
|
1853 |
estate = kctx->auk_ets[AUE_SOCKSEND];
|
|
1854 |
if (amask.as_success & estate || amask.as_failure & estate) {
|
|
1855 |
tad->tad_event = AUE_SOCKSEND;
|
|
1856 |
break;
|
|
1857 |
} else {
|
|
1858 |
return;
|
|
1859 |
}
|
|
1860 |
case T_UNITDATA_IND: /* connectionless receive request */
|
|
1861 |
unitdata_ind = (struct T_unitdata_ind *)mp->b_rptr;
|
|
1862 |
if (unitdata_ind->SRC_offset < sizeof (struct T_unitdata_ind))
|
|
1863 |
return;
|
|
1864 |
offset = unitdata_ind->SRC_offset;
|
|
1865 |
len = unitdata_ind->SRC_length;
|
|
1866 |
estate = kctx->auk_ets[AUE_SOCKRECEIVE];
|
|
1867 |
if (amask.as_success & estate || amask.as_failure & estate) {
|
|
1868 |
tad->tad_event = AUE_SOCKRECEIVE;
|
|
1869 |
break;
|
|
1870 |
} else {
|
|
1871 |
return;
|
|
1872 |
}
|
|
1873 |
default:
|
|
1874 |
return;
|
|
1875 |
}
|
|
1876 |
|
|
1877 |
/*
|
|
1878 |
* we are only interested in tcp stream connections,
|
|
1879 |
* not unix domain stuff
|
|
1880 |
*/
|
|
1881 |
if ((len < 0) || (len > sizeof (struct sockaddr_in))) {
|
|
1882 |
tad->tad_event = AUE_GETMSG;
|
|
1883 |
return;
|
|
1884 |
}
|
|
1885 |
/* skip over TPI header and point to the ip address */
|
|
1886 |
sock_data = (struct sockaddr_in *)((char *)mp->b_rptr + offset);
|
|
1887 |
|
|
1888 |
switch (sock_data->sin_family) {
|
|
1889 |
case AF_INET:
|
|
1890 |
au_write(&(tad->tad_ad), au_to_sock_inet(sock_data));
|
|
1891 |
break;
|
|
1892 |
default: /* reset to AUE_PUTMSG if not a inet request */
|
|
1893 |
tad->tad_event = AUE_GETMSG;
|
|
1894 |
break;
|
|
1895 |
}
|
|
1896 |
}
|
|
1897 |
|
|
1898 |
void
|
|
1899 |
audit_lookupname()
|
|
1900 |
{
|
|
1901 |
}
|
|
1902 |
|
|
1903 |
/*ARGSUSED*/
|
|
1904 |
int
|
|
1905 |
audit_pathcomp(struct pathname *pnp, vnode_t *cvp, cred_t *cr)
|
|
1906 |
{
|
|
1907 |
return (0);
|
|
1908 |
}
|
|
1909 |
|
|
1910 |
static void
|
|
1911 |
add_return_token(caddr_t *ad, unsigned int scid, int err, int rval)
|
|
1912 |
{
|
|
1913 |
unsigned int sy_flags;
|
|
1914 |
|
|
1915 |
#ifdef _SYSCALL32_IMPL
|
|
1916 |
if (lwp_getdatamodel(
|
|
1917 |
ttolwp(curthread)) == DATAMODEL_NATIVE)
|
|
1918 |
sy_flags = sysent[scid].sy_flags & SE_RVAL_MASK;
|
|
1919 |
else
|
|
1920 |
sy_flags = sysent32[scid].sy_flags & SE_RVAL_MASK;
|
|
1921 |
#else
|
|
1922 |
sy_flags = sysent[scid].sy_flags & SE_RVAL_MASK;
|
|
1923 |
#endif
|
|
1924 |
|
|
1925 |
if (sy_flags == SE_64RVAL)
|
|
1926 |
au_write(ad, au_to_return64(err, rval));
|
|
1927 |
else
|
|
1928 |
au_write(ad, au_to_return32(err, rval));
|
|
1929 |
|
|
1930 |
}
|
|
1931 |
|
|
1932 |
/*ARGSUSED*/
|
|
1933 |
void
|
|
1934 |
audit_fdsend(fd, fp, error)
|
|
1935 |
int fd;
|
|
1936 |
struct file *fp;
|
|
1937 |
int error; /* ignore for now */
|
|
1938 |
{
|
|
1939 |
t_audit_data_t *tad; /* current thread */
|
|
1940 |
f_audit_data_t *fad; /* per file audit structure */
|
|
1941 |
struct vnode *vp; /* for file attributes */
|
|
1942 |
|
|
1943 |
/* is this system call being audited */
|
|
1944 |
tad = U2A(u);
|
|
1945 |
ASSERT(tad != (t_audit_data_t *)0);
|
|
1946 |
if (!tad->tad_flag)
|
|
1947 |
return;
|
|
1948 |
|
|
1949 |
fad = F2A(fp);
|
|
1950 |
|
|
1951 |
/* add path and file attributes */
|
|
1952 |
if (fad != NULL && fad->fad_aupath != NULL) {
|
|
1953 |
au_uwrite(au_to_arg32(0, "send fd", (uint32_t)fd));
|
|
1954 |
au_uwrite(au_to_path(fad->fad_aupath));
|
|
1955 |
} else {
|
|
1956 |
au_uwrite(au_to_arg32(0, "send fd", (uint32_t)fd));
|
|
1957 |
#ifdef _LP64
|
|
1958 |
au_uwrite(au_to_arg64(0, "no path", (uint64_t)fp));
|
|
1959 |
#else
|
|
1960 |
au_uwrite(au_to_arg32(0, "no path", (uint32_t)fp));
|
|
1961 |
#endif
|
|
1962 |
}
|
|
1963 |
vp = fp->f_vnode; /* include vnode attributes */
|
|
1964 |
audit_attributes(vp);
|
|
1965 |
}
|
|
1966 |
|
|
1967 |
/*
|
|
1968 |
* Record privileges sucessfully used and we attempted to use but
|
|
1969 |
* didn't have.
|
|
1970 |
*/
|
|
1971 |
void
|
|
1972 |
audit_priv(int priv, const priv_set_t *set, int flag)
|
|
1973 |
{
|
|
1974 |
t_audit_data_t *tad;
|
|
1975 |
int sbit;
|
|
1976 |
priv_set_t *target;
|
|
1977 |
|
|
1978 |
/* Make sure this isn't being called in an interrupt context */
|
|
1979 |
ASSERT(servicing_interrupt() == 0);
|
|
1980 |
|
|
1981 |
tad = U2A(u);
|
|
1982 |
|
|
1983 |
if (tad->tad_flag == 0)
|
|
1984 |
return;
|
|
1985 |
|
|
1986 |
target = flag ? &tad->tad_sprivs : &tad->tad_fprivs;
|
|
1987 |
sbit = flag ? PAD_SPRIVUSE : PAD_FPRIVUSE;
|
|
1988 |
|
|
1989 |
/* Tell audit_success() and audit_finish() that we saw this case */
|
|
1990 |
if (!(tad->tad_evmod & sbit)) {
|
|
1991 |
/* Clear set first time around */
|
|
1992 |
priv_emptyset(target);
|
|
1993 |
tad->tad_evmod |= sbit;
|
|
1994 |
}
|
|
1995 |
|
|
1996 |
/* Save the privileges in the tad */
|
|
1997 |
if (priv == PRIV_ALL) {
|
|
1998 |
priv_fillset(target);
|
|
1999 |
} else {
|
|
2000 |
ASSERT(set != NULL || priv != PRIV_NONE);
|
|
2001 |
if (set != NULL)
|
|
2002 |
priv_union(set, target);
|
|
2003 |
if (priv != PRIV_NONE)
|
|
2004 |
priv_addset(target, priv);
|
|
2005 |
}
|
|
2006 |
}
|
|
2007 |
|
|
2008 |
/*
|
|
2009 |
* Audit the setpriv() system call; the operation, the set name and
|
|
2010 |
* the current value as well as the set argument are put in the
|
|
2011 |
* audit trail.
|
|
2012 |
*/
|
|
2013 |
void
|
|
2014 |
audit_setppriv(int op, int set, const priv_set_t *newpriv, const cred_t *ocr)
|
|
2015 |
{
|
|
2016 |
t_audit_data_t *tad;
|
|
2017 |
const priv_set_t *oldpriv;
|
|
2018 |
priv_set_t report;
|
|
2019 |
const char *setname;
|
|
2020 |
|
|
2021 |
tad = U2A(u);
|
|
2022 |
|
|
2023 |
if (tad->tad_flag == 0)
|
|
2024 |
return;
|
|
2025 |
|
|
2026 |
oldpriv = priv_getset(ocr, set);
|
|
2027 |
|
|
2028 |
/* Generate the actual record, include the before and after */
|
|
2029 |
au_uwrite(au_to_arg32(2, "op", op));
|
|
2030 |
setname = priv_getsetbynum(set);
|
|
2031 |
|
|
2032 |
switch (op) {
|
|
2033 |
case PRIV_OFF:
|
|
2034 |
/* Report privileges actually switched off */
|
|
2035 |
report = *oldpriv;
|
|
2036 |
priv_intersect(newpriv, &report);
|
|
2037 |
au_uwrite(au_to_privset(setname, &report, AUT_PRIV, 0));
|
|
2038 |
break;
|
|
2039 |
case PRIV_ON:
|
|
2040 |
/* Report privileges actually switched on */
|
|
2041 |
report = *oldpriv;
|
|
2042 |
priv_inverse(&report);
|
|
2043 |
priv_intersect(newpriv, &report);
|
|
2044 |
au_uwrite(au_to_privset(setname, &report, AUT_PRIV, 0));
|
|
2045 |
break;
|
|
2046 |
case PRIV_SET:
|
|
2047 |
/* Report before and after */
|
|
2048 |
au_uwrite(au_to_privset(setname, oldpriv, AUT_PRIV, 0));
|
|
2049 |
au_uwrite(au_to_privset(setname, newpriv, AUT_PRIV, 0));
|
|
2050 |
break;
|
|
2051 |
}
|
|
2052 |
}
|
|
2053 |
|
|
2054 |
/*
|
|
2055 |
* Dump the full device policy setting in the audit trail.
|
|
2056 |
*/
|
|
2057 |
void
|
|
2058 |
audit_devpolicy(int nitems, const devplcysys_t *items)
|
|
2059 |
{
|
|
2060 |
t_audit_data_t *tad;
|
|
2061 |
int i;
|
|
2062 |
|
|
2063 |
tad = U2A(u);
|
|
2064 |
|
|
2065 |
if (tad->tad_flag == 0)
|
|
2066 |
return;
|
|
2067 |
|
|
2068 |
for (i = 0; i < nitems; i++) {
|
|
2069 |
au_uwrite(au_to_arg32(2, "major", items[i].dps_maj));
|
|
2070 |
if (items[i].dps_minornm[0] == '\0') {
|
|
2071 |
au_uwrite(au_to_arg32(2, "lomin", items[i].dps_lomin));
|
|
2072 |
au_uwrite(au_to_arg32(2, "himin", items[i].dps_himin));
|
|
2073 |
} else
|
|
2074 |
au_uwrite(au_to_text(items[i].dps_minornm));
|
|
2075 |
|
|
2076 |
au_uwrite(au_to_privset("read", &items[i].dps_rdp,
|
|
2077 |
AUT_PRIV, 0));
|
|
2078 |
au_uwrite(au_to_privset("write", &items[i].dps_wrp,
|
|
2079 |
AUT_PRIV, 0));
|
|
2080 |
}
|
|
2081 |
}
|
|
2082 |
|
|
2083 |
/*ARGSUSED*/
|
|
2084 |
void
|
|
2085 |
audit_fdrecv(fd, fp)
|
|
2086 |
int fd;
|
|
2087 |
struct file *fp;
|
|
2088 |
{
|
|
2089 |
t_audit_data_t *tad; /* current thread */
|
|
2090 |
f_audit_data_t *fad; /* per file audit structure */
|
|
2091 |
struct vnode *vp; /* for file attributes */
|
|
2092 |
|
|
2093 |
/* is this system call being audited */
|
|
2094 |
tad = U2A(u);
|
|
2095 |
ASSERT(tad != (t_audit_data_t *)0);
|
|
2096 |
if (!tad->tad_flag)
|
|
2097 |
return;
|
|
2098 |
|
|
2099 |
fad = F2A(fp);
|
|
2100 |
|
|
2101 |
/* add path and file attributes */
|
|
2102 |
if (fad != NULL && fad->fad_aupath != NULL) {
|
|
2103 |
au_uwrite(au_to_arg32(0, "recv fd", (uint32_t)fd));
|
|
2104 |
au_uwrite(au_to_path(fad->fad_aupath));
|
|
2105 |
} else {
|
|
2106 |
au_uwrite(au_to_arg32(0, "recv fd", (uint32_t)fd));
|
|
2107 |
#ifdef _LP64
|
|
2108 |
au_uwrite(au_to_arg64(0, "no path", (uint64_t)fp));
|
|
2109 |
#else
|
|
2110 |
au_uwrite(au_to_arg32(0, "no path", (uint32_t)fp));
|
|
2111 |
#endif
|
|
2112 |
}
|
|
2113 |
vp = fp->f_vnode; /* include vnode attributes */
|
|
2114 |
audit_attributes(vp);
|
|
2115 |
}
|
|
2116 |
|
|
2117 |
/*
|
|
2118 |
* ROUTINE: AUDIT_CRYPTOADM
|
|
2119 |
* PURPOSE: Records arguments to administrative ioctls on /dev/cryptoadm
|
|
2120 |
* CALLBY: CRYPTO_LOAD_DEV_DISABLED, CRYPTO_LOAD_SOFT_DISABLED,
|
|
2121 |
* CRYPTO_UNLOAD_SOFT_MODULE, CRYPTO_LOAD_SOFT_CONFIG,
|
|
2122 |
* CRYPTO_POOL_CREATE, CRYPTO_POOL_WAIT, CRYPTO_POOL_RUN,
|
|
2123 |
* CRYPTO_LOAD_DOOR
|
|
2124 |
* NOTE:
|
|
2125 |
* TODO:
|
|
2126 |
* QUESTION:
|
|
2127 |
*/
|
|
2128 |
|
|
2129 |
void
|
|
2130 |
audit_cryptoadm(int cmd, char *module_name, crypto_mech_name_t *mech_names,
|
|
2131 |
uint_t mech_count, uint_t device_instance, uint32_t rv, int error)
|
|
2132 |
{
|
|
2133 |
boolean_t mech_list_required = B_FALSE;
|
|
2134 |
cred_t *cr = CRED();
|
|
2135 |
t_audit_data_t *tad;
|
|
2136 |
token_t *ad = NULL;
|
|
2137 |
const auditinfo_addr_t *ainfo = crgetauinfo(cr);
|
|
2138 |
char buffer[MAXNAMELEN * 2];
|
|
2139 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
2140 |
|
|
2141 |
ASSERT(kctx != NULL);
|
|
2142 |
|
|
2143 |
tad = U2A(u);
|
|
2144 |
if (tad == NULL)
|
|
2145 |
return;
|
|
2146 |
|
|
2147 |
if (ainfo == NULL)
|
|
2148 |
return;
|
|
2149 |
|
|
2150 |
tad->tad_event = AUE_CRYPTOADM;
|
|
2151 |
|
|
2152 |
if (audit_success(kctx, tad, error) != AU_OK)
|
|
2153 |
return;
|
|
2154 |
|
|
2155 |
/* Add a subject token */
|
|
2156 |
AUDIT_SETSUBJ((caddr_t *)&(ad), cr, ainfo);
|
|
2157 |
|
|
2158 |
/* add an optional group token */
|
|
2159 |
AUDIT_SETGROUP((caddr_t *)&(ad), cr, kctx);
|
|
2160 |
|
|
2161 |
switch (cmd) {
|
|
2162 |
case CRYPTO_LOAD_DEV_DISABLED:
|
|
2163 |
if (error == 0 && rv == CRYPTO_SUCCESS) {
|
|
2164 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2165 |
"op=CRYPTO_LOAD_DEV_DISABLED, module=%s,"
|
|
2166 |
" dev_instance=%d",
|
|
2167 |
module_name, device_instance);
|
|
2168 |
mech_list_required = B_TRUE;
|
|
2169 |
} else {
|
|
2170 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2171 |
"op=CRYPTO_LOAD_DEV_DISABLED, return_val=%d", rv);
|
|
2172 |
}
|
|
2173 |
break;
|
|
2174 |
|
|
2175 |
case CRYPTO_LOAD_SOFT_DISABLED:
|
|
2176 |
if (error == 0 && rv == CRYPTO_SUCCESS) {
|
|
2177 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2178 |
"op=CRYPTO_LOAD_SOFT_DISABLED, module=%s",
|
|
2179 |
module_name);
|
|
2180 |
mech_list_required = B_TRUE;
|
|
2181 |
} else {
|
|
2182 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2183 |
"op=CRYPTO_LOAD_SOFT_DISABLED, return_val=%d", rv);
|
|
2184 |
}
|
|
2185 |
break;
|
|
2186 |
|
|
2187 |
case CRYPTO_UNLOAD_SOFT_MODULE:
|
|
2188 |
if (error == 0 && rv == CRYPTO_SUCCESS) {
|
|
2189 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2190 |
"op=CRYPTO_UNLOAD_SOFT_MODULE, module=%s",
|
|
2191 |
module_name);
|
|
2192 |
} else {
|
|
2193 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2194 |
"op=CRYPTO_UNLOAD_SOFT_MODULE, return_val=%d", rv);
|
|
2195 |
}
|
|
2196 |
break;
|
|
2197 |
|
|
2198 |
case CRYPTO_LOAD_SOFT_CONFIG:
|
|
2199 |
if (error == 0 && rv == CRYPTO_SUCCESS) {
|
|
2200 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2201 |
"op=CRYPTO_LOAD_SOFT_CONFIG, module=%s",
|
|
2202 |
module_name);
|
|
2203 |
mech_list_required = B_TRUE;
|
|
2204 |
} else {
|
|
2205 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2206 |
"op=CRYPTO_LOAD_SOFT_CONFIG, return_val=%d", rv);
|
|
2207 |
}
|
|
2208 |
break;
|
|
2209 |
|
|
2210 |
case CRYPTO_POOL_CREATE:
|
|
2211 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2212 |
"op=CRYPTO_POOL_CREATE");
|
|
2213 |
break;
|
|
2214 |
|
|
2215 |
case CRYPTO_POOL_WAIT:
|
|
2216 |
(void) snprintf(buffer, sizeof (buffer), "op=CRYPTO_POOL_WAIT");
|
|
2217 |
break;
|
|
2218 |
|
|
2219 |
case CRYPTO_POOL_RUN:
|
|
2220 |
(void) snprintf(buffer, sizeof (buffer), "op=CRYPTO_POOL_RUN");
|
|
2221 |
break;
|
|
2222 |
|
|
2223 |
case CRYPTO_LOAD_DOOR:
|
|
2224 |
if (error == 0 && rv == CRYPTO_SUCCESS)
|
|
2225 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2226 |
"op=CRYPTO_LOAD_DOOR");
|
|
2227 |
else
|
|
2228 |
(void) snprintf(buffer, sizeof (buffer),
|
|
2229 |
"op=CRYPTO_LOAD_DOOR, return_val=%d", rv);
|
|
2230 |
break;
|
|
2231 |
|
|
2232 |
default:
|
|
2233 |
return;
|
|
2234 |
}
|
|
2235 |
|
|
2236 |
au_write((caddr_t *)&ad, au_to_text(buffer));
|
|
2237 |
|
|
2238 |
if (mech_list_required) {
|
|
2239 |
int i;
|
|
2240 |
|
|
2241 |
if (mech_count == 0) {
|
|
2242 |
au_write((caddr_t *)&ad, au_to_text("mech=list empty"));
|
|
2243 |
} else {
|
|
2244 |
char *pb = buffer;
|
|
2245 |
size_t l = sizeof (buffer);
|
|
2246 |
size_t n;
|
|
2247 |
char space[2] = ":";
|
|
2248 |
|
|
2249 |
n = snprintf(pb, l, "mech=");
|
|
2250 |
|
|
2251 |
for (i = 0; i < mech_count; i++) {
|
|
2252 |
pb += n;
|
|
2253 |
l -= n;
|
|
2254 |
if (l < 0)
|
|
2255 |
l = 0;
|
|
2256 |
|
|
2257 |
if (i == mech_count - 1)
|
|
2258 |
(void) strcpy(space, "");
|
|
2259 |
|
|
2260 |
n = snprintf(pb, l, "%s%s", mech_names[i],
|
|
2261 |
space);
|
|
2262 |
}
|
|
2263 |
au_write((caddr_t *)&ad, au_to_text(buffer));
|
|
2264 |
}
|
|
2265 |
}
|
|
2266 |
|
|
2267 |
/* add a return token */
|
|
2268 |
if (error || (rv != CRYPTO_SUCCESS))
|
|
2269 |
add_return_token((caddr_t *)&ad, tad->tad_scid, -1, error);
|
|
2270 |
else
|
|
2271 |
add_return_token((caddr_t *)&ad, tad->tad_scid, 0, rv);
|
|
2272 |
|
|
2273 |
AS_INC(as_generated, 1, kctx);
|
|
2274 |
AS_INC(as_kernel, 1, kctx);
|
|
2275 |
|
|
2276 |
au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CRYPTOADM, 0);
|
|
2277 |
}
|
898
|
2278 |
|
|
2279 |
/*
|
|
2280 |
* Audit the kernel SSL administration command. The address and the
|
|
2281 |
* port number for the SSL instance, and the proxy port are put in the
|
|
2282 |
* audit trail.
|
|
2283 |
*/
|
|
2284 |
void
|
|
2285 |
audit_kssl(int cmd, void *params, int error)
|
|
2286 |
{
|
|
2287 |
cred_t *cr = CRED();
|
|
2288 |
t_audit_data_t *tad;
|
|
2289 |
token_t *ad = NULL;
|
|
2290 |
const auditinfo_addr_t *ainfo = crgetauinfo(cr);
|
|
2291 |
au_kcontext_t *kctx = SET_KCTX_PZ;
|
|
2292 |
|
|
2293 |
ASSERT(kctx != NULL);
|
|
2294 |
tad = U2A(u);
|
|
2295 |
|
|
2296 |
if (ainfo == NULL)
|
|
2297 |
return;
|
|
2298 |
|
|
2299 |
tad->tad_event = AUE_CONFIGKSSL;
|
|
2300 |
|
|
2301 |
if (audit_success(kctx, tad, error) != AU_OK)
|
|
2302 |
return;
|
|
2303 |
|
|
2304 |
/* Add a subject token */
|
|
2305 |
AUDIT_SETSUBJ((caddr_t *)&ad, cr, ainfo);
|
|
2306 |
|
|
2307 |
/* add an optional group token */
|
|
2308 |
AUDIT_SETGROUP((caddr_t *)&ad, cr, kctx);
|
|
2309 |
|
|
2310 |
switch (cmd) {
|
|
2311 |
case KSSL_ADD_ENTRY: {
|
|
2312 |
char buf[32];
|
|
2313 |
kssl_params_t *kp = (kssl_params_t *)params;
|
|
2314 |
struct sockaddr_in *saddr = &(kp->kssl_addr);
|
|
2315 |
|
|
2316 |
au_write((caddr_t *)&ad, au_to_text("op=KSSL_ADD_ENTRY"));
|
|
2317 |
au_write((caddr_t *)&ad, au_to_in_addr(&(saddr->sin_addr)));
|
|
2318 |
(void) snprintf(buf, sizeof (buf), "SSL port=%d",
|
|
2319 |
saddr->sin_port);
|
|
2320 |
au_write((caddr_t *)&ad, au_to_text(buf));
|
|
2321 |
|
|
2322 |
(void) snprintf(buf, sizeof (buf), "proxy port=%d",
|
|
2323 |
kp->kssl_proxy_port);
|
|
2324 |
au_write((caddr_t *)&ad, au_to_text(buf));
|
|
2325 |
break;
|
|
2326 |
}
|
|
2327 |
|
|
2328 |
case KSSL_DELETE_ENTRY: {
|
|
2329 |
char buf[32];
|
|
2330 |
struct sockaddr_in *saddr = (struct sockaddr_in *)params;
|
|
2331 |
|
|
2332 |
au_write((caddr_t *)&ad, au_to_text("op=KSSL_DELETE_ENTRY"));
|
|
2333 |
au_write((caddr_t *)&ad, au_to_in_addr(&(saddr->sin_addr)));
|
|
2334 |
(void) snprintf(buf, sizeof (buf), "SSL port=%d",
|
|
2335 |
saddr->sin_port);
|
|
2336 |
au_write((caddr_t *)&ad, au_to_text(buf));
|
|
2337 |
break;
|
|
2338 |
}
|
|
2339 |
|
|
2340 |
default:
|
|
2341 |
return;
|
|
2342 |
}
|
|
2343 |
|
|
2344 |
/* add a return token */
|
|
2345 |
add_return_token((caddr_t *)&ad, tad->tad_scid, error, 0);
|
|
2346 |
|
|
2347 |
AS_INC(as_generated, 1, kctx);
|
|
2348 |
AS_INC(as_kernel, 1, kctx);
|
|
2349 |
|
|
2350 |
au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CONFIGKSSL, 0);
|
|
2351 |
}
|