A Standalone Linux Kernel Module

栏目: IT技术 · 发布时间: 4年前

内容简介:If you’ve ever compiled a module for the Linux Kernel you’ve probably seen (or assumed there’s) quite a lot of voodoo going on between the stages of runningAs a quick reminder of the black magic involved in the process, take a look at the following simples

If you’ve ever compiled a module for the Linux Kernel you’ve probably seen (or assumed there’s) quite a lot of voodoo going on between the stages of running make and insmod .

As a quick reminder of the black magic involved in the process, take a look at the following simplest of kernel modules, and it’s appropriate makefile:

A super simple module
It takes a while to decipher what’s going on

The makefile is in itself pretty obscure, but the make command is where the real fun occur:

A Standalone Linux Kernel Module
This is just the tip of the iceberg

Right of the start we see no “standard” compilation calls, involving directories mostly untouched by the everyday user. Runing make V=1 reveals a mountain of calls, some of them to non-compilation-related binaries and scripts. What’s going on?

The .ko compilation process may seem scary and complicated, but upon simple inspection, it’s not so hard to figure out exactly what’s going on.

In this post we’ll walk through the journey of compiling a kernel module, without using any kernel headers or complicated makefiles. Our goal would be to write a short, simple, and easy to understand .c file, that when compiled with gcc and a few minimal flags, outputs a valid .ko that can be insmod ed.

This can be achieved using several different approaches:

  • Reading the documentation.
  • Inspecting the standard compilation process.
  • Looking through the kernel sources, attempting to understand what the init_module syscall does (the one responsible for loading a .ko ).

But our method of choice will be a fourth one — The Blackbox Way : Tinkering with the loader, looking at valid modules, writing invalid ones, and attempting to do whatever seems to work until we finally succeed.

IMHO, blackboxing is the most useful and effective skill to have when researching unkown or uncharetd systems, as oftentimes none of former approaches is applicable, or is probably more time-consuming and exhausting. Also, it’s the most rewarding process, as you get quick and fun payoffs along the way, with little effort.

But first, we must understand what a kernel module actually is.

What $(make)s a Kernel Module?

The .ko suffix means “ kernel object ”, hinting at what a module really is — just an ELF object file . In fact, before kernel version 2.6 , kernel modules used the .o suffix, just like standard object files.

So what distinguishes between conventional .o files and .ko ones? Let’s try to load an “empty” object file into our kernel:

Loading an “empty” object file into the kernel fails

Luckily for us, the kernel is pretty descriptive when it comes to errors regarding modules. dmesg reveals that our empty object file is missing a section called .modinfo . Let’s add it to our module!

The simplest way to do that is by creating any variable, and telling gcc to store it in a section of our choice using __attribute__((section(<name>))) . See the gcc documentation for more info on attributes.

A Standalone Linux Kernel Module
`highlight` is like `cat` but with syntax highlighting!

The error changed! Looks like we’re missing some name field in our modinfo section. To learn how to properly set that field, let’s look at a “real” kernel module, from /lib/modules/$(uname -r)/ , dumping the contents of that section using objdump -s -j .modinfo :

A Standalone Linux Kernel Module

In the muggle world, use the handy ` modinfo ` command

Looks like it’s just made up of key=value strings, separated by null bytes. So let’s add the name field and see what happens:

A Standalone Linux Kernel Module
I solemnly swear that I am up to no good

It worked! The kernel successfully identified our module’s name as standalone !

This next error seems a bit obscure. With no useful tips from the kernel, it’s time to look again at a “real” kernel module. Upon examination of its sections, using either readelf -S or objdump -h , we find another candidate with a rather suspicious name, that probably has something to do with the loading process: [.rela].gnu.linkonce.this_module .

(The .rela part is just the relocation data for the values of that section)

On my Ubuntu 18.04, this section is of size 0x380 bytes, and has 2 relocatable symbols: init_module at offset 0x178 , and cleanup_module at offset 0x330 . Dumping the contents of the section ( objdump -s ) shows that it’s mostly zeroed out, except for the module name, at offset 0x18 .

This section is actually the C struct module from the Linux Kernel sources, include/linux/module.h , embedded as a section inside the ELF. It’s usually named __this_module , and during the loading process, the kernel loader initializes the other relevant fields in the struct.

But we’re not using any kernel header files. Luckily, we have all the information we need. Let’s add some init and exit functions, and the relevant section:

almost there!
Lumos Maxima!

(We’re using __attribute__((packed)) to force the compiler to not add any extra padding between the struct’s fields, so as to force our known offsets.)

Rather bafflingly, even though insmod failed, there’s no error log in dmesg . We can verify that the module isn’t in fact loaded using lsmod | grep standalone . So what’s going on?

Usually the kernel alerts us on any missing parameters, but apparantely on some kernel configurations, sometimes no message is printed for some missing fields. Let’s look back at a real kernel module. The only major difference between our module and a real one is the fields in the .modinfo section.

This is the part where we can start to copy the remaining fields one by one until we succeed or get a different error message. However, luckily for us, an enchanted oracle whispered in our ear at night that we should start by copying the .vermagic field first!

vermagic is short for “Version Magic”, a string used by the loader to sanity check that a module was indeed compiled for that kernel release. We can extract its content from a module compiled for the kernel, or alternatively, let the kernel spit it out for us!

Makefiles and Charms are my two favorite classes in Hogwarts
A Standalone Linux Kernel Module
Thank’s for the tip!

Changing the vermagic value one last time yields:

A Standalone Linux Kernel Module
It worked!

…And we’re done! We successfully loaded a module into the kernel, compiled without using any kernel header files!

To see the final standalone.c file in it’s entirety, visit https://github.com/0xEitan/standalone-ko .

The Demystification Of Complex Systems

Many people get overwhelmed when faced with a complex and often uninviting system. Be it some collosal project they’re getting acquainted with, an unknown embedded device they want to program, or the Linux Kernel in general — it’s always intimidating diving into the deep waters.

Even though we didn’t use pure blackboxing in this post, I find methods such as the one shown, to be extremely effective in such scenarios. It may not produce successful results like in the present case, but it can certainly always reveal important insights, and help to overcome the first obstacles when facing unknown code bases.

Nothing is too complex to understand, it just takes the right tool to do it.


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

互联网+

互联网+

马化腾 / 中信出版社 / 2015-5-1 / CNY 58.00

中国进入新常态,李克强总理制定*“互联网+”行动计划以推动经济进一步发展,并认为站在“互联网+”风口顺势而为,可以使经济飞起来。 《互联网+:国家战略行动路线图》由“互联网+”理念的提出者于扬、*强有力推动者马化腾等创作。书稿从理论层面、实践经验等多个角度,结合当下各产业的现状、发展趋势,全方位进行阐述,以通俗易懂的文字将这一经济发展新引擎呈现出来,并对读者如何抓住新时期的机遇有切实的指导意......一起来看看 《互联网+》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换