A Guide to Kernel Exploitation Attacking the Core [Paperback]
465 pág.

A Guide to Kernel Exploitation Attacking the Core [Paperback]


DisciplinaLinux714 materiais1.845 seguidores
Pré-visualização50 páginas
slab_chunks; /* chunks (bufs) in this slab */
uint32_t slab_stuck_offset; /* unmoved buffer offset */
uint16_t slab_later_count; /* cf KMEM_CBRC_LATER */
uint16_t slab_flags; /* bits to mark the slab */
} kmem_slab_t;
Tag information is associated with each object in the slab. The structure hold-
ing the tag information is called kmem_bufctl and is meaningful primarily when
the object is free. In fact, in such cases, it is used to link the object in the free list
of available objects. In practice, each free object holds the information necessary
to locate the next free object, while the slab controlling structure, kmem_slab_t,
holds the address of the first available object in the slab. This design is immedi-
ately clear by checking the code responsible for the allocation of a new slab:
typedef struct kmem_bufctl {
struct kmem_bufctl *bc_next; /* next bufctl struct */
void *bc_addr; /* address of buffer */
struct kmem_slab *bc_slab; /* controlling slab */
} kmem_bufctl_t;
slab = vmem_alloc(vmp, slabsize, kmflag & KM_VMFLAGS);
[\u2026]
sp->slab_head = NULL;
sp->slab_base = buf = slab + color;
[\u2026]
chunks = (slabsize - sizeof (kmem_slab_t) - color) / chunksize;
[\u2026]
while (chunks-- != 0) {
if (cache_flags & KMF_HASH) {
[\u2026]
} else {
bcp = KMEM_BUFCTL(cp, buf);
Practical UNIX Exploitation 141
}
[\u2026]
bcp->bc_next = sp->slab_head;
sp->slab_head = bcp;
buf += chunksize;
}
In the code, bcp is of type kmem_bufctl_t, while sp is of type kmem_slab_t.
KMEM_BUFCTL is a macro for retrieving the kmem_bufctl_t associated with a buffer.
As shown at the end of the code, objects are linked in reverse order, from the
object that is closer to the end of the slab back to the first object in the slab, and
that at the end of the loop, slab_head points to the last buffer in the slab.
Given this premise, we would expect slab allocation to simply work by:
\u2022 Getting the pointer to the first free object from kmem_slab_t->slab_head
\u2022 Taking this object out from the free list
\u2022 Reading the address of the next free object from kmem_bufctl_t->bc_next
\u2022 Updating kmem_slab_t->slab_head with the address of the next free object
We would also expect the path to free an object to basically be the reverse
operation: place the object in the free list, update its kmem_bufctl_t->bc_next
with the value of kmem_slab_t->slab_head, and update that with the address of
the freshly freed object. This would also lead to the LIFO property for allocations
(the last freed object is the first one returned on a subsequent allocation), which
we said in Chapter 3 is typical for slab allocators.
Although our hypothesis is fundamentally correct, the OpenSolaris slab alloca-
tor is slightly more complicated than this. Magazines and per-CPU caches are in
fact used to improve the scalability of the allocator. The design and implementa-
tion of magazines and per-CPU caches is extensively described in another
Bonwick paper, \u201cMagazines and Vmem: Extending the Slab Allocator to Many
CPUs and Arbitrary Resources,\u201d so once again, here we will just briefly sum-
marize the concepts relevant to our exploitation aims. Figure 4.2, inspired by
Bonwick\u2019s paper, shows a global picture of the slab allocator.
To better understand Figure 4.2, we need to define what a magazine is.
A magazine is simply a collection of pointers to objects with a counter that keeps
track of how many of those are allocated. An allocation from the magazine returns
the first available free object and marks its slot as empty, while a free to the
magazine places the freed object in the first empty slot. In other words, a maga-
zine behaves like a stack of objects, which means that once again the LIFO
property of the allocator is maintained.
As we can see from Figure 4.2, the slab allocator is composed of various
layers, which are sequentially evaluated during either the object allocation or the
free path. The CPU layer acts as a local cache. If possible, objects are exchanged
back and forth from the magazines associated with each CPU. Since these maga-
zines are private to each CPU, no locking or synchronization is required and each
operation can be run in parallel on different CPUs. Eventually, though, the
142 CHAPTER 4 The UNIX Family
allocator will reach a state where the CPU layer cannot fulfill a kernel path
request. The allocator then turns to the Depot layer to retrieve either a full maga-
zine (if an allocation is requested) or an empty magazine (if a free magazine is
requested).Z
The Depot layer is basically a reserve of the full and empty magazines, but is
obviously not infinite. If a new object needs to be allocated, but no full maga-
zines exist, the allocation is pushed down to and satisfied by the Slab layer. The
same principle applies to the free path, with the difference that, if possible,
M
ag
az
in
e 
la
ye
r 
(co
ns
tru
cte
d)
Sl
ab
 la
ye
r 
(un
co
ns
tru
cte
d)
CP
U 
la
ye
r
D
ep
ot
cache_cpu (0)
Full
magazines
cache_cpu (1)
Loaded
(4 round)
cache_cpu (NCPU-1)
Previous
(full)
Loaded
(5 round)
Previous
(empty)
Loaded
(3 round)
Previous
(full)
Empty
magazines
Slab list
bufctl
One or more pages from cache\u2019s vmem source
Vmem Arena
bufctl bufctl
Slab
Color Buffer BufferBuffer
FIGURE 4.2
The OpenSolaris slab allocator.
ZThe \u201cprevious\u201d magazine at the CPU layer is an optimization to this approach. Since it will always
be either full or empty, it is kept there and swapped with the current one in case it could fulfill the
request. The current OpenSolaris implementation keeps three magazines at the CPU layer: a full
one, an empty one, and a partially used (current) one.
Practical UNIX Exploitation 143
a new empty magazine is allocated to store the freed object. This is an important
characteristic of the slab allocator (which proves mandatory for correct exploita-
tion). Full magazines are never allocated; they just generate as a consequence of
the normal behavior of the allocator. In other words, when no full magazines are
available, the Slab layer satisfies the allocation. Figure 4.3 summarizes the two
algorithms.
A CPU, Depot, and Slab layer exists for each cache in the system. But how
many caches are there? Once again, kstat can give us the answer:
osol-box$ kstat -l -c kmem_cache -s slab_alloc
[\u2026]
unix:0:clnt_clts_endpnt_cache:slab_alloc
unix:0:cred_cache:slab_alloc
unix:0:crypto_session_cache:slab_alloc
unix:0:cyclic_id_cache:slab_alloc
unix:0:dev_info_node_cache:slab_alloc
[\u2026]
unix:0:kmem_alloc_16:slab_alloc
unix:0:kmem_alloc_160:slab_alloc
unix:0:kmem_alloc_1600:slab_alloc
unix:0:kmem_alloc_16384:slab_alloc
unix:0:kmem_alloc_192:slab_alloc
unix:0:kmem_alloc_2048:slab_alloc
unix:0:kmem_alloc_224:slab_alloc
[\u2026]
Is the CPU\u2019s
loaded magazine
 empty? 
yes
Is the CPU\u2019s
previous
magazine full?
Pop the
top object
and return it
Exchange
loaded
with previous
yes
Does the depot
have any
full magazines
Alloc:
allocate an object
from the Slab layer,
apply its constructor,
and return it
Return
previous
to depot,
move loaded
to previous,
load the
full magazine
Alloc
yes
not
not not
yes
yes
Does the depot
have any
empty magazines
Free:
apply the
object\u2019s destructor
and return it
to the Slab layer
Return
previous
to depot,
move loaded
to previous,
load the empty
magazine
Free
yes
not
Is the CPU\u2019s
loaded magazine
full?
Is the CPU\u2019s
previous magazine
empty?
Push the
object on top
and return
Exchange
loaded with
previous
FIGURE 4.3
The alloc and free algorithms.
144 CHAPTER 4 The UNIX Family
As we can see, there are several caches. The end of the reported output is
particularly interesting, since it shows the name of those so-called general-purpose
caches.