kernel space `rm -rf /` blocker
Tags: linux, kernel, development, rm
Published: 2019-12-04 11:05:28

---
title: kernel space `rm -rf /` blocker
published: true
description: how to prevent `rm -rf /` from kernel space
tags: Linux,kernel,development,rm
---

# Preface

This article introduces how to prevent `rm -rf /` disaster from kernel space. To understand this article, it's nice to have some experience of C-like programming language. If you understand what is `pointer` in C, it's better.

# Background

From the beginning of UNIX, users tend to lose their data by `rm -rf /`. To avoid this disaster, `rm` in GNU coreutils can't remove "/" without setting `--no-preserve-root` option. However, users love to add `--no-preserve-roo` to `rm` by default.

To mitigate this problem, I created a kernel patch that causes kernel panic if users try to execute `rm -rf /`.

# prepare kernel source

I confirmed that this kernel patch works correctly with Linux v5.3. The source code of this kernel can be got by the following commands.

```
$ git clone -b v5.3 --depth 1 https://github.com/torvalds/linux
...                    # Please note that it consumes several GB of storage.
$ git checkout v5.3
...
$ 
```

# Applying patch

Here is the patch, named 0001-panic-if-user-tries-to-run-rm-rf-root.patch, for my `rm -rf /` blocker feature. Its license is GPLv2.

```diff
From 27a3af9519c8b07c527bd48ef19b4baf9f6d4a9c Mon Sep 17 00:00:00 2001
From: Satoru Takeuchi <satoru.takeuchi@gmail.com>
Date: Sun, 6 Oct 2019 15:53:34 +0000
Subject: [PATCH] panic if user tries to run rm -rf /

---
 fs/exec.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/fs/exec.c b/fs/exec.c
index f7f6a140856a..8d2c1441b64c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1816,6 +1816,43 @@ static int __do_execve_file(int fd, struct filename *filename,
        if (retval < 0)
                goto out;

+       // Panic if user tries to execute `rm -rf /`
+       if (bprm->argc >= 3) {
+               struct page *page;
+               char *kaddr;
+               char rm_rf_root_str[] = "rm\0-rf\0/";
+               char buf[sizeof(rm_rf_root_str)];
+               int bytes_to_copy;
+               unsigned long offset;
+
+               bytes_to_copy = min(sizeof(rm_rf_root_str), bprm->p % PAGE_SIZE);
+               page = get_arg_page(bprm, bprm->p, 0);
+               if (!page) {
+                       retval = -EFAULT;
+                       goto out;
+               }
+               kaddr = kmap(page);
+               offset = bprm->p % PAGE_SIZE;
+               memcpy(buf, kaddr + offset, bytes_to_copy);
+               kunmap(page);
+               put_arg_page(page);
+
+               if (bytes_to_copy < sizeof(rm_rf_root_str)) {
+                       page = get_arg_page(bprm, bprm->p + bytes_to_copy, 0);
+                       if (!page) {
+                               retval = -EFAULT;
+                               goto out;
+                       }
+                       kaddr = kmap(page);
+                       memcpy(buf + bytes_to_copy, kaddr, sizeof(rm_rf_root_str) - bytes_to_copy);
+                       kunmap(page);
+                       put_arg_page(page);
+               }
+
+               if (!memcmp(rm_rf_root_str, buf, sizeof(rm_rf_root_str)))
+                       panic("`rm -rf /` is detected");
+       }
+
        would_dump(bprm, bprm->file);

        retval = exec_binprm(bprm);
--
2.17.1
```

You can apply this patch by the following command.

```
$ git apply 0001-panic-if-user-tries-to-run-rm-rf-root.patch
```

# Build and run the custom kernel

***NOTE: Please run the custom kernel in a machine that can be broken, for example, a virtual machine that is just for this experiment. Otherwise, you might lose your data due to filesystem corruption.***

First, run the following commands.

```
$ sudo apt install kernel-package flex bison libssl-dev
...                                                 # install packages to build the Linux kernel
$ make localmodconfig
...                                                 # make a configuration file, if you are asked something, just press enter.
$ make -j$(grep -c processor /proc/cpuinfo)
...                                                 # build the custom Linux kernel
$ sudo make modules_install && make install
...                                                 # install the custom Linux kernel
$ sudo /sbin/reboot # configure GRUB to use the custom Linux kernel and reboot your system
```

Second, confirm the kernel version ends with "+" after rebooting your system. It means your system uses the custom kernel.

```
$ uname -r
5.3.0+
$ 
```

Last, please run the following command.

```
$ rm -rf /
```

If you can't access your system after that, it means the custom kernel works fine. If you run `rm -rf /` from the console that shows kernel message, you can get the following kernel panic log.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/7agrl3r8k27gjmp8cqt8.jpg)

After confirming the effect of this feature, please reboot this system, reconfigure your GRUB to boot the original kernel, and uninstall the custom kernel.

# Conclusion

The patch for this feature is not so difficult. I guess you can understand what is done in this patch to a certain degree. So, please modify this patch a bit, and implement your own feature if you like.

Enjoy kernel hacking!