如何阻止进程写入文件

如何阻止进程写入文件

我想在 Linux 上运行命令,使其无法创建或打开任何要写入的文件。它应该仍然能够正常读取文件(因此空 chroot 不是一个选项),并且仍然能够写入已经打开的文件(尤其是 stdout)。

如果仍然可以将文件写入某些目录(即当前目录),则奖励积分。

我正在寻找一种进程本地的解决方案,即不涉及为整个系统配置 AppArmor 或 SELinux 等内容,也不涉及 root 权限。不过,它可能涉及安装它们的内核模块。

我正在研究功能,如果有创建文件的功能,这些功能会很好而且很容易。 ulimit 是另一种很方便的方法,如果它涵盖了这个用例。

答案1

创建一个空的 chroot,然后在 chroot 内将主文件系统绑定挂载为只读怎么样?

可能应该是这样的来创建只读绑定安装:

mount --bind /foo/ /path/to/chroot/
mount -o remount,ro /path/to/chroot/

您可以绑定挂载您希望监狱也具有写入权限的其他目录。如果您需要绑定挂载特殊目录(/dev/、/proc/、/sys/),请小心,按原样挂载它们可能不安全。

答案2

看来这项工作的正确工具是fseccomp基于sync-ignoringBastian Blank 的 f 代码,我想出了这个相对较小的文件,导致它的所有子文件无法打开文件进行写入:

/*
 * Copyright (C) 2013 Joachim Breitner <[email protected]>
 *
 * Based on code Copyright (C) 2013 Bastian Blank <[email protected]>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define _GNU_SOURCE 1
#include <errno.h>
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define filter_rule_add(action, syscall, count, ...) \
  if (seccomp_rule_add(filter, action, syscall, count, ##__VA_ARGS__)) abort();

static int filter_init(void)
{
  scmp_filter_ctx filter;

  if (!(filter = seccomp_init(SCMP_ACT_ALLOW))) abort();
  if (seccomp_attr_set(filter, SCMP_FLTATR_CTL_NNP, 1)) abort();
  filter_rule_add(SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY));
  filter_rule_add(SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR));
  return seccomp_load(filter);
}

int main(__attribute__((unused)) int argc, char *argv[])
{
  if (argc <= 1)
  {
    fprintf(stderr, "usage: %s COMMAND [ARG]...\n", argv[0]);
    return 2;
  }

  if (filter_init())
  {
    fprintf(stderr, "%s: can't initialize seccomp filter\n", argv[0]);
    return 1;
  }

  execvp(argv[1], &argv[1]);

  if (errno == ENOENT)
  {
    fprintf(stderr, "%s: command not found: %s\n", argv[0], argv[1]);
    return 127;
  }

  fprintf(stderr, "%s: failed to execute: %s: %s\n", argv[0], argv[1], strerror(errno));
  return 1;
}

在这里可以看到仍然可以读取文件:

[jojo@kirk:1] Wed, der 06.03.2013 um 12:58 Uhr Keep Smiling :-)
> ls test
ls: cannot access test: No such file or directory
> echo foo > test
bash: test: Permission denied
> ls test
ls: cannot access test: No such file or directory
> touch test
touch: cannot touch 'test': Permission denied
> head -n 1 no-writes.c # reading still works
/*

它不会阻止删除文件、移动文件或除打开之外的其他文件操作,但可以添加这些操作。

无需编写 C 代码即可实现此目的的工具是系统调用限制器

答案3

您会考虑编写函数的替代品open(…)并使用 LD_PRELOAD 加载它吗?

答案4

以 root 身份进行一些初始设置确实是最简单的方法。具体来说,chroot 到只读绑定挂载是阻力最小的路径。

您可以使用绑定文件系统而不是mount --bind在不需要 root 的情况下创建只读视图。但是,您确实需要以 root 身份执行某些操作以防止访问其他文件,例如 chroot。

另一种方法是LD_PRELOAD一个挂钩文件打开并拒绝允许写入的库。这不需要特殊特权。从安全角度来看,这是可以绕过的,但对于您只需要包含特定功能而不是任意本机代码的用例来说这是可以的。然而,我不知道现有的库可以实现这一点。也可用于将程序限制为使用或LD_PRELOAD创建的只读视图;再说一次,我不知道现有的图书馆。mount --bindbindfs

在 Debian 及其衍生版本上,您可以设置施鲁特环境。 schroot是setuid root,需要配置为root,但可以由任何授权用户执行。

一种不需要 root 任何配合的方法是在虚拟机中运行该进程。您可以设置 KVM 或 VirtualBox,或者用户模式Linux。它有点重量级,意味着额外的内存消耗,但不会显着影响原始符号计算的速度。

如何在不成为 root 的情况下“监禁”进程?可能会提供一些启发。

相关内容