* Allocate a single object of specified size with specified flags * (either M_WAITOK or M_NOWAIT). */
| 287 | * (either M_WAITOK or M_NOWAIT). |
| 288 | */ |
| 289 | void * |
| 290 | memguard_alloc(unsigned long req_size, int flags) |
| 291 | { |
| 292 | vm_offset_t addr, origaddr; |
| 293 | u_long size_p, size_v; |
| 294 | int do_guard, error, rv; |
| 295 | |
| 296 | size_p = round_page(req_size); |
| 297 | if (size_p == 0) |
| 298 | return (NULL); |
| 299 | |
| 300 | /* |
| 301 | * To ensure there are holes on both sides of the allocation, |
| 302 | * request 2 extra pages of KVA. Save the value of memguard_options |
| 303 | * so that we use a consistent value throughout this function. |
| 304 | */ |
| 305 | size_v = size_p; |
| 306 | do_guard = (memguard_options & MG_GUARD_AROUND) != 0; |
| 307 | if (do_guard) |
| 308 | size_v += 2 * PAGE_SIZE; |
| 309 | |
| 310 | /* |
| 311 | * When we pass our memory limit, reject sub-page allocations. |
| 312 | * Page-size and larger allocations will use the same amount |
| 313 | * of physical memory whether we allocate or hand off to |
| 314 | * malloc_large(), so keep those. |
| 315 | */ |
| 316 | if (vmem_size(memguard_arena, VMEM_ALLOC) >= memguard_physlimit && |
| 317 | req_size < PAGE_SIZE) { |
| 318 | addr = (vm_offset_t)NULL; |
| 319 | memguard_fail_pgs++; |
| 320 | goto out; |
| 321 | } |
| 322 | |
| 323 | /* |
| 324 | * Attempt to avoid address reuse for as long as possible, to increase |
| 325 | * the likelihood of catching a use-after-free. |
| 326 | */ |
| 327 | error = vmem_alloc(memguard_arena, size_v, M_NEXTFIT | M_NOWAIT, |
| 328 | &origaddr); |
| 329 | if (error != 0) { |
| 330 | memguard_fail_kva++; |
| 331 | addr = (vm_offset_t)NULL; |
| 332 | goto out; |
| 333 | } |
| 334 | addr = origaddr; |
| 335 | if (do_guard) |
| 336 | addr += PAGE_SIZE; |
| 337 | rv = kmem_back(kernel_object, addr, size_p, flags); |
| 338 | if (rv != KERN_SUCCESS) { |
| 339 | vmem_xfree(memguard_arena, origaddr, size_v); |
| 340 | memguard_fail_pgs++; |
| 341 | addr = (vm_offset_t)NULL; |
| 342 | goto out; |
| 343 | } |
| 344 | *v2sizep(trunc_page(addr)) = req_size; |
| 345 | *v2sizev(trunc_page(addr)) = size_v; |
| 346 | memguard_succ++; |
no test coverage detected