プロセスがファイルを書き込むのを防ぐ方法


13

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

特定のディレクトリ(つまり、現在のディレクトリ)へのファイルの書き込みが引き続き可能かどうかは、ボーナスポイントです。

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

私は機能を検討していましたが、ファイルを作成する機能があれば、これらは素晴らしく簡単でした。ulimitは、このユースケースをカバーしている場合に便利な別のアプローチです。


もちろん、プログラムが多すぎると、当然ファイルを書き込むことができると想定します(できない場合は、奇妙な方法で失敗します)。straceプログラムが開いているファイルを通知します。なぜこれをしたいのですか?それは特定のプログラムですか、それともこれをテストまたは他の何かに使用しますか?現在のディレクトリ以外のほぼすべての場所に書き込む権限のないユーザー/グループとしてプログラムを実行できますか?最近のLinuxディストリビューションでは、ユーザーごとにグループという概念を使用しているため、これは比較的簡単にセットアップできます。
フォンブランド2013

これは特別なプログラム(Isabelle)であり、すでにある程度安全な方法でコードを解釈します(任意のコード実行はありません)が、コードが任意の場所にファイルを作成できるようにします。コードは信頼できないので、(プログラムを中止することによって)これが起こらないようにしたいと思います。プログラムはすでに特別なユーザーとして実行されていますが、コードが/ tmpなどの場所を破壊できなかった場合は、より安全だと思います。
Joachim Breitner 2013

あなたには、アプリケーションを実行するために、新しいユーザーを追加することができます。
Ctrl + Alt + delor

回答:


9

空のchrootを作成してから、メインファイルシステムをchroot内で読み取り専用としてバインドマウントしますか?

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

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

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


繰り返しますが、root権限とその他の「グローバルセットアップ」が必要です。しかし、オプション、はい。
Joachim Breitner 2013

/foo/メインファイルシステムへのパスはありますか?
ウェインコンラッド

5

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

/*
 * 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です。


4
安全なアプローチは、システムコールをホワイトリストに登録することであり、ブラックリストに登録することではないことに注意してください。拒否が多すぎる場合は、保護されていない外部ヘルパーを使用してプログラムを支援できます。LD_PRELOADを使用すると、このようなヘルパーを実行中のプログラムに対して透過的にすることができます。
Vi。

4

open(…)関数の代替を作成し、LD_PRELOADを使用してロードすることを検討しますか?


2
たぶんopen…そうですね、このアプローチを使用する既存のソリューションを使用することを検討します。
Joachim Breitner、2013

2
github.com/certik/restrictにこのようなものがありますが、コンパイルによって構成されており、広く使用されているようには見えません。
Joachim Breitner、2013

はい、申し訳ありませんが、私の間違い、答えを更新しています…しかし、私にとっては、1つをwrite(…)同様に置き換える必要があるようです。
レオニード

github.com/certik/restrict、はい、あなたは完全に正しいです。
レオニード

3

最も簡単な解決策は、関連するファイルシステムを読み取り専用でマウントして新しいファイルシステム名前空間を作成し、制限しようとしているプログラムを実行するラッパープログラムでしょう。

systemdを使用ReadOnlyDirectories=して、特定のディレクトリをサービスの読み取り専用としてマークすると、これが行われます。新しい名前空間を作成する作業を行うことができるunshareコマンドもあるutil-linuxので、次のようなことができます:

unshare -m <wrapper>

この場合wrapper、実際のターゲットプログラムを開始する前に、必要に応じてファイルシステムを再マウントする必要があります。

唯一の問題はroot、新しい名前空間を作成する必要があることです...


私はこれについて考えました。しかし、これはrootになることなく可能ですか?そのための既製のスクリプト/プログラムはありますか?
Joachim Breitner 2013

1
はい、少なくとも3.7カーネルでは、rootになる必要があるようです。
TomH

私はこの解決策をさらに検討していました。それはすることが可能である再帰的に新しい/ではなく、およびに/バインド・マウントrecursivley読み取り専用としてマーク。
Joachim Breitner 2013


2

仮想マシンを使用すると、ホストシステムに影響を与えずにスクリプトで任意の場所に書き込むことができ、実際に書き込みを行おうとしている場所を検査することができます。

たとえば、次のコマンドでArch Linuxを簡単に起動できます。

kvm -boot d -m 512 -cdrom archlinux-*.iso

1
新しいシステムや新しい環境などをセットアップする必要がないように、現在のマシンでプログラムを実行したいのですが、仮想マシンは、私のユースケースでは重すぎます。
Joachim Breitner、2013

2

rootとしていくつかの初期設定を行うことが、本当に最も簡単な方法です。特に、読み取り専用のバインドマウントへのchrootは、最も抵抗の少ないパスです。

の代わりにbindfsを使用して、rootでなくmount --bindても読み取り専用ビューを作成できます。ただし、chrootなどの他のファイルへのアクセスを防ぐために、rootとして何かを行う必要があります。

別のアプローチは、LD_PRELOADファイルのオープンにフックし、書き込みを許可しないライブラリへのアプローチです。これには特別な権限は必要ありません。これはセキュリティの観点からは回避できますが、任意のネイティブコードではなく特定の機能のみを含める必要があるユースケースでは問題ありません。ただし、このための既存のライブラリーは知りません。またはでLD_PRELOAD作成された読み取り専用ビューにプログラムを制限するためにも使用できます。繰り返しますが、私は既存のライブラリを知りません。mount --bindbindfs

Debianおよび派生物では、schroot環境をセットアップできます。Schrootはsetuidルートであり、ルートとして構成する必要がありますが、許可されたユーザーであれば誰でも実行できます。

ルートからの協力を必要としない方法は、仮想マシンでプロセスを実行することです。KVM、VirtualBox、またはユーザーモードのLinuxをセットアップできます。これは少し重いですが、追加のメモリ消費を意味しますが、生のシンボリック計算の速度に大きな影響を与えることはありません。

ルートにならずにプロセスを「投獄」する方法は?インスピレーションを与えるかもしれません。


1

プロセスがファイルを書き込まないようにする(ただし、ファイルを作成しない)ための1つの方法は、ulimit -f 0最初にを呼び出すことです。これは、ファイルに書き込もうとするとすぐにプロセスを中止しますが、空のファイルを作成することはまだ可能です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.