Linux

如何防止程序寫入文件

  • May 3, 2017

我想以無法創建或打開任何要寫入的文件的方式在 Linux 上執行命令。它應該仍然能夠正常讀取文件(因此不能選擇空的 chroot),並且仍然能夠寫入已經打開的文件(尤其是標準輸出)。

如果仍然可以將文件寫入某些目錄(即目前目錄),則可以加分。

我正在尋找一種本地程序的解決方案,即不涉及為整個系統配置 AppArmor 或 SELinux 之類的東西,也不涉及 root 權限。不過,它可能涉及安裝他們的核心模組。

我正在研究功能,如果有創建文件的功能,這些功能會很簡單。ulimit 是另一種方便的方法,如果它涵蓋了這個案例。

看來這項工作的正確工具是fseccomp基於sync-ignoringBastian Blank 的 f 程式碼,我想出了這個相對較小的文件,導致它的所有子文件都無法打開文件進行寫入:

/*
* Copyright (C) 2013 Joachim Breitner <mail@joachim-breitner.de>
*
* Based on code Copyright (C) 2013 Bastian Blank <waldi@debian.org>
*
* 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 程式碼即可啟用此功能的工具是syscall_limiter

創建一個空的 chroot,然後將主文件系統綁定掛載為 chroot 內的只讀文件怎麼樣?

可能應該是這樣來創建只讀綁定掛載:

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

您也可以綁定掛載您希望監獄具有寫入權限的其他目錄。如果您需要綁定掛載特殊目錄(/dev/、/proc/、/sys/),請小心,按原樣掛載它們可能不安全。

引用自:https://unix.stackexchange.com/questions/64642