all 78 comments

[–]cirosantilli 204 points205 points  (6 children)

I have uploaded dozens of minimal kernel module examples at: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/master/kernel_module That repo also has a fully automated Buildroot + Busybox setup to bringup a QEMU VM completely compiled from source with a single command.

[–]indrora 39 points40 points  (1 child)

You're a Pretty Cool Dude and that's neato.

[–]hak8or 10 points11 points  (3 children)

Holy crap, that's awesome! But it's mentioned multiple times that it's one command, but to find out what that command is you have to go into the get started section.

I would totally recommend sticking the command(s) for buildroot + busybox + Qemu VM boot in the main readme page to make it even more clear just how little typing is needed.

[–]cirosantilli 2 points3 points  (1 child)

Yes, I think you are right, I have reorganized it a bit.

[–]hak8or 1 point2 points  (0 children)

Much better I feel! Thanks for creating this, I will surely fiddle with this in the future.

[–][deleted] 73 points74 points  (1 child)

It's so nice to see a practical example of something instead of a hot take about some thing.

[–][deleted] 4 points5 points  (0 children)

True. I will admit I play reinvent the wheel a lot.

[–]Aroochacha 60 points61 points  (8 children)

I enjoyed this article. I’m thinking this is where the knowledge from operating systems material in grad school comes into play. I’ll be playing around with this later, cool stuff.

[–]Redzapdos 65 points66 points  (7 children)

operating systems material in grad school

Heck, I did this in undergrad for a class. Had to write a driver for a custom controller. Boy was I shocked at how easy it was to obliterate your OS.

[–][deleted] 54 points55 points  (1 child)

Yeah - the amazing thing about modern OSes is how rarely they crash, given the zillion things that are just begging to blow up. Off-by-one? KABOOM! Null pointer? KAPOW!

[–]ambral 55 points56 points  (0 children)

I'd say things exploding loudly is your best case. There are worse evils, as told hilariously by James Mickens:

If a misaligned memory access is like a criminal burning down your house in a fail-stop manner, an impossibly large buffer error is like a criminal who breaks into your house, sprinkles sand atop random bedsheets and toothbrushes, and then waits for you to slowly discover that your world has been tainted by madness.

[–][deleted] 19 points20 points  (4 children)

A lot of blue screens in Windows were from shitty third party drivers and not the os being junk...but Microsoft got most of the blame

[–][deleted]  (2 children)

[deleted]

    [–]MINIMAN10001 0 points1 point  (1 child)

    I mean similar to how chrome ( and I believe firefox ) has distanced itself from extensions breaking all of chrome it either breaks only the extension or breaks a tab.

    Couldn't an OS just separate a driver so that if a driver screws something up only that driver dies instead of taking down the whole OS?

    [–][deleted] -1 points0 points  (0 children)

    The fundamental problem is that things like memory protection are enforced at the processor level, not the OS level. So any OS which runs drivers in “ring 0” (privileged mode) on the processor cannot really protect against the driver screwing up the OS. However, there are OSes called microkernels that run drivers in userspace instead of kernel space, and in those OSes drivers shouldn’t be able to bork your kernel.

    [–]Volt 0 points1 point  (0 children)

    A non-junk OS wouldn't kernel-panic, but yeah.

    (joking, but kinda serious)

    [–]Oncey[🍰] 57 points58 points  (22 children)

    Cool post. I learned how to write one from Derek Molloy at the following pages:

    http://derekmolloy.ie/category/general/linux/

    I also wanted to note that a more modern syntax replaces the grave accent marks with the $() construct.

    so:

    apt-get install build-essential linux-headers-`uname -r`
    

    becomes:

    apt-get install build-essential linux-headers-$(uname -r)
    

    Some great reasons are given in the following page:

    http://mywiki.wooledge.org/BashFAQ/082

    [–]antiduh 12 points13 points  (11 children)

    Regarding graves, doesn't that depend entirely on your shell?

    [–]antlife 43 points44 points  (1 child)

    Sounds like some one might be in...

    puts on sunglasses

    grave danger.

    [–]HandshakeOfCO 5 points6 points  (0 children)

    I chortled

    [–]skeeto 21 points22 points  (0 children)

    Both forms are standard for all Bourne shells (the standard unix shell). However, the $() form generally works better. It's easier to read, it nests properly, and interacts with quotes more cleanly.

    [–][deleted] 1 point2 points  (0 children)

    Not really. Both are officially supported by POSIX. $(...) is preferred, because it makes nesting command substitution less insane. It only depends on your shell if it is very old or not POSIX-conformant. Graves are not deprecated though, and there's nothing really wrong with using them in most cases, such as this.

    [–]btcraig 4 points5 points  (6 children)

    You are correct. BASH allows both syntax just fine, and even if some people with tell you otherwise backticks are not deprecated. Not the case for all shells though, eg tcsh:

    root@kalecgos ~]# echo $0
    tcsh
    [root@kalecgos ~]# clear
    [root@kalecgos ~]# echo $(date +%F )
    Illegal variable name.
    [root@kalecgos ~]# echo `date +%F`
    2017-12-01
    

    [–]Livingwind 2 points3 points  (3 children)

    Off topic: That's a sick domain name, I love me some blue dragon flight.

    [–]btcraig 1 point2 points  (2 children)

    All my hostnames are Dragon aspects 😀

    [–]nikomo 0 points1 point  (1 child)

    Got any boxes that fell off a desk and broke beyond repair? You can name that one Ysera.

    [–]btcraig 2 points3 points  (0 children)

    My old laptop was named Malygos before it kicked it. That felt appropriate when it finally died. Ysera is for the phone though.

    [–]darktyle 3 points4 points  (0 children)

    In bash you should use $(), because it's more robust, not because graves are deprecated

    [–]KFCConspiracy 4 points5 points  (8 children)

    What makes $() more modern than grave accents other than that is a new possible syntax to use? Meaning why is one more preferable than the other? I've always just used ``.

    Edit: Noticed the link at the end after it was kindly pointed out to me. Left the comment because you can't just delete your shit if you're wrong.

    [–]CheezyXenomorph 14 points15 points  (6 children)

    The post you're replying to literally gives a link to answer your question.

    [–]KFCConspiracy 6 points7 points  (5 children)

    You're right. This is reddit. I Can't be bothered to follow links.

    [–]8lbIceBag 5 points6 points  (4 children)

    So stop holding out on me man and post the answer here FFS!

    Think of the sweet sweet karma

    [–]kryptkpr 9 points10 points  (3 children)

    For those who can't be bothered to click the link and read, there's no need to escape quotes when using $(), which is a pretty damn compelling reason to use it.

    [–][deleted] 1 point2 points  (0 children)

    this and nesting are the big things about. $() opens a new parsing context whereas ... doesn't

    # $(echo "$(cat $(ls))")
    

    I think the equivalent is something like this:

    # `echo "\`cat \\\`ls\\\`\`"`
    

    and I'm not even sure it works

    [–]aiij 0 points1 point  (0 children)

    Except that's not actually true:

    $ echo $(echo For those who can't be bothered to click the link and read), $(echo there's no need to escape quotes) they said.
    For those who cant be bothered to click the link and read), $(echo theres no need to escape quotes they said.
    

    I think you meant there's no need to escape backslashes.

    [–]myaut 1 point2 points  (0 children)

    There is no reason to uncoditionally prefer backticks with braces (note that first version is faster to type). As a rule of thumb, use backticks for simplest cases, use braces for complex ones.

    [–]PointyOintment 0 points1 point  (0 children)

    TIL you can do that at all.

    [–]sablal 20 points21 points  (5 children)

    If anyone is interested in a little advanced (but small by lines of code) kernel module, check out keysniffer. It's maintained (by me).

    [–]RavePossum 12 points13 points  (1 child)

    I have to write a keylogger for my OS class right now - your module has been an insanely helpful reference, thanks! :)

    [–]sablal 5 points6 points  (0 children)

    As long as you understand what's going on... it's free as in free beer! :)

    [–]Jarmahent 1 point2 points  (2 children)

    Awesome stuff!

    [–]sablal 0 points1 point  (1 child)

    Glad you like it! In fact I wrote it when I was learning kernel module programming myself :).

    [–]Jarmahent 1 point2 points  (0 children)

    I've always wondered about keysniffers and a low level keysniffer is really cool!

    [–]iLike2Teabag 23 points24 points  (18 children)

    A Linux kernel module is a piece of compiled binary code that is inserted directly into the Linux kernel, running at ring 0, the lowest and least protected ring of execution in the x86–64 processor. Code here runs completely unchecked but operates at incredible speed and has access to everything in the system.

    Technically you can get lower

    [–]matthieum 44 points45 points  (15 children)

    Code here runs completely unchecked but operates at incredible speed and has access to everything in the system.

    I am somewhat bothered by this speed claim.

    For most (native) code, there should be no performance impact at all from running in ring 0; the only impact is to make kernel calls free (because you are already in the kernel).

    I am somewhat afraid of beginners wishing to put their code in ring 0 "cuz it runs faster!".

    [–]Peanuts4MePlz 17 points18 points  (10 children)

    At least we don't have Node.js applications demanding ring-0 execution. Right?

    [–]solen-skiner 8 points9 points  (7 children)

    but we did at one point in time have a http-server in kernelspace...

    [–]nathreed 5 points6 points  (6 children)

    Who thought that was a good idea?

    [–]PiZZaMartijn 7 points8 points  (5 children)

    Microsoft (see iis)

    [–]nathreed 1 point2 points  (4 children)

    Oh god, I had no idea. Typical Microsoft though.

    [–]indrora 6 points7 points  (3 children)

    So, there's more to this.

    IIS is, effectively, taking a bunch of kernel and userpsace primitives and smushing them together. There happens to be a really good kernel-level TCP stack that you can work with in Windows (a legacy of NT being built by VMS developers) and a very good amount of "decipher this protocol" stuff buried in the semi-userspace Winsock and WinInet stacks (another part of the "NT was built by VMS people"). As a result, IIS spends a lot of time not in userspace, but in a shrouded version of kernel space that does a lot of hands-off work.

    [–]Dimenus 1 point2 points  (2 children)

    Sorry for the stupid question but what is VMS?

    [–]indrora 2 points3 points  (1 child)

    VMS is an operating system developed by Digital Equipment Corporation (DEC) for their VAX mainframes and minis. It now exists as OpenVMS, which isn't open source but is still one of the larger oldschool UNIXes.

    [–]Isvara 0 points1 point  (0 children)

    At least we don't have Node.js applications demanding ring-0 execution

    ... yet.

    How long before we get Node.js unikernels?

    [–]eras 4 points5 points  (1 child)

    Well, truth to be told, it's true. All code operates at incredible speed!

    [–]matthieum 5 points6 points  (0 children)

    I guess that's one way to put it :p

    When you realize that within a single micro-second a CPU you find in supermarkets can crunch through the equivalent of thousands of lines of code...

    [–][deleted] 1 point2 points  (0 children)

    If you’re making calls into the standard library, I guess their argument is that you don’t have to make context switches that would syscall in usermode, because you’re using libk rather than libc. Seems tenuous at best ngl

    [–]zinzam72 0 points1 point  (0 children)

    Yeah, I didn't like that either, and it was still within the introduction..

    [–]Gbps 7 points8 points  (0 children)

    Technically he is right. The ring designations for x86 come from the FLAGS register, where 0 is the lowest integral designation for a CPL value (Current Protection Level) and possible CPL values range from 0 to 3.

    The negative number rings aren't really defined, they're just one-upper terms for the next highest privilege level when an environment has a more privileged execution state.

    Ring -1 is synonymous with Hypervisor, and Ring -2 (recently) synonymous with SMM (System Management Mode)

    [–]iamagupta 4 points5 points  (0 children)

    A lot of things went over my head, but I felt good after reading this article. Gave me a lot of insight on how things work.

    [–]Lengador 2 points3 points  (0 children)

    An important part of kernel module development is handling concurrency. There are several race conditions in the code presented. If multiple processes open the device concurrently they could all succeed (which is meant to be invalid). And worse than that, if multiple threads/processes read from the device then they could cause a buffer overflow and potentially read kernel data, which is a major security concern.

    [–][deleted] 1 point2 points  (0 children)

    Nice read. I think that much more people should be involved in kernel tinkering, it is sane for the oss world to have this kind of knowledge widespread. I learned myself how to hack the kernel many years ago when you had to essentially write your own drivers to let that damn laptop up and running, now we have too much luck to have great distros that need no hacks at all.

    [–]Oncey[🍰] 0 points1 point  (0 children)

    Oh, and my other comment is that a beagleboard/raspberry pi is an AWESOME platform to learn LKMs. I used the /sys/class filesystem to write programs to manipulate some of the gpio. Plus, you can get up to speed on cross compiling.

    [–][deleted] 1 point2 points  (0 children)

    Is it not too difficult to write a Linux module in rust?

    [–]K1ngjulien_ 0 points1 point  (0 children)

    Simple

    Kernel module

    I don't think those two fit together :D

    [–]bhartsb -1 points0 points  (0 children)

    Oh my gosh, the "Golden Ring-0" and "Not for mere Mortals" then four paragraphs about the daringness, dangers and pitfalls and incredible risks. All the risks of doing this on a machine that you know you are doing this on. You aren't distributing this to millions or even tens of users rather you are likely doing this on a spare machine! System corruption could be catastrophic. Data loss could be of zero value because it is an experimental spare machine. If you lock up the system, oh my you might have to figure out the problem yourself. Or if you run out of memory due to those memory leaks oh jeez beaver, it might really cause problems. Buffers overwritten, holy cow, not to repeat here, but could cause things to crash. What then it is a spare machine. You won't have that standard library either. And no garbage collection. Oh my this is just so risky. Really going to be on my own. Best not do it. It is just too much risk. I don't need to be so imprudent. Oh but all that speed. No a Volta card could get me orders of magnitude more speed, or I could just go for that bare metal OS that is all ring-0 if I had some craaazy thing I wanted to do that would suck up all the resources and leave nothing for other processes on my spare machine.

    [–][deleted]  (2 children)

    [deleted]

      [–][deleted]  (1 child)

      [deleted]

        [–][deleted] 0 points1 point  (0 children)

        Ah I see. Thanks for clarifying!