1

I would like to protect a system with overlayroot, so everything that is done - even by a user with root permission - will not survive a reboot. I found several guides how to do that, but none of them tells me how safe it is and if there are tricks to overcome the protection.

My approach: GRUB is locked and offers only the overlayroot-option without password.

But this is most likely not enough to protect the system, as someone (well, someone with root permission) could do dd if=/dev/zero of=/dev/sda and I assume the system will refuse to boot after restart.

According to my research the only way to restrict root from directly accessing /dev/sda, /dev/sda1 and so on is SELinux. SELinux seems to be horrendously complicated and complete overkill just for restricting access to a few files, but it seems the only way to restrict root.

So my questions are:

  1. Are there any other possibilities for a user with root privilege to overcome overlayroot than accessing /dev/sda(X)?

  2. Are there other options to prevent access to /dev/sda(X) and if not is there a simple example / guide for a SELinux policy that only blocks access to certain files?

Addition 2016-09-12:
I found this: https://github.com/msuhanov/Linux-write-blocker/
It is a very small (7 lines of code) and simple kernel patch that makes the Linux kernel actually respect the read-only flag of a block device (otherwise this flag is more informative for a fs driver).

This is a great starting point, but one problem: root can easily change the read-only flag. My idea now:

  1. The kernel is booted with additional options forcero=/dev/sda forcero=/dev/sda1

  2. At some point this is parsed and either a existing list of block-devices is extended with a read-only flag or a new list of read-only block-devices is created.

  3. The code from that patch is extended to check for that flag

I know this is not perfectly safe because some custom kernel module could reset that flag (except you sign all modules and allow only signed modules).

I actually never wrote kernel code, the first problem I encountered is: I was not able to find the definition of the struct block_device or of the function bdevname. I used http://lxr.free-electrons.com/ident to find it, but no luck. My second thought: If there is a list somewhere, is it stable or could a rescan for devices clear it? There is the function name_to_dev_t that translates a name like /dev/sda1 to the dev_t type, which is just an integer, how is that related to block_device?

Can somebody give me some hints how to write that kernel patch? I'm also still open for other ideas.

10
  • Put the filesystem on read-only media. Sep 11, 2016 at 0:28
  • How do I make an HDD read-only? Is there a kernel option to set a device to read-only mode? A general read-only solution (like jumper on hdd?) is not an option, it should be possible to boot without overlayroot, so that it is possible to make permanent changes.
    – Stefan
    Sep 11, 2016 at 0:39
  • Read-only media means something that is actually physically read only, such as a Blu-ray or DVD disc. If I physically have access to something that is generally writable, such as a hard drive, there is no real way to prevent writing to it. Sep 11, 2016 at 5:37
  • Read-only media is not an option, it's about protecting notebooks. For Windows there are solutions (freeware and commercial) for decades and for Linux it's not possible at all? I don't need 100% hacker-safety, but it should be that safe that it would be easier to disassemble the notebook and connect the HDD to some other device than to circumvent the software protection. The major problem is that IMHO the UNIX rights are not helpful for a single-user desktop system: The normal user can't install anything or modify minor system settings but then root can do anything, like deleting MBR.
    – Stefan
    Sep 11, 2016 at 10:53
  • 1
    Your question really is not clear on what the threat model is. You will get better advice if you can include this information. (And of course, you don't necessarily need to give anybody the root password!) Sep 11, 2016 at 11:00

2 Answers 2

0

I extended the patch mentioned before to check against a list of read-only block-devices set up by the boot command-line.

/*
 * Block write and discard commands going to a read-only device.
 * We do this because kernel drivers often lack necessary checks
 * and send write/discard commands to read-only block devices.
 */
if (unlikely((bio->bi_rw & (REQ_WRITE | REQ_WRITE_SAME | REQ_DISCARD))
        && (bdev_read_only(bio->bi_bdev) || bdev_check_readonly_boot_param(bio->bi_bdev->bd_inode->i_rdev)))) {
    pr_warn("unexpected %s command to %s blocked\n",
        (bio->bi_rw & REQ_DISCARD) ? "discard" : "write",
        bdevname(bio->bi_bdev, b));
    goto end_io;
}

This is the original patch extended to check for the boot-param with this function:

extern dev_t READONLY_DEV[]; 
static inline int bdev_check_readonly_boot_param(dev_t bd)
{
    dev_t *dev = READONLY_DEV;
    while (*dev) {
        if (*dev == bd) return 1;
        dev++;
    }
    return 0;
}

In the do_mounts.c I added this:

static char __initdata saved_readonly_dev[64];

dev_t READONLY_DEV[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

static int __init readonly_bdev_setup(char *line)
{
    strlcpy(saved_readonly_dev, line, sizeof(saved_readonly_dev));
    return 1;
}

__setup("forcero=", readonly_bdev_setup);

/*
 * Setup list with read-only devices
 */
void __init setup_readonly_bdev(void)
{
    int i = 0;
    char *dev_name, *readonly_dev;

    if (saved_readonly_dev[0]) {
        readonly_dev = saved_readonly_dev;
        do {
            dev_name = strsep(&readonly_dev, ",");
            if (dev_name) {
                READONLY_DEV[i] = name_to_dev_t(dev_name);
                if (READONLY_DEV[i]) {
                    i++;
                    printk(KERN_NOTICE "Set %s to read-only.\n",dev_name);
                }
                else
                    printk(KERN_WARNING "Error setting read-only: Could not identify block-device '%s'\n",dev_name);
            }
        } while (dev_name);
    }
}

Additionally in the main.c in the function kernel_init_freeable I added one line to call my function (the function is declared in init.h):

   if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
        ramdisk_execute_command = NULL;
        prepare_namespace();
    }

    setup_readonly_bdev();

Now you can boot the kernel with command-line argument forcero=8:16,8:17 and it will block all write calls to this devices. /dev/sdb does not work for me, the kernel function cannot resolve a dev_t-id of that. Note that the kernel does not know that the device is read-only, you can write on it and even dd will not tell you any problem, but if you look into the kern.log, you'll see lots of I/O errors then. If you delete a file on read-only-partition in nemo (the default GUI file manager of Cinnamon), it's gone, but then you press F5 and it's back. Also important: Blocking /dev/sda will not automatically block devices like /dev/sda1, you have to list all block devices. But that means you can protect the boot sector/partition table while some partitions are writeable.

This patch I'm very sure does not meet the kernel code quality standards to be merged, I'd be very happy if someone could clean it up/improve it or tell me what I should do.

0

Protecting a system from any modification while at the same time allowing the "root" using full access seems like a lost battle. The whole point of root is that it can do anything. As you mention, you can insert any kernel code, and hence access any memory location, .. everything.

There are two scenario's: 1) You want to protect against accidental writes, and 2) you want to protect against malicious writes. For 1, yes, a trick like overlayfs can already protect against most accidental writes. For 2, run your untrusted software as something else than root..

There is however an obvious way to do it still, and that is to simply use hardware protection (so that the software, even root/kernel/..) cannot write to it. (e.g. run from a CD, or read-only medium)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .