Bug Summary

File:obj-scan-build/../kern/syscall_emulation.c
Location:line 402, column 2
Description:Null pointer argument in call to memory copy function

Annotated Source Code

1/*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26
27#include <string.h>
28
29#include <mach/error.h>
30#include <mach/vm_param.h>
31#include <kern/syscall_emulation.h>
32#include <kern/task.h>
33#include <kern/kalloc.h>
34#include <vm/vm_kern.h>
35
36/* XXX */
37#define syscall_emulation_sync(task)
38
39
40
41/*
42 * WARNING:
43 * This code knows that kalloc() allocates memory most efficiently
44 * in sizes that are powers of 2, and asks for those sizes.
45 */
46
47/*
48 * Go from number of entries to size of struct eml_dispatch and back.
49 */
50#define base_size(sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) (sizeof(struct eml_dispatch) - sizeof(eml_routine_t))
51#define count_to_size(count)((sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) + sizeof
(vm_offset_t) * (count))
\
52 (base_size(sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) + sizeof(vm_offset_t) * (count))
53
54#define size_to_count(size)( ((size) - (sizeof(struct eml_dispatch) - sizeof(eml_routine_t
))) / sizeof(vm_offset_t) )
\
55 ( ((size) - base_size(sizeof(struct eml_dispatch) - sizeof(eml_routine_t))) / sizeof(vm_offset_t) )
56
57/*
58 * eml_init: initialize user space emulation code
59 */
60void eml_init(void)
61{
62}
63
64/*
65 * eml_task_reference() [Exported]
66 *
67 * Bumps the reference count on the common emulation
68 * vector.
69 */
70
71void eml_task_reference(
72 task_t task,
73 task_t parent)
74{
75 eml_dispatch_t eml;
76
77 if (parent == TASK_NULL((task_t) 0))
78 eml = EML_DISPATCH_NULL(eml_dispatch_t)0;
79 else
80 eml = parent->eml_dispatch;
81
82 if (eml != EML_DISPATCH_NULL(eml_dispatch_t)0) {
83 simple_lock(&eml->lock);
84 eml->ref_count++;
85 simple_unlock(&eml->lock)((void)(&eml->lock));
86 }
87 task->eml_dispatch = eml;
88}
89
90
91/*
92 * eml_task_deallocate() [Exported]
93 *
94 * Cleans up after the emulation code when a process exits.
95 */
96
97void eml_task_deallocate(task)
98 const task_t task;
99{
100 eml_dispatch_t eml;
101
102 eml = task->eml_dispatch;
103 if (eml != EML_DISPATCH_NULL(eml_dispatch_t)0) {
104 int count;
105
106 simple_lock(&eml->lock);
107 count = --eml->ref_count;
108 simple_unlock(&eml->lock)((void)(&eml->lock));
109
110 if (count == 0)
111 kfree((vm_offset_t)eml, count_to_size(eml->disp_count)((sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) + sizeof
(vm_offset_t) * (eml->disp_count))
);
112 }
113}
114
115/*
116 * task_set_emulation_vector: [Server Entry]
117 * set a list of emulated system calls for this task.
118 */
119kern_return_t
120task_set_emulation_vector_internal(
121 task_t task,
122 int vector_start,
123 emulation_vector_t emulation_vector,
124 unsigned int emulation_vector_count)
125{
126 eml_dispatch_t cur_eml, new_eml, old_eml;
127 vm_size_t new_size;
128 int cur_start, cur_end;
129 int new_start = 0, new_end = 0;
130 int vector_end;
131
132 if (task == TASK_NULL((task_t) 0))
133 return EML_BAD_TASK(((((0x0)&0x3f)<<26)|(((2)&0xfff)<<14))|0x0001
)
;
134
135 vector_end = vector_start + emulation_vector_count;
136
137 /*
138 * We try to re-use the existing emulation vector
139 * if possible. We can reuse the vector if it
140 * is not shared with another task and if it is
141 * large enough to contain the entries we are
142 * supplying.
143 *
144 * We must grab the lock on the task to check whether
145 * there is an emulation vector.
146 * If the vector is shared or not large enough, we
147 * need to drop the lock and allocate a new emulation
148 * vector.
149 *
150 * While the lock is dropped, the emulation vector
151 * may be released by all other tasks (giving us
152 * exclusive use), or may be enlarged by another
153 * task_set_emulation_vector call. Therefore,
154 * after allocating the new emulation vector, we
155 * must grab the lock again to check whether we
156 * really need the new vector we just allocated.
157 *
158 * Since an emulation vector cannot be altered
159 * if it is in use by more than one task, the
160 * task lock is sufficient to protect the vector`s
161 * start, count, and contents. The lock in the
162 * vector protects only the reference count.
163 */
164
165 old_eml = EML_DISPATCH_NULL(eml_dispatch_t)0; /* vector to discard */
166 new_eml = EML_DISPATCH_NULL(eml_dispatch_t)0; /* new vector */
167
168 for (;;) {
169 /*
170 * Find the current emulation vector.
171 * See whether we can overwrite it.
172 */
173 task_lock(task);
174 cur_eml = task->eml_dispatch;
175 if (cur_eml != EML_DISPATCH_NULL(eml_dispatch_t)0) {
176 cur_start = cur_eml->disp_min;
177 cur_end = cur_eml->disp_count + cur_start;
178
179 simple_lock(&cur_eml->lock);
180 if (cur_eml->ref_count == 1 &&
181 cur_start <= vector_start &&
182 cur_end >= vector_end)
183 {
184 /*
185 * Can use the existing emulation vector.
186 * Discard any new one we allocated.
187 */
188 simple_unlock(&cur_eml->lock)((void)(&cur_eml->lock));
189 old_eml = new_eml;
190 break;
191 }
192
193 if (new_eml != EML_DISPATCH_NULL(eml_dispatch_t)0 &&
194 new_start <= cur_start &&
195 new_end >= cur_end)
196 {
197 /*
198 * A new vector was allocated, and it is large enough
199 * to hold all the entries from the current vector.
200 * Copy the entries to the new emulation vector,
201 * deallocate the current one, and use the new one.
202 */
203 memcpy(&new_eml->disp_vector[cur_start-new_start],
204 &cur_eml->disp_vector[0],
205 cur_eml->disp_count * sizeof(vm_offset_t));
206
207 if (--cur_eml->ref_count == 0)
208 old_eml = cur_eml; /* discard old vector */
209 simple_unlock(&cur_eml->lock)((void)(&cur_eml->lock));
210
211 task->eml_dispatch = new_eml;
212 syscall_emulation_sync(task);
213 cur_eml = new_eml;
214 break;
215 }
216 simple_unlock(&cur_eml->lock)((void)(&cur_eml->lock));
217
218 /*
219 * Need a new emulation vector.
220 * Ensure it will hold all the entries from
221 * both the old and new emulation vectors.
222 */
223 new_start = vector_start;
224 if (new_start > cur_start)
225 new_start = cur_start;
226 new_end = vector_end;
227 if (new_end < cur_end)
228 new_end = cur_end;
229 }
230 else {
231 /*
232 * There is no current emulation vector.
233 * If a new one was allocated, use it.
234 */
235 if (new_eml != EML_DISPATCH_NULL(eml_dispatch_t)0) {
236 task->eml_dispatch = new_eml;
237 cur_eml = new_eml;
238 break;
239 }
240
241 /*
242 * Compute the size needed for the new vector.
243 */
244 new_start = vector_start;
245 new_end = vector_end;
246 }
247
248 /*
249 * Have no vector (or one that is no longer large enough).
250 * Drop all the locks and allocate a new vector.
251 * Repeat the loop to check whether the old vector was
252 * changed while we didn`t hold the locks.
253 */
254
255 task_unlock(task)((void)(&(task)->lock));
256
257 if (new_eml != EML_DISPATCH_NULL(eml_dispatch_t)0)
258 kfree((vm_offset_t)new_eml, count_to_size(new_eml->disp_count)((sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) + sizeof
(vm_offset_t) * (new_eml->disp_count))
);
259
260 new_size = count_to_size(new_end - new_start)((sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) + sizeof
(vm_offset_t) * (new_end - new_start))
;
261 new_eml = (eml_dispatch_t) kalloc(new_size);
262
263 memset(new_eml, 0, new_size);
264 simple_lock_init(&new_eml->lock);
265 new_eml->ref_count = 1;
266 new_eml->disp_min = new_start;
267 new_eml->disp_count = new_end - new_start;
268
269 continue;
270 }
271
272 /*
273 * We have the emulation vector.
274 * Install the new emulation entries.
275 */
276 memcpy(&cur_eml->disp_vector[vector_start - cur_eml->disp_min],
277 &emulation_vector[0],
278 emulation_vector_count * sizeof(vm_offset_t));
279
280 task_unlock(task)((void)(&(task)->lock));
281
282 /*
283 * Discard any old emulation vector we don`t need.
284 */
285 if (old_eml)
286 kfree((vm_offset_t) old_eml, count_to_size(old_eml->disp_count)((sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) + sizeof
(vm_offset_t) * (old_eml->disp_count))
);
287
288 return KERN_SUCCESS0;
289}
290
291/*
292 * task_set_emulation_vector: [Server Entry]
293 *
294 * Set the list of emulated system calls for this task.
295 * The list is out-of-line.
296 */
297kern_return_t
298task_set_emulation_vector(
299 task_t task,
300 int vector_start,
301 emulation_vector_t emulation_vector,
302 unsigned int emulation_vector_count)
303{
304 kern_return_t kr;
305 vm_offset_t emul_vector_addr;
306
307 if (task == TASK_NULL((task_t) 0))
308 return EML_BAD_TASK(((((0x0)&0x3f)<<26)|(((2)&0xfff)<<14))|0x0001
)
; /* XXX sb KERN_INVALID_ARGUMENT */
309
310 /*
311 * The emulation vector is really a vm_map_copy_t.
312 */
313 kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr,
314 (vm_map_copy_t) emulation_vector);
315 if (kr != KERN_SUCCESS0)
316 return kr;
317
318 /*
319 * Do the work.
320 */
321 kr = task_set_emulation_vector_internal(
322 task,
323 vector_start,
324 (emulation_vector_t) emul_vector_addr,
325 emulation_vector_count);
326
327 /*
328 * Discard the memory
329 */
330 (void) kmem_free(ipc_kernel_map,
331 emul_vector_addr,
332 emulation_vector_count * sizeof(eml_dispatch_t));
333
334 return kr;
335}
336
337/*
338 * task_get_emulation_vector: [Server Entry]
339 *
340 * Get the list of emulated system calls for this task.
341 * List is returned out-of-line.
342 */
343kern_return_t
344task_get_emulation_vector(
345 task_t task,
346 int *vector_start, /* out */
347 emulation_vector_t *emulation_vector, /* out */
348 unsigned int *emulation_vector_count) /* out */
349{
350 eml_dispatch_t eml;
351 vm_size_t vector_size, size;
352 vm_offset_t addr;
353
354 if (task == TASK_NULL((task_t) 0))
1
Assuming 'task' is not equal to null
2
Taking false branch
355 return EML_BAD_TASK(((((0x0)&0x3f)<<26)|(((2)&0xfff)<<14))|0x0001
)
;
356
357 addr = 0;
3
The value 0 is assigned to 'addr'
358 size = 0;
359
360 for(;;) {
4
Loop condition is true. Entering loop body
361 vm_size_t size_needed;
362
363 task_lock(task);
364 eml = task->eml_dispatch;
365 if (eml == EML_DISPATCH_NULL(eml_dispatch_t)0) {
5
Assuming 'eml' is not equal to null
6
Taking false branch
366 task_unlock(task)((void)(&(task)->lock));
367 if (addr)
368 (void) kmem_free(ipc_kernel_map, addr, size);
369 *vector_start = 0;
370 *emulation_vector = 0;
371 *emulation_vector_count = 0;
372 return KERN_SUCCESS0;
373 }
374
375 /*
376 * Do we have the memory we need?
377 */
378 vector_size = eml->disp_count * sizeof(vm_offset_t);
379
380 size_needed = round_page(vector_size)((vm_offset_t)((((vm_offset_t)(vector_size)) + ((1 << 12
)-1)) & ~((1 << 12)-1)))
;
381 if (size_needed <= size)
7
Assuming 'size_needed' is <= 'size'
8
Taking true branch
382 break;
9
Execution continues on line 400
383
384 /*
385 * If not, unlock the task and allocate more memory.
386 */
387 task_unlock(task)((void)(&(task)->lock));
388
389 if (size != 0)
390 kmem_free(ipc_kernel_map, addr, size);
391
392 size = size_needed;
393 if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS0)
394 return KERN_RESOURCE_SHORTAGE6;
395 }
396
397 /*
398 * Copy out the dispatch addresses
399 */
400 *vector_start = eml->disp_min;
401 *emulation_vector_count = eml->disp_count;
402 memcpy((void *)addr,
10
Null pointer argument in call to memory copy function
403 eml->disp_vector,
404 vector_size);
405
406 /*
407 * Unlock the task and free any memory we did not need
408 */
409 task_unlock(task)((void)(&(task)->lock));
410
411 {
412 vm_size_t size_used, size_left;
413 vm_map_copy_t memory;
414
415 /*
416 * Free any unused memory beyond the end of the last page used
417 */
418 size_used = round_page(vector_size)((vm_offset_t)((((vm_offset_t)(vector_size)) + ((1 << 12
)-1)) & ~((1 << 12)-1)))
;
419 if (size_used != size)
420 (void) kmem_free(ipc_kernel_map,
421 addr + size_used,
422 size - size_used);
423
424 /*
425 * Zero the remainder of the page being returned.
426 */
427 size_left = size_used - vector_size;
428 if (size_left > 0)
429 memset((char *)addr + vector_size, 0, size_left);
430
431 /*
432 * Make memory into copyin form - this unwires it.
433 */
434 (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE((boolean_t) 1), &memory);
435
436 *emulation_vector = (emulation_vector_t) memory;
437 }
438
439 return KERN_SUCCESS0;
440}
441
442/*
443 * task_set_emulation: [Server Entry]
444 * set up for user space emulation of syscalls within this task.
445 */
446kern_return_t task_set_emulation(
447 task_t task,
448 vm_offset_t routine_entry_pt,
449 int routine_number)
450{
451 return task_set_emulation_vector_internal(task, routine_number,
452 &routine_entry_pt, 1);
453}