プロセスがファイルへの書き込みを停止する方法

プロセスがファイルへの書き込みを停止する方法

書き込み用のファイルを作成または開くことができないように、Linuxでコマンドを実行したいと思います。それでもファイルを正常に読み取ることができなければならず(したがって、空のchrootはオプションではありません)、すでに開いているファイル(特にstdout)に書き込むことができるはずです。

ファイルを一部のディレクトリ(現在のディレクトリなど)に書き込むことができれば、ボーナスポイントになります。

私は、システム全体のAppArmorやSELinuxなどの設定を含まず、root権限も含まないプロセスローカルソリューションを探しています。ただし、カーネルモジュールのインストールが必要な場合があります。

ファイルを作成する機能がある場合は、本当に快適で良いような機能を探しています。 ulimitは、このユースケースに対処するためのもう1つの便利な方法です。

答え1

空のchrootを作成し、chroot内で読み取り専用でデフォルトのファイルシステムをバインドマウントするのはどうですか?

おそらく読み取り専用のバインドマウントを作成するには、次のようにする必要があります。

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

刑務所に書き込みアクセス権を付与したい他のディレクトリをバインドマウントできます。マウント特殊ディレクトリ(/dev/、/proc/、/sys/)をバインドする必要がある場合は、そのディレクトリをそのままマウントすることは安全ではない可能性があるため、注意してください。

答え2

仕事に適したツールはBastian Blankのfコードfseccompに基づいているようですsync-ignoring。比較的小さなファイルについてこれを思いついたので、すべてのサブファイルが書き込み用にファイルを開くことができなくなりました。

/*
 * 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

関数の代替関数を作成し、LD_PRELOADを使用してロードすることを検討してくださいopen(…)

答え4

rootで初期設定を行うのが実際に最も簡単な方法です。具体的には、読み取り専用バインドマウント用のchroot抵抗が最も少ない長さだ。

あなたはそれを使用することができますファイルシステムバインディングmount --bindルートなしで読み取り専用ビューを作成する代わりに。ただし、chrootなどの他のファイルへのアクセスを防ぐには、rootとして操作を実行する必要があります。

別の方法はLD_PRELOADフックファイルが開き、ライブラリの書き込み権限が拒否されます。これには特別な権限は必要ありません。これはセキュリティの観点からは回避できますが、任意のネイティブコードではなく特定の機能のみを含める必要があるユースケースには適しています。しかし、私はこれを達成できる既存のライブラリを知りません。また、使用または生成されたコンテンツの読み取り専用ビューにプログラムを制限するためにも使用できますLD_PRELOAD。既存のライブラリはわかりません。mount --bindbindfs

Debian とその派生物では、以下を設定できます。シュルート環境。 schrootはsetuid rootであり、rootとして設定する必要がありますが、認証されたすべてのユーザーが実行できます。

ルートの連携が不要な1つの方法は、仮想マシンでプロセスを実行することです。 KVM または VirtualBox を設定できます。ユーザーモードLinux。少し重いので余分なメモリ消費を意味しますが、生のシンボルの計算速度に大きな影響はありません。

ルートにならずにプロセスを「刑務所」にする方法は?インスピレーションを与えることもできます。

関連情報