Bug Summary

File:obj-scan-build/../kern/syscall_emulation.c
Location:line 404, 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()
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(task, parent)
72 task_t task, parent;
73{
74 eml_dispatch_t eml;
75
76 if (parent == TASK_NULL((task_t) 0))
77 eml = EML_DISPATCH_NULL(eml_dispatch_t)0;
78 else
79 eml = parent->eml_dispatch;
80
81 if (eml != EML_DISPATCH_NULL(eml_dispatch_t)0) {
82 simple_lock(&eml->lock);
83 eml->ref_count++;
84 simple_unlock(&eml->lock);
85 }
86 task->eml_dispatch = eml;
87}
88
89
90/*
91 * eml_task_deallocate() [Exported]
92 *
93 * Cleans up after the emulation code when a process exits.
94 */
95
96void eml_task_deallocate(task)
97 task_t task;
98{
99 eml_dispatch_t eml;
100
101 eml = task->eml_dispatch;
102 if (eml != EML_DISPATCH_NULL(eml_dispatch_t)0) {
103 int count;
104
105 simple_lock(&eml->lock);
106 count = --eml->ref_count;
107 simple_unlock(&eml->lock);
108
109 if (count == 0)
110 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))
);
111 }
112}
113
114/*
115 * task_set_emulation_vector: [Server Entry]
116 * set a list of emulated system calls for this task.
117 */
118kern_return_t
119task_set_emulation_vector_internal(task, vector_start, emulation_vector,
120 emulation_vector_count)
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);
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);
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);
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);
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);
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(task, vector_start, emulation_vector,
299 emulation_vector_count)
300 task_t task;
301 int vector_start;
302 emulation_vector_t emulation_vector;
303 unsigned int emulation_vector_count;
304{
305 kern_return_t kr;
306 vm_offset_t emul_vector_addr;
307
308 if (task == TASK_NULL((task_t) 0))
309 return EML_BAD_TASK(((((0x0)&0x3f)<<26)|(((2)&0xfff)<<14))|0x0001
)
; /* XXX sb KERN_INVALID_ARGUMENT */
310
311 /*
312 * The emulation vector is really a vm_map_copy_t.
313 */
314 kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr,
315 (vm_map_copy_t) emulation_vector);
316 if (kr != KERN_SUCCESS0)
317 return kr;
318
319 /*
320 * Do the work.
321 */
322 kr = task_set_emulation_vector_internal(
323 task,
324 vector_start,
325 (emulation_vector_t) emul_vector_addr,
326 emulation_vector_count);
327
328 /*
329 * Discard the memory
330 */
331 (void) kmem_free(ipc_kernel_map,
332 emul_vector_addr,
333 emulation_vector_count * sizeof(eml_dispatch_t));
334
335 return kr;
336}
337
338/*
339 * task_get_emulation_vector: [Server Entry]
340 *
341 * Get the list of emulated system calls for this task.
342 * List is returned out-of-line.
343 */
344kern_return_t
345task_get_emulation_vector(task, vector_start, emulation_vector,
346 emulation_vector_count)
347 task_t task;
348 int *vector_start; /* out */
349 emulation_vector_t *emulation_vector; /* out */
350 unsigned int *emulation_vector_count; /* out */
351{
352 eml_dispatch_t eml;
353 vm_size_t vector_size, size;
354 vm_offset_t addr;
355
356 if (task == TASK_NULL((task_t) 0))
1
Assuming 'task' is not equal to null
2
Taking false branch
357 return EML_BAD_TASK(((((0x0)&0x3f)<<26)|(((2)&0xfff)<<14))|0x0001
)
;
358
359 addr = 0;
3
The value 0 is assigned to 'addr'
360 size = 0;
361
362 for(;;) {
4
Loop condition is true. Entering loop body
363 vm_size_t size_needed;
364
365 task_lock(task);
366 eml = task->eml_dispatch;
367 if (eml == EML_DISPATCH_NULL(eml_dispatch_t)0) {
5
Assuming 'eml' is not equal to null
6
Taking false branch
368 task_unlock(task);
369 if (addr)
370 (void) kmem_free(ipc_kernel_map, addr, size);
371 *vector_start = 0;
372 *emulation_vector = 0;
373 *emulation_vector_count = 0;
374 return KERN_SUCCESS0;
375 }
376
377 /*
378 * Do we have the memory we need?
379 */
380 vector_size = eml->disp_count * sizeof(vm_offset_t);
381
382 size_needed = round_page(vector_size)((vm_offset_t)((((vm_offset_t)(vector_size)) + ((1 << 12
)-1)) & ~((1 << 12)-1)))
;
383 if (size_needed <= size)
7
Assuming 'size_needed' is <= 'size'
8
Taking true branch
384 break;
9
Execution continues on line 402
385
386 /*
387 * If not, unlock the task and allocate more memory.
388 */
389 task_unlock(task);
390
391 if (size != 0)
392 kmem_free(ipc_kernel_map, addr, size);
393
394 size = size_needed;
395 if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS0)
396 return KERN_RESOURCE_SHORTAGE6;
397 }
398
399 /*
400 * Copy out the dispatch addresses
401 */
402 *vector_start = eml->disp_min;
403 *emulation_vector_count = eml->disp_count;
404 memcpy((void *)addr,
10
Null pointer argument in call to memory copy function
405 eml->disp_vector,
406 vector_size);
407
408 /*
409 * Unlock the task and free any memory we did not need
410 */
411 task_unlock(task);
412
413 {
414 vm_size_t size_used, size_left;
415 vm_map_copy_t memory;
416
417 /*
418 * Free any unused memory beyond the end of the last page used
419 */
420 size_used = round_page(vector_size)((vm_offset_t)((((vm_offset_t)(vector_size)) + ((1 << 12
)-1)) & ~((1 << 12)-1)))
;
421 if (size_used != size)
422 (void) kmem_free(ipc_kernel_map,
423 addr + size_used,
424 size - size_used);
425
426 /*
427 * Zero the remainder of the page being returned.
428 */
429 size_left = size_used - vector_size;
430 if (size_left > 0)
431 memset((char *)addr + vector_size, 0, size_left);
432
433 /*
434 * Make memory into copyin form - this unwires it.
435 */
436 (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE((boolean_t) 1), &memory);
437
438 *emulation_vector = (emulation_vector_t) memory;
439 }
440
441 return KERN_SUCCESS0;
442}
443
444/*
445 * task_set_emulation: [Server Entry]
446 * set up for user space emulation of syscalls within this task.
447 */
448kern_return_t task_set_emulation(task, routine_entry_pt, routine_number)
449 task_t task;
450 vm_offset_t routine_entry_pt;
451 int routine_number;
452{
453 return task_set_emulation_vector_internal(task, routine_number,
454 &routine_entry_pt, 1);
455}