Kernel Hacking – use crypto API in the IRQ context

After my first post about Linux kernel crypto API, I keep playing with kernel crypto API for DSA and RSA implementations (will talk about these in my future posts). The truth is crypto API is NOT designed for IRQ context. That is the reason why if a device driver wants crypto functionalities, there are usually 2 ways for the developer to do it, either writing its own crypto stuffs, making sure it highly efficient and no sleep, or delaying the work into the bottom half, such as work queue or a kernel thread. This post dose NOT talk either of these solutions. Instead, this post discusses the general way to make crypto API work in the IRQ context. Happy hacking~

0. kmalloc

The most common way to break the kernel within an IRQ context is kmalloc with GFP_KERNEL flag, which, as you may have known already, could sleep. While sometimes it may work (like SegV may not happen each time), once there is a heavy load on the kernel, you will see kernel panic/oops frequently. The key here is to use GFP_ATOMIC flag.

1. MPI

Most crypto APIs are based on MPI ported from GnuPG. Let us do a quick search based on Linux kernel 3.18.3 under lib/mpi:

Daves-MacBook-Pro-2:mpi daveti$ pwd
/Users/daveti/linux-3.18.3/lib/mpi
Daves-MacBook-Pro-2:mpi daveti$ grep GFP *
mpicoder.c: p = buffer = kmalloc(n, GFP_KERNEL);
mpih-mul.c: ctx->next = kzalloc(sizeof *ctx, GFP_KERNEL);
mpiutil.c: a = kmalloc(sizeof *a, GFP_KERNEL);
mpiutil.c: return kmalloc(len, GFP_KERNEL);
mpiutil.c: p = kmalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL);
mpiutil.c: a->d = kzalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL);
Daves-MacBook-Pro-2:mpi daveti$

2. crypto API

Once MPI lib is patched, we need to take care of crypto API itself. If we still follow the stupid grep we have done for MPI, under crypto/, you may find there are so many places we need to change. Instead, we will be a little bit smart here – depending on the crypto API you want to use, only patch that crypto API related source. For example, we would like to use synchronous hash here, crypto_alloc_shash(). The implementation of shash is crypto/shash.c. Stupid grep works then:

Daves-MacBook-Pro-2:crypto daveti$ pwd
/Users/daveti/linux-3.18.3/crypto
Daves-MacBook-Pro-2:crypto daveti$ grep GFP shash.c
buffer = kmalloc(absize, GFP_KERNEL);
GFP_KERNEL);
Daves-MacBook-Pro-2:crypto daveti$

Are we done? Apparently not, because of the design of crypto framework, which provides the unified API (crypto API) for different crypto algorithms, we need to patch the crypto framework itself, which is crypto/api.c. Again stupid grep helps:

Daves-MacBook-Pro-2:crypto daveti$ pwd
/Users/daveti/linux-3.18.3/crypto
Daves-MacBook-Pro-2:crypto daveti$ grep GFP api.c
larval = kzalloc(sizeof(*larval), GFP_KERNEL);
tfm = kzalloc(tfm_size, GFP_KERNEL);
mem = kzalloc(total, GFP_KERNEL);
Daves-MacBook-Pro-2:crypto daveti$

3. Summary

Most of the time, these patches should make your crypto API work in the IRQ context. At least I have used it in the netfilter and USB ep0 handler. Note, if you would like to submit your code into the mainline, you probably have to follow the traditional ways.

About daveti

Interested in kernel hacking, compilers, machine learning and guitars.
This entry was posted in OS, Security and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s