Hướng Dẫn Viết System Call

Stephen oimlya.com • 14 November 2016

A while back, I wrote about writing a shell in C, a task which lets youpeek under the covers of a tool you use daily. Underneath even a simple shellare many operating system calls,like read, fork, exec, wait, write, and chdir (to name afew). Now, it’s time to continue this journey down another level, and learn justhow these system calls are implemented in Linux.

Bạn đang xem: Hướng dẫn viết system call

What is a system call?

Before we start implementing system calls, we’d better make sure we understandexactly what they are. A naive programmer—like me not that long ago—mightdefine a system điện thoại tư vấn as any function provided by the C library. But this isn’tquite true. Although many functions in the C library align nicely with systemcalls (like chdir), other ones bởi quite a bit more than simply ask theoperating system to bởi something (such as fork or fprintf). Still otherssimply provide programming functionality without using the operating system,such as qsort and strtok.

In fact, a system call has a very specific definition. It is a way of requestingthat the operating system kernel vày something on your behalf. Operations liketokenizing a string don’t require interacting with the kernel, but anythinginvolving devices, files, or processes definitely does.

System calls also behave differently under the hood than a normal function.Rather than simply jumping to some code from your program or a library, yourprogram has to lớn ask the CPU khổng lồ switch into kernel mode, and then go khổng lồ apredefined location within the kernel to lớn handle your system call. This can bedone in a few different ways, such as a processor interrupt, or specialinstructions such as syscall or sysenter. In fact, the modern way of makinga system gọi in Linux is khổng lồ let the kernel provide some code (called the VDSO)which does the right thing khổng lồ make a system call. Here’san interesting SO question on the topic.

Thankfully, all that complexity is handled for us. No matter how a system callis made, it all comes down lớn looking up the particular system điện thoại tư vấn number ina table to lớn find the correct kernel function khổng lồ call. Since all you need is atable entry và a function, it’s actually very easy khổng lồ implement your own systemcall. So let’s give it a shot!

Set up your VM

Unlike my previous articles on kernel development, implementing asystem hotline is not something you can bởi vì in a kernel module. Instead, you mustactually get a copy of the Linux source, modify it, compile it, and boot it.This is something you could do directly on your main computer (if you runLinux), but it’s probably best to lớn try this out on a virtual machine! For thisexample, we’ll be using VirtualBox, so install it if you don’t already have it.

Although you can mess around with setting up a virtual machine manually, it’smore worth your time khổng lồ simply download a pre-installed virtual machine. You candownload a premade Arch Linux machine here. In this article, I’ll beusing the 201608 CLI version for VirtualBox. Tải về and unzip it. Create a newvirtual machine in VirtualBox, và when it asks about a hard disk file, choosethe vdi tệp tin you downloaded. Create và run your virtual machine, & youshould be greeted with a CLI login screen. The root password should have beennoted on the download page (mine was osboxes.org).

Note: if you have a multicore machine, it would be a good idea to lớn edit your VMsettings lớn allow it lớn use more than one core. This will dramatically improveyour compile times, so long as you substitute make -jN for make in all following commands, where N is the number of cores you giveyour VM access to.

The first preparation step you should take is lớn install bc, a build-timedependency of Linux that isn’t included in the virtual machine. Unfortunately,this will require that you update the virtual machine first. Chú ý that everycommand I give in this article should be run as root, which shouldn’t be hard,because the only user on your VM is, in fact, root.


You have to reboot because the kernel will almost certainly be updated, và wewant lớn make sure we’re running the kernel we have installed before continuingwith the rest of this process.

Acquire Source Code

After you have your development virtual machine, the next step is to lớn downloadthe kernel source code. Although most developers reflexively reach for Git whenthey need to lớn get code, this is probably not the time for that! The Linux Gitrepository is very large, và so cloning it will almost certainly not beworthwhile. Instead, you should tải về the source tarball associated with yourkernel version. You can check your version with uname -r, và then pick adownload at kernel.org that is as close khổng lồ your kernel version aspossible. Within your virtual machine, download the source using curl, e.g.:


# -O -J will set the output filename based on the URL$ curl -O -J https://www.kernel.org/pub/linux/kernel/v4.x/linux-VERSION.tar.xz
To ensure that you have values for all configuration variables, run makeoldconfig. More than likely, this will not ask you any configuration questions.

The only configuration thành phầm that you ought to modify is the kernel name, toensure that it doesn’t conflict with your currently installed one. On ArchLinux, the kernel is built with the suffix -ARCH. You should change thissuffix to lớn something chất lượng to you: I used -stephen. To bởi this, the simplestway is to mở cửa .config with a text editor, and modify this line directly.You’ll find it just under the “General setup” heading, not too far down thefile:


Add Your System Call

Now that the kernel is configured, you could start compiling it right away.However, creating a system hotline requires editing a table that is included by atruly huge amount of code. Since compiling takes a rather long time, you’ll endup wasting a lot of time if you compile right now. So let’s get on lớn the goodstuff: writing your system call!

Some of Linux’s code is architecture-specific, such as the code that initiallyhandles interrupts & system calls. Thus, the tables of system calls areactually located in directories specific lớn your processor. We’ll just vị thisfor x86_64.

System điện thoại tư vấn table

The file containing the system gọi table for x86_64 is located inarch/x86/entry/syscalls/syscall_64.tbl. This table is read by scripts and usedto generate some of the boilerplate code, which makes our lives a lot easier! Goto the bottom of the first group (it ends at syscall 328 in version 4.7.1), andadd the following line:


Notice that there is a tab between each column (not a space). The first columnis the system hotline number. I chose the next available number in the table, whichin this case was 329. You should also choose the next available number, whichmay not be 329! The second column says that this system gọi is common lớn both32-bit và 64-bit CPUs. The third column is the name of the system call, & thefourth is the name of the function implementing it. By convention this is simplythe syscall name, prefixed by sys_. I used stephen for my system hotline name,but you can use whatever you’d like.

System hotline function

The last step is to write the function for the system call! We haven’t reallygone into what the system hotline should do, but really all we would lượt thích is khổng lồ dosomething simple that we can observe. An easy thing to bởi is write to lớn the kernellog using printk(). So, our system call will take one argument, a string, andit will write it to the kernel log.

Xem thêm: Dịch Vụ Triệt Lông Vĩnh Viễn Tại Tphcm, 11+ Địa Chỉ Triệt Lông Vĩnh Viễn Uy Tín Tại Tphcm

You can implement system calls anywhere, but miscellaneous syscalls tend lớn goin the kernel/sys.c file. Put this somewhere in the file:


SYSCALL_DEFINE1(stephen, char *, msg)
SYSCALL_DEFINEN is a family of macros that make it easy lớn define a systemcall with N arguments. The first argument khổng lồ the macro is the name of the systemcall (without sys_ prepended lớn it). The remaining arguments are pairs of typeand name for the parameters. Since our system điện thoại tư vấn has one argument, we useSYSCALL_DEFINE1, và our only parameter is a char * which we name msg.

An interesting issue that we encounter immediately is that we cannot directlyuse the msg pointer provided to lớn us. There are several reasons why this is thecase, but none are very obvious!

The process could try to lớn trick us into printing out data from kernel memory bygiving us a pointer that maps to lớn kernel space. This should not be allowed. The process could try lớn read another process’s memory by giving a pointerthat maps into another process’s address space. We also need to lớn respect the read/write/execute permissions of memory.

To handle these issues, we use a handy strncpy_from_user() functionwhich behaves like normal strncpy, but checks the user-space memory addressfirst. If the string was too long or if there was a problem copying, we returnEFAULT (although returning EINVAL for a too-long string might be better).

Finally, we use printk with the KERN_INFO log level. This is actually amacro that resolves to lớn a string literal. The compiler concatenates that with theformat string & printk() uses it to determine the log level. Finally,printk does formatting similar khổng lồ printf(), which is where the %s comesin.

Compile & boot the kernel

Note: the steps here get a bit complicated. Read this section but you don’tneed to run the commands yet. At the kết thúc I’ll give a nice bash script that youcan run to bởi vì all of this.

Our first step is to lớn compile the kernel và its modules. The main kernel imageis compiled by running make. You can find the result in the filearch/x86_64/boot/bzImage. The kernel modules that go along with this versionare compiled và copied into /lib/modules/KERNEL_VERSION when you run makemodules_install. For instance, with the configuration I have created thus farin this article, the modules would be compiled & placed in/lib/modules/linux-4.7.1-stephen/.

After you have compiled the kernel & its modules, you’ll need to vì a few morethings in order to get it to boot. First, you’ll have khổng lồ copy the compiledkernel image into your /boot directory:


Next, for reasons that aren’t really important to lớn us, you need to lớn create an“initramfs”. We can vì this with two steps. First, by creating a preset based onyour old one:


#!/usr/bin/bash# Compile và "deploy" a new custom kernel from source on Arch Linux# Change this if you"d like. It has no relation# khổng lồ the suffix set in the kernel config.SUFFIX="-stephen"# This causes the script to lớn exit if an error occursset -e# Compile the kernelmake# Compile & install modulesmake modules_install# Install kernel imagecp arch/x86_64/boot/bzImage /boot/vmlinuz-linux$SUFFIX# Create preset & build initramfssed s/linux/linux$SUFFIX/g >/etc/mkinitcpio.d/linux$SUFFIX.presetmkinitcpio -p linux$SUFFIX# Update bootloader entries with new kernels.grub-mkconfig -o /boot/grub/grub.cfg
Save this as deploy.sh in the main directory of your kernel source, mix itsexecute permission with chmod u+x deploy.sh, and from now on you can build anddeploy your kernel by running that single script and rebooting. The compile maytake a while.

Once the script completes, run reboot. When GRUB pops up, select “AdvancedOptions for Arch Linux”. This should bring you a thực đơn listing the availablekernels. Select your custom one to boot it. You can always go back khổng lồ theoriginal if something horrible happens.

If all goes well, you should be greeted with login screen roughly lượt thích this:

*

The text 4.7.1-stephen is the kernel version, so it is plain lớn see that weare running my modified kernel version. If for some reason you can’t see akernel version on boot, you can always check uname -r.

Testing Your Syscall

So far, you have compiled & booted a kernel which has your own custommodifications made to lớn it. Take a moment to congratulate yourself! This issomething that not very many people have done. However, the most exciting partof the whole affair is getting to run your system call. So how exactly vị we dothat?

The C library wraps most system calls for us, so we never have to lớn think ofactually triggering an interrupt. For the system calls we don’t have available,the GNU C library provides the syscall() function for us, which can gọi anysystem điện thoại tư vấn by number. Here is a tiny little program that uses this to hotline oursystem call:


/* * test the stephen syscall (#329) */#define _GNU_SOURCE#include #include #include /* * Put your syscall number here. */#define SYS_stephen 329int main(int argc, char **argv) if (argc 1) printf("Must provide a string to lớn give lớn system call. "); return -1; char *arg = argv<1>; printf("Making system call with "%s". ", arg); long res = syscall(SYS_stephen, arg); printf("System call returned %ld. ", res); return res;
Put this in a file named test.c, & compile it with gcc -o test test.c.From there, you can run something lượt thích this for your first “hello world” systemcall!


To see the log entries generated here, just use the dmesg command. Sincedmesg dumps a ton of information onto your terminal, you may want lớn usedmesg | tail to get the last few lines of the log. You should see your systemcall’s text in the log! Here’s how it looks on my machine:

*

Wrap Up

Congratulations! You’ve implemented & tested your own system call! From here,the whole world of kernel development is open to you. You can change what yoursystem hotline does và then rebuild everything with that handy deploy script. Oryou could find another system call & edit what it does, leading to lớn some(potentially) horrific results! You can always reboot with your old kernel tosave your butt.

I really hope that some people follow this tutorial all the way through và gettheir own custom kernels và system calls up & running. Please drop me a linein the comments if you do!

Please keep in mind that I’m not a kernel expert, & nothing I say here isguaranteed to lớn be the best way to do something. For instance, you can save a lotof time if you’re doing serious development by using qemu instead of VirtualBox.

Finally, if you liked this article, you may want to kiểm tra out my previous twokernel development episodes: Episode 1, Episode 2. They’re allabout how lớn make the kernel fail in interesting ways.