1155192Srwatson/*
2188313Srwatson * Copyright (c) 1999-2009 Apple Inc.
3155192Srwatson * Copyright (c) 2005 Robert N. M. Watson
4155192Srwatson * All rights reserved.
5155192Srwatson *
6155192Srwatson * Redistribution and use in source and binary forms, with or without
7155192Srwatson * modification, are permitted provided that the following conditions
8155192Srwatson * are met:
9155192Srwatson * 1.  Redistributions of source code must retain the above copyright
10155192Srwatson *     notice, this list of conditions and the following disclaimer.
11155192Srwatson * 2.  Redistributions in binary form must reproduce the above copyright
12155192Srwatson *     notice, this list of conditions and the following disclaimer in the
13155192Srwatson *     documentation and/or other materials provided with the distribution.
14180701Srwatson * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15155192Srwatson *     its contributors may be used to endorse or promote products derived
16155192Srwatson *     from this software without specific prior written permission.
17155192Srwatson *
18155192Srwatson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21155192Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22155192Srwatson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26155192Srwatson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27155192Srwatson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28155192Srwatson * POSSIBILITY OF SUCH DAMAGE.
29155192Srwatson */
30155192Srwatson
31178186Srwatson#include <sys/cdefs.h>
32178186Srwatson__FBSDID("$FreeBSD$");
33178186Srwatson
34155192Srwatson#include <sys/param.h>
35155192Srwatson#include <sys/fcntl.h>
36155192Srwatson#include <sys/filedesc.h>
37155192Srwatson#include <sys/libkern.h>
38155192Srwatson#include <sys/malloc.h>
39155192Srwatson#include <sys/mount.h>
40155192Srwatson#include <sys/proc.h>
41184482Srwatson#include <sys/rwlock.h>
42155192Srwatson#include <sys/sem.h>
43181060Scsjp#include <sys/sbuf.h>
44155192Srwatson#include <sys/syscall.h>
45155192Srwatson#include <sys/sysctl.h>
46155192Srwatson#include <sys/sysent.h>
47155192Srwatson#include <sys/vnode.h>
48155192Srwatson
49155192Srwatson#include <bsm/audit.h>
50155192Srwatson#include <bsm/audit_kevents.h>
51155192Srwatson#include <security/audit/audit.h>
52155192Srwatson#include <security/audit/audit_private.h>
53155192Srwatson
54155192Srwatson/*
55155192Srwatson * Hash table functions for the audit event number to event class mask
56155192Srwatson * mapping.
57155192Srwatson */
58180735Srwatson#define	EVCLASSMAP_HASH_TABLE_SIZE	251
59155192Srwatsonstruct evclass_elem {
60155192Srwatson	au_event_t event;
61155192Srwatson	au_class_t class;
62155192Srwatson	LIST_ENTRY(evclass_elem) entry;
63155192Srwatson};
64155192Srwatsonstruct evclass_list {
65155192Srwatson	LIST_HEAD(, evclass_elem) head;
66155192Srwatson};
67155192Srwatson
68155192Srwatsonstatic MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
69184482Srwatsonstatic struct rwlock		evclass_lock;
70156889Srwatsonstatic struct evclass_list	evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
71155192Srwatson
72184482Srwatson#define	EVCLASS_LOCK_INIT()	rw_init(&evclass_lock, "evclass_lock")
73184482Srwatson#define	EVCLASS_RLOCK()		rw_rlock(&evclass_lock)
74184482Srwatson#define	EVCLASS_RUNLOCK()	rw_runlock(&evclass_lock)
75184482Srwatson#define	EVCLASS_WLOCK()		rw_wlock(&evclass_lock)
76184482Srwatson#define	EVCLASS_WUNLOCK()	rw_wunlock(&evclass_lock)
77184482Srwatson
78195925Srwatsonstruct aue_open_event {
79195925Srwatson	int		aoe_flags;
80195925Srwatson	au_event_t	aoe_event;
81195925Srwatson};
82195925Srwatson
83195925Srwatsonstatic const struct aue_open_event aue_open[] = {
84195925Srwatson	{ O_RDONLY,					AUE_OPEN_R },
85195925Srwatson	{ (O_RDONLY | O_CREAT),				AUE_OPEN_RC },
86195925Srwatson	{ (O_RDONLY | O_CREAT | O_TRUNC),		AUE_OPEN_RTC },
87195925Srwatson	{ (O_RDONLY | O_TRUNC),				AUE_OPEN_RT },
88195925Srwatson	{ O_RDWR,					AUE_OPEN_RW },
89195925Srwatson	{ (O_RDWR | O_CREAT),				AUE_OPEN_RWC },
90195925Srwatson	{ (O_RDWR | O_CREAT | O_TRUNC),			AUE_OPEN_RWTC },
91195925Srwatson	{ (O_RDWR | O_TRUNC),				AUE_OPEN_RWT },
92195925Srwatson	{ O_WRONLY,					AUE_OPEN_W },
93195925Srwatson	{ (O_WRONLY | O_CREAT),				AUE_OPEN_WC },
94195925Srwatson	{ (O_WRONLY | O_CREAT | O_TRUNC),		AUE_OPEN_WTC },
95195925Srwatson	{ (O_WRONLY | O_TRUNC),				AUE_OPEN_WT },
96195925Srwatson};
97195925Srwatsonstatic const int aue_open_count = sizeof(aue_open) / sizeof(aue_open[0]);
98195925Srwatson
99195925Srwatsonstatic const struct aue_open_event aue_openat[] = {
100195925Srwatson	{ O_RDONLY,					AUE_OPENAT_R },
101195925Srwatson	{ (O_RDONLY | O_CREAT),				AUE_OPENAT_RC },
102195925Srwatson	{ (O_RDONLY | O_CREAT | O_TRUNC),		AUE_OPENAT_RTC },
103195925Srwatson	{ (O_RDONLY | O_TRUNC),				AUE_OPENAT_RT },
104195925Srwatson	{ O_RDWR,					AUE_OPENAT_RW },
105195925Srwatson	{ (O_RDWR | O_CREAT),				AUE_OPENAT_RWC },
106195925Srwatson	{ (O_RDWR | O_CREAT | O_TRUNC),			AUE_OPENAT_RWTC },
107195925Srwatson	{ (O_RDWR | O_TRUNC),				AUE_OPENAT_RWT },
108195925Srwatson	{ O_WRONLY,					AUE_OPENAT_W },
109195925Srwatson	{ (O_WRONLY | O_CREAT),				AUE_OPENAT_WC },
110195925Srwatson	{ (O_WRONLY | O_CREAT | O_TRUNC),		AUE_OPENAT_WTC },
111195925Srwatson	{ (O_WRONLY | O_TRUNC),				AUE_OPENAT_WT },
112195925Srwatson};
113195925Srwatsonstatic const int aue_openat_count = sizeof(aue_openat) / sizeof(aue_openat[0]);
114195925Srwatson
115155192Srwatson/*
116155192Srwatson * Look up the class for an audit event in the class mapping table.
117155192Srwatson */
118155192Srwatsonau_class_t
119155192Srwatsonau_event_class(au_event_t event)
120155192Srwatson{
121155192Srwatson	struct evclass_list *evcl;
122155192Srwatson	struct evclass_elem *evc;
123155192Srwatson	au_class_t class;
124155192Srwatson
125184482Srwatson	EVCLASS_RLOCK();
126155192Srwatson	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
127173142Srwatson	class = 0;
128155192Srwatson	LIST_FOREACH(evc, &evcl->head, entry) {
129155192Srwatson		if (evc->event == event) {
130155192Srwatson			class = evc->class;
131155192Srwatson			goto out;
132155192Srwatson		}
133155192Srwatson	}
134155192Srwatsonout:
135184482Srwatson	EVCLASS_RUNLOCK();
136155192Srwatson	return (class);
137155192Srwatson}
138155192Srwatson
139156889Srwatson/*
140155192Srwatson * Insert a event to class mapping. If the event already exists in the
141155192Srwatson * mapping, then replace the mapping with the new one.
142156889Srwatson *
143155192Srwatson * XXX There is currently no constraints placed on the number of mappings.
144156889Srwatson * May want to either limit to a number, or in terms of memory usage.
145155192Srwatson */
146155192Srwatsonvoid
147156889Srwatsonau_evclassmap_insert(au_event_t event, au_class_t class)
148155192Srwatson{
149155192Srwatson	struct evclass_list *evcl;
150155192Srwatson	struct evclass_elem *evc, *evc_new;
151155192Srwatson
152155192Srwatson	/*
153155192Srwatson	 * Pessimistically, always allocate storage before acquiring mutex.
154155192Srwatson	 * Free if there is already a mapping for this event.
155155192Srwatson	 */
156155192Srwatson	evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
157155192Srwatson
158184482Srwatson	EVCLASS_WLOCK();
159155192Srwatson	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
160155192Srwatson	LIST_FOREACH(evc, &evcl->head, entry) {
161155192Srwatson		if (evc->event == event) {
162155192Srwatson			evc->class = class;
163184482Srwatson			EVCLASS_WUNLOCK();
164155192Srwatson			free(evc_new, M_AUDITEVCLASS);
165155192Srwatson			return;
166155192Srwatson		}
167155192Srwatson	}
168155192Srwatson	evc = evc_new;
169155192Srwatson	evc->event = event;
170155192Srwatson	evc->class = class;
171155192Srwatson	LIST_INSERT_HEAD(&evcl->head, evc, entry);
172184482Srwatson	EVCLASS_WUNLOCK();
173155192Srwatson}
174155192Srwatson
175155192Srwatsonvoid
176156889Srwatsonau_evclassmap_init(void)
177155192Srwatson{
178155192Srwatson	int i;
179155192Srwatson
180184482Srwatson	EVCLASS_LOCK_INIT();
181155192Srwatson	for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
182155192Srwatson		LIST_INIT(&evclass_hash[i].head);
183155192Srwatson
184155192Srwatson	/*
185155192Srwatson	 * Set up the initial event to class mapping for system calls.
186155192Srwatson	 *
187155192Srwatson	 * XXXRW: Really, this should walk all possible audit events, not all
188155192Srwatson	 * native ABI system calls, as there may be audit events reachable
189155192Srwatson	 * only through non-native system calls.  It also seems a shame to
190155192Srwatson	 * frob the mutex this early.
191156889Srwatson	 */
192155192Srwatson	for (i = 0; i < SYS_MAXSYSCALL; i++) {
193155192Srwatson		if (sysent[i].sy_auevent != AUE_NULL)
194173142Srwatson			au_evclassmap_insert(sysent[i].sy_auevent, 0);
195155192Srwatson	}
196155192Srwatson}
197155192Srwatson
198155192Srwatson/*
199155192Srwatson * Check whether an event is aditable by comparing the mask of classes this
200155192Srwatson * event is part of against the given mask.
201155192Srwatson */
202155192Srwatsonint
203159269Srwatsonau_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
204155192Srwatson{
205155192Srwatson	au_class_t effmask = 0;
206155192Srwatson
207155192Srwatson	if (mask_p == NULL)
208155192Srwatson		return (-1);
209155192Srwatson
210156889Srwatson	/*
211155192Srwatson	 * Perform the actual check of the masks against the event.
212155192Srwatson	 */
213155192Srwatson	if (sorf & AU_PRS_SUCCESS)
214159269Srwatson		effmask |= (mask_p->am_success & class);
215156889Srwatson
216155192Srwatson	if (sorf & AU_PRS_FAILURE)
217159269Srwatson		effmask |= (mask_p->am_failure & class);
218156889Srwatson
219155192Srwatson	if (effmask)
220155192Srwatson		return (1);
221156889Srwatson	else
222155192Srwatson		return (0);
223155192Srwatson}
224155192Srwatson
225155192Srwatson/*
226156889Srwatson * Convert sysctl names and present arguments to events.
227155192Srwatson */
228155192Srwatsonau_event_t
229176690Srwatsonaudit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
230155192Srwatson{
231155192Srwatson
232155192Srwatson	/* can't parse it - so return the worst case */
233156889Srwatson	if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
234155192Srwatson		return (AUE_SYSCTL);
235155192Srwatson
236155192Srwatson	switch (name[0]) {
237155192Srwatson	/* non-admin "lookups" treat them special */
238155192Srwatson	case KERN_OSTYPE:
239155192Srwatson	case KERN_OSRELEASE:
240155192Srwatson	case KERN_OSREV:
241155192Srwatson	case KERN_VERSION:
242155192Srwatson	case KERN_ARGMAX:
243155192Srwatson	case KERN_CLOCKRATE:
244155192Srwatson	case KERN_BOOTTIME:
245155192Srwatson	case KERN_POSIX1:
246155192Srwatson	case KERN_NGROUPS:
247155192Srwatson	case KERN_JOB_CONTROL:
248155192Srwatson	case KERN_SAVED_IDS:
249155192Srwatson	case KERN_OSRELDATE:
250155192Srwatson	case KERN_DUMMY:
251155192Srwatson		return (AUE_SYSCTL_NONADMIN);
252155192Srwatson
253155192Srwatson	/* only treat the changeable controls as admin */
254155192Srwatson	case KERN_MAXVNODES:
255155192Srwatson	case KERN_MAXPROC:
256155192Srwatson	case KERN_MAXFILES:
257155192Srwatson	case KERN_MAXPROCPERUID:
258155192Srwatson	case KERN_MAXFILESPERPROC:
259155192Srwatson	case KERN_HOSTID:
260155192Srwatson	case KERN_SECURELVL:
261155192Srwatson	case KERN_HOSTNAME:
262155192Srwatson	case KERN_VNODE:
263155192Srwatson	case KERN_PROC:
264155192Srwatson	case KERN_FILE:
265155192Srwatson	case KERN_PROF:
266155192Srwatson	case KERN_NISDOMAINNAME:
267155192Srwatson	case KERN_UPDATEINTERVAL:
268155192Srwatson	case KERN_NTP_PLL:
269155192Srwatson	case KERN_BOOTFILE:
270155192Srwatson	case KERN_DUMPDEV:
271155192Srwatson	case KERN_IPC:
272155192Srwatson	case KERN_PS_STRINGS:
273155192Srwatson	case KERN_USRSTACK:
274155192Srwatson	case KERN_LOGSIGEXIT:
275155192Srwatson	case KERN_IOV_MAX:
276155192Srwatson		return ((valid_arg & ARG_VALUE) ?
277181053Srwatson		    AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
278155192Srwatson
279155192Srwatson	default:
280155192Srwatson		return (AUE_SYSCTL);
281155192Srwatson	}
282155192Srwatson	/* NOTREACHED */
283155192Srwatson}
284155192Srwatson
285155192Srwatson/*
286156889Srwatson * Convert an open flags specifier into a specific type of open event for
287155192Srwatson * auditing purposes.
288155192Srwatson */
289155192Srwatsonau_event_t
290176690Srwatsonaudit_flags_and_error_to_openevent(int oflags, int error)
291156889Srwatson{
292195925Srwatson	int i;
293155192Srwatson
294156889Srwatson	/*
295156889Srwatson	 * Need to check only those flags we care about.
296156889Srwatson	 */
297155192Srwatson	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
298195925Srwatson	for (i = 0; i < aue_open_count; i++) {
299195925Srwatson		if (aue_open[i].aoe_flags == oflags)
300195925Srwatson			return (aue_open[i].aoe_event);
301195925Srwatson	}
302195925Srwatson	return (AUE_OPEN);
303195925Srwatson}
304155192Srwatson
305195925Srwatsonau_event_t
306195925Srwatsonaudit_flags_and_error_to_openatevent(int oflags, int error)
307195925Srwatson{
308195925Srwatson	int i;
309155192Srwatson
310156889Srwatson	/*
311195925Srwatson	 * Need to check only those flags we care about.
312155192Srwatson	 */
313195925Srwatson	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
314195925Srwatson	for (i = 0; i < aue_openat_count; i++) {
315195925Srwatson		if (aue_openat[i].aoe_flags == oflags)
316195925Srwatson			return (aue_openat[i].aoe_event);
317155192Srwatson	}
318195925Srwatson	return (AUE_OPENAT);
319155192Srwatson}
320155192Srwatson
321155192Srwatson/*
322155192Srwatson * Convert a MSGCTL command to a specific event.
323155192Srwatson */
324188313Srwatsonau_event_t
325176565Srwatsonaudit_msgctl_to_event(int cmd)
326155192Srwatson{
327155192Srwatson
328155192Srwatson	switch (cmd) {
329155192Srwatson	case IPC_RMID:
330155192Srwatson		return (AUE_MSGCTL_RMID);
331155192Srwatson
332155192Srwatson	case IPC_SET:
333155192Srwatson		return (AUE_MSGCTL_SET);
334155192Srwatson
335155192Srwatson	case IPC_STAT:
336155192Srwatson		return (AUE_MSGCTL_STAT);
337155192Srwatson
338155192Srwatson	default:
339170196Srwatson		/* We will audit a bad command. */
340155192Srwatson		return (AUE_MSGCTL);
341155192Srwatson	}
342155192Srwatson}
343155192Srwatson
344155192Srwatson/*
345155192Srwatson * Convert a SEMCTL command to a specific event.
346155192Srwatson */
347188313Srwatsonau_event_t
348176565Srwatsonaudit_semctl_to_event(int cmd)
349155192Srwatson{
350155192Srwatson
351155192Srwatson	switch (cmd) {
352155192Srwatson	case GETALL:
353155192Srwatson		return (AUE_SEMCTL_GETALL);
354155192Srwatson
355155192Srwatson	case GETNCNT:
356155192Srwatson		return (AUE_SEMCTL_GETNCNT);
357155192Srwatson
358155192Srwatson	case GETPID:
359155192Srwatson		return (AUE_SEMCTL_GETPID);
360155192Srwatson
361155192Srwatson	case GETVAL:
362155192Srwatson		return (AUE_SEMCTL_GETVAL);
363155192Srwatson
364155192Srwatson	case GETZCNT:
365155192Srwatson		return (AUE_SEMCTL_GETZCNT);
366155192Srwatson
367155192Srwatson	case IPC_RMID:
368155192Srwatson		return (AUE_SEMCTL_RMID);
369155192Srwatson
370155192Srwatson	case IPC_SET:
371155192Srwatson		return (AUE_SEMCTL_SET);
372155192Srwatson
373155192Srwatson	case SETALL:
374155192Srwatson		return (AUE_SEMCTL_SETALL);
375155192Srwatson
376155192Srwatson	case SETVAL:
377155192Srwatson		return (AUE_SEMCTL_SETVAL);
378155192Srwatson
379155192Srwatson	case IPC_STAT:
380155192Srwatson		return (AUE_SEMCTL_STAT);
381155192Srwatson
382155192Srwatson	default:
383181053Srwatson		/* We will audit a bad command. */
384155192Srwatson		return (AUE_SEMCTL);
385155192Srwatson	}
386155192Srwatson}
387155192Srwatson
388155192Srwatson/*
389155192Srwatson * Convert a command for the auditon() system call to a audit event.
390155192Srwatson */
391188313Srwatsonau_event_t
392155192Srwatsonauditon_command_event(int cmd)
393155192Srwatson{
394155192Srwatson
395155192Srwatson	switch(cmd) {
396155192Srwatson	case A_GETPOLICY:
397155192Srwatson		return (AUE_AUDITON_GPOLICY);
398155192Srwatson
399155192Srwatson	case A_SETPOLICY:
400155192Srwatson		return (AUE_AUDITON_SPOLICY);
401155192Srwatson
402155192Srwatson	case A_GETKMASK:
403155192Srwatson		return (AUE_AUDITON_GETKMASK);
404155192Srwatson
405155192Srwatson	case A_SETKMASK:
406155192Srwatson		return (AUE_AUDITON_SETKMASK);
407155192Srwatson
408155192Srwatson	case A_GETQCTRL:
409155192Srwatson		return (AUE_AUDITON_GQCTRL);
410155192Srwatson
411155192Srwatson	case A_SETQCTRL:
412155192Srwatson		return (AUE_AUDITON_SQCTRL);
413155192Srwatson
414155192Srwatson	case A_GETCWD:
415155192Srwatson		return (AUE_AUDITON_GETCWD);
416155192Srwatson
417155192Srwatson	case A_GETCAR:
418155192Srwatson		return (AUE_AUDITON_GETCAR);
419155192Srwatson
420155192Srwatson	case A_GETSTAT:
421155192Srwatson		return (AUE_AUDITON_GETSTAT);
422155192Srwatson
423155192Srwatson	case A_SETSTAT:
424155192Srwatson		return (AUE_AUDITON_SETSTAT);
425155192Srwatson
426155192Srwatson	case A_SETUMASK:
427155192Srwatson		return (AUE_AUDITON_SETUMASK);
428155192Srwatson
429155192Srwatson	case A_SETSMASK:
430155192Srwatson		return (AUE_AUDITON_SETSMASK);
431155192Srwatson
432155192Srwatson	case A_GETCOND:
433155192Srwatson		return (AUE_AUDITON_GETCOND);
434155192Srwatson
435155192Srwatson	case A_SETCOND:
436155192Srwatson		return (AUE_AUDITON_SETCOND);
437155192Srwatson
438155192Srwatson	case A_GETCLASS:
439155192Srwatson		return (AUE_AUDITON_GETCLASS);
440155192Srwatson
441155192Srwatson	case A_SETCLASS:
442155192Srwatson		return (AUE_AUDITON_SETCLASS);
443155192Srwatson
444155192Srwatson	case A_GETPINFO:
445155192Srwatson	case A_SETPMASK:
446155192Srwatson	case A_SETFSIZE:
447155192Srwatson	case A_GETFSIZE:
448155192Srwatson	case A_GETPINFO_ADDR:
449155192Srwatson	case A_GETKAUDIT:
450155192Srwatson	case A_SETKAUDIT:
451155192Srwatson	default:
452155192Srwatson		return (AUE_AUDITON);	/* No special record */
453155192Srwatson	}
454155192Srwatson}
455155192Srwatson
456156889Srwatson/*
457156889Srwatson * Create a canonical path from given path by prefixing either the root
458156889Srwatson * directory, or the current working directory.  If the process working
459170196Srwatson * directory is NULL, we could use 'rootvnode' to obtain the root directory,
460156889Srwatson * but this results in a volfs name written to the audit log. So we will
461156889Srwatson * leave the filename starting with '/' in the audit log in this case.
462155192Srwatson */
463155192Srwatsonvoid
464243726Spjdaudit_canon_path(struct thread *td, int dirfd, char *path, char *cpath)
465155192Srwatson{
466181060Scsjp	struct vnode *cvnp, *rvnp;
467181060Scsjp	char *rbuf, *fbuf, *copy;
468155192Srwatson	struct filedesc *fdp;
469181060Scsjp	struct sbuf sbf;
470243745Spjd	int error, needslash;
471155192Srwatson
472181060Scsjp	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
473181060Scsjp	    __func__,  __FILE__, __LINE__);
474165621Srwatson
475181060Scsjp	copy = path;
476181060Scsjp	rvnp = cvnp = NULL;
477155192Srwatson	fdp = td->td_proc->p_fd;
478168355Srwatson	FILEDESC_SLOCK(fdp);
479181060Scsjp	/*
480181060Scsjp	 * Make sure that we handle the chroot(2) case.  If there is an
481181060Scsjp	 * alternate root directory, prepend it to the audited pathname.
482181060Scsjp	 */
483181060Scsjp	if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) {
484181060Scsjp		rvnp = fdp->fd_rdir;
485181060Scsjp		vhold(rvnp);
486155192Srwatson	}
487181060Scsjp	/*
488181060Scsjp	 * If the supplied path is relative, make sure we capture the current
489181060Scsjp	 * working directory so we can prepend it to the supplied relative
490181060Scsjp	 * path.
491181060Scsjp	 */
492181060Scsjp	if (*path != '/') {
493243726Spjd		if (dirfd == AT_FDCWD) {
494243726Spjd			cvnp = fdp->fd_cdir;
495243726Spjd			vhold(cvnp);
496243726Spjd		} else {
497243726Spjd			/* XXX: fgetvp() that vhold()s vnode instead of vref()ing it would be better */
498255240Spjd			error = fgetvp(td, dirfd, NULL, &cvnp);
499243726Spjd			if (error) {
500263960Smjg				FILEDESC_SUNLOCK(fdp);
501243726Spjd				cpath[0] = '\0';
502243726Spjd				if (rvnp != NULL)
503243726Spjd					vdrop(rvnp);
504243726Spjd				return;
505243726Spjd			}
506243726Spjd			vhold(cvnp);
507243726Spjd			vrele(cvnp);
508243726Spjd		}
509243726Spjd		needslash = (fdp->fd_rdir != cvnp);
510243726Spjd	} else {
511243726Spjd		needslash = 1;
512181060Scsjp	}
513168355Srwatson	FILEDESC_SUNLOCK(fdp);
514181060Scsjp	/*
515181060Scsjp	 * NB: We require that the supplied array be at least MAXPATHLEN bytes
516181060Scsjp	 * long.  If this is not the case, then we can run into serious trouble.
517181060Scsjp	 */
518181060Scsjp	(void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
519181060Scsjp	/*
520181060Scsjp	 * Strip leading forward slashes.
521181060Scsjp	 */
522181060Scsjp	while (*copy == '/')
523181060Scsjp		copy++;
524181060Scsjp	/*
525181060Scsjp	 * Make sure we handle chroot(2) and prepend the global path to these
526181060Scsjp	 * environments.
527181060Scsjp	 *
528181060Scsjp	 * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
529181060Scsjp	 * on Darwin.  As a result, this may need some additional attention
530181060Scsjp	 * in the future.
531181060Scsjp	 */
532181060Scsjp	if (rvnp != NULL) {
533184660Sjhb		error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf);
534181060Scsjp		vdrop(rvnp);
535181060Scsjp		if (error) {
536155192Srwatson			cpath[0] = '\0';
537181060Scsjp			if (cvnp != NULL)
538181060Scsjp				vdrop(cvnp);
539181060Scsjp			return;
540181060Scsjp		}
541181060Scsjp		(void) sbuf_cat(&sbf, rbuf);
542181060Scsjp		free(fbuf, M_TEMP);
543181060Scsjp	}
544181060Scsjp	if (cvnp != NULL) {
545184660Sjhb		error = vn_fullpath(td, cvnp, &rbuf, &fbuf);
546181060Scsjp		vdrop(cvnp);
547181060Scsjp		if (error) {
548181060Scsjp			cpath[0] = '\0';
549181060Scsjp			return;
550181060Scsjp		}
551181060Scsjp		(void) sbuf_cat(&sbf, rbuf);
552181060Scsjp		free(fbuf, M_TEMP);
553181060Scsjp	}
554243726Spjd	if (needslash)
555182090Scsjp		(void) sbuf_putc(&sbf, '/');
556181060Scsjp	/*
557181060Scsjp	 * Now that we have processed any alternate root and relative path
558181060Scsjp	 * names, add the supplied pathname.
559181060Scsjp	 */
560181060Scsjp        (void) sbuf_cat(&sbf, copy);
561181060Scsjp	/*
562181060Scsjp	 * One or more of the previous sbuf operations could have resulted in
563181060Scsjp	 * the supplied buffer being overflowed.  Check to see if this is the
564181060Scsjp	 * case.
565181060Scsjp	 */
566212425Smdf	if (sbuf_error(&sbf) != 0) {
567181060Scsjp		cpath[0] = '\0';
568181060Scsjp		return;
569181060Scsjp	}
570181060Scsjp	sbuf_finish(&sbf);
571155192Srwatson}
572