我想用overlayroot来保护一个系统,所以所做的一切 – 即使是具有root权限的用户 – 都不会在重新启动后存活下来。 我find了几个指导如何做,但没有一个告诉我它是多么安全,是否有技巧来克服保护。
我的做法:GRUB被locking,只提供没有密码的overlayroot选项。
但是,这很可能不足以保护系统,因为某人(呃,有root用户权限的人)可以dd if=/dev/zero of=/dev/sda执行dd if=/dev/zero of=/dev/sda ,我假设系统在重新启动之后拒绝启动。
根据我的研究,限制root直接访问/dev/sda , /dev/sda1等的唯一方法是SELinux。 SELinux似乎是非常复杂和完全矫枉过正,只是为了限制访问一些文件,但似乎是限制root的唯一方法。
所以我的问题是:
有没有其他的可能性,以root用户权限来克服overlayroot比访问/dev/sda(X) ?
是否有其他选项来防止访问/dev/sda(X) ,如果没有,是否有一个SELinux策略的简单示例/指南,只阻止访问某些文件?
补充2016-09-12:
我发现这个: https : //github.com/msuhanov/Linux-write-blocker/
这是一个非常小的代码(7行代码)和简单的内核补丁,使得Linux内核实际上尊重块设备的只读标志(否则该标志对于fs驱动程序来说是更多的信息)。
这是一个很好的起点,但是一个问题是:root可以很容易地改变只读标志。 我现在的想法是:
使用其他选项forcero=/dev/sda forcero=/dev/sda1引导内核
在某些情况下,这将被parsing,并且现有的块设备列表被扩展为只读标志,或者创build一个新的只读块设备列表。
该补丁的代码被扩展来检查该标志
我知道这不是完全安全的,因为一些定制的内核模块可以重置该标志(除非您签署所有模块,并且只允许签名的模块)。
我从来没有写过内核代码,我遇到的第一个问题是:我无法findstruct block_device或函数bdevname 。 我用http://lxr.free-electrons.com/identfind它,但没有运气。 我的第二个想法是:如果在某个地方有一个清单,它是稳定的还是可以重新扫描设备清除它? 有一个函数name_to_dev_t将/dev/sda1这样的名字翻译成dev_ttypes,它只是一个整数,这与block_device什么关系?
有人可以给我一些提示如何编写内核补丁? 我也对其他想法仍然开放。
我扩展了之前提到的补丁,以检查由boot命令行设置的只读块设备列表。
/* * 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; }
这是扩展的原始补丁来检查这个函数的启动参数:
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; }
在do_mounts.c我添加了这个:
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));
返回1;
}
__setup(“forcero =”,readonly_bdev_setup);
/ *
*设置列表只读设备
* /
void __init setup_readonly_bdev(void)
{
int i = 0;
char * dev_name,* readonly_dev;
if(saved_readonly_dev [0]){
readonly_dev = saved_readonly_dev;
做{
dev_name = strsep(&readonly_dev,“,”);
if(dev_name){
READONLY_DEV [i] = name_to_dev_t(dev_name);
如果(READONLY_DEV [i]){
我++;
printk(KERN_NOTICE“将%s设置为只读。\ n”,dev_name);
}
其他
printk(KERN_WARNING“错误设置为只读:无法识别块设备'%s'\ n”,dev_name);
}
(dev_name);
}
}
另外在函数kernel_init_freeable的main.c中,我添加了一行来调用我的函数(该函数在init.h声明):
if(sys_access((const char __user *)ramdisk_execute_command,0)!= 0){
ramdisk_execute_command = NULL;
prepare_namespace();
}
setup_readonly_bdev();
现在你可以用命令行参数forcero=8:16,8:17来启动内核,它将阻止对这个设备的所有写操作。 /dev/sdb不起作用,内核函数无法parsingdev_t -id。 请注意,内核不知道该设备是只读的,你可以写在它上面,甚至dd也不会告诉你任何问题,但是如果你看看kern.log ,你会看到很多的I / O错误然后。 如果你删除nemo (Cinnamon的默认GUI文件pipe理器)中的只读分区上的文件,它就消失了,但是你按了F5键后又回来了。 同样重要的是:阻止/dev/sda不会自动阻止像/dev/sda1这样的设备,您必须列出所有块设备。 但是这意味着你可以保护引导扇区/分区表,而一些分区是可写的。
我非常肯定这个补丁不符合要合并的内核代码质量标准,如果有人能够清理/改进它,或告诉我该怎么做,我会非常高兴。
保护系统不受任何修改,同时允许使用完全访问的“根”看起来像是一场失败的战斗。 根本的一点是它可以做任何事情。 正如你所提到的,你可以插入任何内核代码,并因此访问任何内存位置,一切。
有两种情况:1)你想防止意外写入,2)你想防止恶意写入。 对于1,是的,像overlayfs这样的技巧已经可以防止大多数意外的写入。 对于2,运行不可信的软件作为别的东西而不是root。
然而,仍然有一个明显的方法,那就是简单地使用硬件保护(以便软件,甚至根/内核/ ..)不能写入它。 (例如从CD或只读介质运行)