]>
Commit | Line | Data |
---|---|---|
b0d623f7 A |
1 | /* |
2 | * Copyright (c) 2008 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | #include <mach/mach_types.h> | |
29 | #include <mach/notify.h> | |
30 | #include <ipc/ipc_port.h> | |
31 | #include <kern/ipc_kobject.h> | |
32 | #include <kern/audit_sessionport.h> | |
6d2010ae | 33 | #include <libkern/OSAtomic.h> |
b0d623f7 A |
34 | |
35 | #if CONFIG_AUDIT | |
36 | /* | |
37 | * audit_session_mksend | |
38 | * | |
6d2010ae | 39 | * Description: Obtain a send right for given audit session. |
b0d623f7 A |
40 | * |
41 | * Parameters: *aia_p Audit session information to assosiate with | |
42 | * the new port. | |
43 | * *sessionport Pointer to the current session port. This may | |
44 | * actually be set to IPC_PORT_NULL. | |
45 | * | |
46 | * Returns: !NULL Resulting send right. | |
47 | * NULL Failed to allocate port (due to lack of memory | |
48 | * resources). | |
6d2010ae A |
49 | |
50 | * Assumptions: Caller holds a reference on the session during the call. | |
51 | * If there were no outstanding send rights against the port, | |
52 | * hold a reference on the session and arm a new no-senders | |
53 | * notification to determine when to release that reference. | |
54 | * Otherwise, by creating an additional send right, we share | |
55 | * the port's reference until all send rights go away. | |
b0d623f7 A |
56 | */ |
57 | ipc_port_t | |
58 | audit_session_mksend(struct auditinfo_addr *aia_p, ipc_port_t *sessionport) | |
59 | { | |
b0d623f7 | 60 | ipc_port_t sendport = IPC_PORT_NULL; |
6d2010ae | 61 | ipc_port_t port; |
b0d623f7 A |
62 | |
63 | /* | |
6d2010ae | 64 | * If we don't have an existing session port, then create one. |
b0d623f7 | 65 | */ |
6d2010ae A |
66 | port = *sessionport; |
67 | if (!IP_VALID(port)) { | |
68 | ipc_port_t new_port = ipc_port_alloc_kernel(); | |
69 | if (!IP_VALID(new_port)) | |
70 | return new_port; | |
71 | ipc_kobject_set(new_port, (ipc_kobject_t)aia_p, IKOT_AU_SESSIONPORT); | |
72 | if (!OSCompareAndSwapPtr(port, new_port, sessionport)) | |
73 | ipc_port_dealloc_kernel(new_port); | |
74 | port = *sessionport; | |
b0d623f7 A |
75 | } |
76 | ||
6d2010ae A |
77 | assert(ip_active(port) && IKOT_AU_SESSIONPORT == ip_kotype(port)); |
78 | sendport = ipc_port_make_send(port); | |
79 | ||
b0d623f7 | 80 | /* |
6d2010ae A |
81 | * If we don't have a no-senders notification outstanding against |
82 | * the port, take a reference on the session and request one. | |
b0d623f7 | 83 | */ |
6d2010ae A |
84 | if (IP_NULL == port->ip_nsrequest) { |
85 | ipc_port_t notifyport; | |
86 | ||
87 | audit_session_aiaref(aia_p); | |
88 | ||
6d2010ae | 89 | |
6d2010ae | 90 | ip_lock(port); |
316670eb A |
91 | /* Need a send-once right for the target of the notification */ |
92 | notifyport = ipc_port_make_sonce_locked(port); | |
93 | /* Request a no-senders notification (at the new make-send threshold) */ | |
6d2010ae A |
94 | ipc_port_nsrequest(port, port->ip_mscount, notifyport, ¬ifyport); |
95 | /* port unlocked */ | |
96 | ||
97 | if (IP_NULL != notifyport) { | |
98 | /* race requesting notification */ | |
99 | audit_session_aiaunref(aia_p); | |
100 | ipc_port_release_sonce(notifyport); | |
101 | } | |
b0d623f7 | 102 | } |
b0d623f7 A |
103 | |
104 | return (sendport); | |
105 | } | |
106 | ||
107 | ||
108 | /* | |
109 | * audit_session_porttoaia | |
110 | * | |
111 | * Description: Obtain the audit session info associated with the given port. | |
112 | ||
113 | * Parameters: port A Mach port. | |
114 | * | |
115 | * Returns: NULL The given Mach port did not reference audit | |
116 | * session info. | |
117 | * !NULL The audit session info that is associated with | |
118 | * the Mach port. | |
119 | * | |
120 | * Notes: The caller must have a reference on the sessionport. | |
121 | */ | |
122 | struct auditinfo_addr * | |
123 | audit_session_porttoaia(ipc_port_t port) | |
124 | { | |
125 | struct auditinfo_addr *aia_p = NULL; | |
126 | ||
127 | if (IP_VALID(port)) { | |
128 | ip_lock(port); | |
6d2010ae A |
129 | if (IKOT_AU_SESSIONPORT == ip_kotype(port)) { |
130 | assert(ip_active(port)); | |
b0d623f7 | 131 | aia_p = (struct auditinfo_addr *)port->ip_kobject; |
6d2010ae | 132 | } |
b0d623f7 | 133 | ip_unlock(port); |
6d2010ae | 134 | } |
b0d623f7 A |
135 | |
136 | return (aia_p); | |
137 | } | |
138 | ||
139 | ||
140 | /* | |
141 | * audit_session_nosenders | |
142 | * | |
143 | * Description: Handle a no-senders notification for a sessionport. | |
144 | * | |
145 | * Parameters: msg A Mach no-senders notification message. | |
146 | * | |
147 | * Notes: It is possible that new send rights are created after a | |
148 | * no-senders notification has been sent (i.e. via audit_session_mksend). | |
149 | * We check the port's mscount against the notification's not_count | |
150 | * to detect when this happens, and re-arm the notification in that | |
151 | * case. | |
152 | * | |
153 | * In the normal case (no new senders), we first mark the port | |
154 | * as dying by setting its object type to IKOT_NONE so that | |
155 | * audit_session_mksend will no longer use it to create | |
156 | * additional send rights. We can then safely call | |
157 | * audit_session_port_destroy with no locks. | |
158 | */ | |
159 | void | |
160 | audit_session_nosenders(mach_msg_header_t *msg) | |
161 | { | |
162 | mach_no_senders_notification_t *notification = (void *)msg; | |
163 | ipc_port_t port = notification->not_header.msgh_remote_port; | |
164 | ipc_port_t notifyport; | |
165 | struct auditinfo_addr *port_aia_p = NULL; | |
166 | ||
6d2010ae | 167 | assert(IKOT_AU_SESSIONPORT == ip_kotype(port)); |
b0d623f7 | 168 | ip_lock(port); |
6d2010ae A |
169 | assert(ip_active(port)); |
170 | port_aia_p = (struct auditinfo_addr *)port->ip_kobject; | |
171 | assert(NULL != port_aia_p); | |
172 | ||
173 | /* | |
174 | * if new send rights have been made since the last notify | |
175 | * request, re-arm the notification with the new threshold. | |
176 | */ | |
177 | if (port->ip_mscount > notification->not_count) { | |
316670eb | 178 | notifyport = ipc_port_make_sonce_locked(port); |
6d2010ae A |
179 | ipc_port_nsrequest(port, port->ip_mscount, notifyport, ¬ifyport); |
180 | /* port unlocked */ | |
181 | ||
182 | if (IP_NULL != notifyport) { | |
183 | /* race re-arming the notification */ | |
184 | ipc_port_release_sonce(notifyport); | |
185 | audit_session_aiaunref(port_aia_p); | |
b0d623f7 | 186 | } |
6d2010ae | 187 | return; |
b0d623f7 | 188 | } |
6d2010ae A |
189 | |
190 | /* | |
191 | * Otherwise, no more extant send rights, so release the | |
192 | * reference held on the session by those send rights. | |
193 | */ | |
b0d623f7 | 194 | ip_unlock(port); |
6d2010ae A |
195 | audit_session_aiaunref(port_aia_p); |
196 | } | |
197 | ||
198 | void | |
199 | audit_session_portdestroy(ipc_port_t *sessionport) | |
200 | { | |
201 | ipc_port_t port = *sessionport; | |
202 | ||
203 | if (IP_VALID(port)) { | |
204 | assert (ip_active(port)); | |
205 | assert(IKOT_AU_SESSIONPORT == ip_kotype(port)); | |
206 | ipc_kobject_set_atomically(port, IKO_NULL, IKOT_NONE); | |
207 | ipc_port_dealloc_kernel(port); | |
208 | *sessionport = IP_NULL; | |
209 | } | |
b0d623f7 A |
210 | } |
211 | #endif /* CONFIG_AUDIT */ |