프로세스가 파일을 쓰지 못하게하는 방법


13

쓸 파일을 만들거나 열 수없는 방식으로 Linux에서 명령을 실행하고 싶습니다. 여전히 파일을 정상적으로 읽을 수 있고 (빈 chroot는 옵션이 아님) 이미 열려있는 파일 (특히 stdout)에 쓸 수 있어야합니다.

특정 디렉토리 (예 : 현재 디렉토리)에 파일을 쓰는 경우 보너스 포인트가 여전히 가능합니다.

프로세스 로컬 인 솔루션을 찾고 있는데, 즉 전체 시스템에 대해 AppArmor 또는 SELinux와 같은 것을 구성하거나 루트 권한을 포함하지 않는 솔루션을 찾고 있습니다. 커널 모듈을 설치해야 할 수도 있습니다.

기능을 살펴 보았는데 파일을 만드는 기능이 있다면 훌륭하고 쉬웠을 것입니다. ulimit는이 사용 사례를 다루는 경우 편리한 다른 접근 방식입니다.


너무 많은 프로그램은 당연히 파일을 쓸 수 있다고 가정합니다 (그리고 할 수 없으면 이상한 방식으로 실패합니다). strace프로그램이 어떤 파일을 열고 있는지 알려줍니다. 왜 이러고 싶니? 특정 프로그램입니까, 아니면 테스트 또는 다른 용도로 사용 하시겠습니까? 현재 디렉토리를 제외하고 거의 모든 곳에서 쓸 수있는 권한이없는 사용자 / 그룹으로 프로그램을 실행할 수 있습니까? 최신 Linux 배포판에서는 각 사용자에 대해 그룹 개념을 사용하므로 비교적 쉽게 설정할 수 있습니다.
vonbrand

이 코드는 이미 임의의 코드 실행없이 다소 안전한 방식으로 코드를 해석하지만 코드가 임의의 위치에 파일을 작성할 수 있도록하는 특수 프로그램 (Isabelle)입니다. 코드를 신뢰할 수 없으므로 (프로그램 중단)이 발생하지 않도록하고 싶습니다. 이 프로그램은 이미 특수 사용자로 실행되지만 코드가 / tmp 또는 이와 유사한 위치를 방해하지 않으면 더 안전합니다.
Joachim Breitner

새로운 사용자를 추가하여 앱을 실행할 수 있습니다.
ctrl-alt-delor

답변:


9

빈 chroot를 만든 다음 chroot 내에서 기본 파일 시스템을 읽기 전용으로 바인드 마운트하십시오.

읽기 전용 바인드 마운트를 만들려면 아마도 다음과 같아야합니다.

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

감옥에 쓰기 권한이있는 다른 디렉토리도 바인드 마운트 할 수 있습니다. 특수 디렉토리 (/ dev /, / proc /, / sys /)를 바인드 마운트해야하는 경우주의하여 마운트하는 것이 안전하지 않을 수 있습니다.


다시, 루트 권한과 다른 "글로벌 설정"이 필요합니다. 그러나 옵션입니다.
Joachim Breitner

/foo/주요 파일 시스템의 경로는?
Wayne Conrad

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

2
github.com/certik/restrict 에는 이와 같은 것이 있지만 컴파일로 구성되어 있으며 널리 사용되지 않는 것 같습니다.
Joachim Breitner

예, 죄송합니다. 실수로 답변이 업데이트되었습니다. 그러나 나에게도 하나를 대신해야 할 것 같습니다 write(…).
Leonid

에 관해서는 github.com/certik/restrict , 그래, 당신은 완전히 맞아.
Leonid

3

가장 간단한 해결책은 관련 파일 시스템이 읽기 전용으로 마운트 된 상태에서 새 파일 시스템 네임 스페이스를 만든 다음 제한하려는 프로그램을 실행하는 래퍼 프로그램 일 것입니다.

이것은 특정 디렉토리를 서비스에 대한 읽기 전용으로 표시하는 데 systemd사용 ReadOnlyDirectories=하는 작업입니다. 새 네임 스페이스를 만드는 작업을 수행 할 수 있는 unshare명령 도 util-linux있으므로 다음과 같은 작업을 수행 할 수 있습니다.

unshare -m <wrapper>

여기서 wrapper실제 대상 프로그램을 시작하기 전에 필요에 따라 다음 바로 다시 마운트 파일 시스템에있을 것입니다.

유일한 문제는 root새로운 네임 스페이스를 만들어야 한다는 것입니다 ...


나는 이것에 대해 생각했다. 그러나 이것이 루트가 아닌 가능합니까? 사용할 수있는 준비된 스크립트 / 프로그램이 있습니까?
Joachim Breitner

1
그렇습니다. 최소한 3.7 커널에서는 루트가되어야합니다.
TomH

이 솔루션을 더 자세히보고있었습니다. 그것은 가능하다 반복적으로 바인드 마운트 / 새 / 아니지만과에 recursivley 마크 그것을 읽기 전용으로.
Joachim Breitner


2

가상 머신은 스크립트가 호스트 시스템에 영향을주지 않고 어디에서나 쓸 수 있으며 실제로 작성하려는 위치를 검사하는 것이 목표 인 것 같습니다.

예를 들어 다음과 같이 Arch Linux를 쉽게 시작할 수 있습니다.

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

1
새 시스템, 새 환경 등을 설정하지 않아도 현재 컴퓨터에서 프로그램을 실행하고 싶습니다. 가상 컴퓨터는 사용 사례에 비해 너무 무겁습니다.
Joachim Breitner

2

루트로 초기 설정을하는 것이 실제로 가장 쉬운 방법입니다. 특히, 읽기 전용 바인드 마운트의 chroot 는 가장 저항이 적은 경로입니다.

root 일 필요없이 읽기 전용보기를 작성하는 대신 bindfs 를 사용할 수 있습니다 mount --bind. 그러나 chroot와 같은 다른 파일에 액세스하지 못하게하려면 root로 무언가를 수행해야합니다.

또 다른 방법은 LD_PRELOAD파일 열기에 연결하고 쓰기를 거부하는 라이브러리에 대한 것입니다. 특별한 권한이 필요하지 않습니다. 보안 측면에서이 방법은 무시할 수 있지만 임의의 고유 코드가 아닌 특정 기능 만 포함해야하는 사용 사례에 적합합니다. 그러나 이것에 대한 기존 라이브러리는 모르겠습니다. 또는 ;로 LD_PRELOAD작성된 읽기 전용보기로 프로그램을 제한하는 데 사용될 수도 있습니다 . 다시, 나는 기존 도서관을 모른다.mount --bindbindfs

데비안 및 파생 제품에서 schroot 환경을 설정할 수 있습니다. Schroot는 setuid root이며 root로 구성해야하지만 권한이있는 모든 사용자가 실행할 수 있습니다.

루트로부터 어떠한 협력도 필요로하지 않는 방법은 가상 머신에서 프로세스를 실행하는 것입니다. KVM 또는 VirtualBox 또는 사용자 모드 Linux를 설정할 수 있습니다. 약간 무겁고 추가 메모리 소비를 의미하지만 원시 기호 계산 속도에는 큰 영향을 미치지 않습니다.

루트가 아닌 프로세스를 "감옥"하는 방법? 영감을 줄 수 있습니다.


1

프로세스가 파일을 쓰지 못하도록하는 (적어도 파일을 작성하지는 못) 방지하는 한 가지 방법은 ulimit -f 0먼저 호출하는 것 입니다. 이렇게하면 파일에 쓰려고하면 프로세스가 중단되지만 빈 파일을 만들 수는 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.