วิธีป้องกันไม่ให้กระบวนการเขียนไฟล์


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

ดูเหมือนว่าเครื่องมือที่เหมาะสมสำหรับงานนี้fseccompขึ้นอยู่กับsync-ignoringรหัส f โดย Bastian Blank ฉันมากับไฟล์ที่ค่อนข้างเล็กซึ่งทำให้ลูก ๆ ของมันไม่สามารถเปิดไฟล์เพื่อเขียนได้:

/*
 * 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
โปรดทราบว่าวิธีการที่ปลอดภัยคือการขึ้นบัญชีขาว syscalls ไม่ใช่เพื่อขึ้นบัญชีดำ หากถูกปฏิเสธมากเกินไปผู้ช่วยเหลือที่ไม่ได้อยู่ในกล่องภายนอกสามารถนำมาใช้เพื่อช่วยเหลือโปรแกรม ด้วย LD_PRELOAD ผู้ช่วยเหลือดังกล่าวสามารถทำให้เกิดความโปร่งใสต่อโปรแกรมที่เราใช้งาน
วิ

4

คุณจะลองเขียนการแทนที่open(…)ฟังก์ชันและโหลดโดยใช้ LD_PRELOAD หรือไม่


2
คุณอาจหมายถึงopen... ดีฉันจะพิจารณาใช้โซลูชันที่มีอยู่ที่ใช้วิธีนี้ใช่
Joachim Breitner

2
มีบางอย่างเช่นนี้ที่github.com/certik/restrictแต่ถูกกำหนดค่าโดยการรวบรวมและดูเหมือนจะไม่ได้ใช้งานอย่างแพร่หลาย
Joachim Breitner

ใช่ขออภัยความผิดพลาดของฉันการอัปเดตคำตอบ… แต่สำหรับฉันแล้วคุณจะต้องแทนที่write(…)ด้วย
Leonid

สำหรับgithub.com/certik/จำกัด ใช่คุณพูดถูก
Leonid

3

ทางออกที่ง่ายที่สุดน่าจะเป็นโปรแกรม wrapper ที่สร้างเนมสเปซระบบไฟล์ใหม่พร้อมกับระบบไฟล์ที่เกี่ยวข้องซึ่งติดตั้งแบบอ่านอย่างเดียวจากนั้นเรียกใช้โปรแกรมที่คุณพยายาม จำกัด

นี่คือสิ่งที่systemdจะเกิดขึ้นเมื่อคุณใช้ReadOnlyDirectories=เพื่อทำเครื่องหมายไดเรกทอรีบางอย่างว่าเป็นแบบอ่านอย่างเดียวสำหรับบริการ นอกจากนี้ยังมีunshareคำสั่งในutil-linuxการทำงานของการสร้างเนมสเปซใหม่ดังนั้นคุณสามารถทำสิ่งต่อไปนี้:

unshare -m <wrapper>

ที่wrapperจะแล้วเพียงแค่ต้อง filesystems remount ตามที่ต้องการก่อนที่จะเริ่มโปรแกรมเป้าหมายที่แท้จริง

ปัญหาเดียวคือคุณต้องrootสร้างเนมสเปซใหม่ ...


ฉันคิดเกี่ยวกับเรื่องนี้ แต่สิ่งนี้เป็นไปได้หรือไม่ มีสคริปต์ / โปรแกรมที่พร้อมใช้งานสำหรับสิ่งนั้นหรือไม่
Joachim Breitner

1
ใช่ดูเหมือนว่าคุณจะต้องรูทอย่างน้อยกับเคอร์เนล 3.7
TomH

ฉันดูเพิ่มเติมที่โซลูชันนี้ มันเป็นไปได้ที่จะผูกติดซ้ำ / ใหม่ / แต่ไม่ใช่และrecursivleyทำเครื่องหมายว่าอ่านอย่างเดียว
Joachim Breitner

2

คุณสามารถเรียกใช้มันใน chroot ติดตั้งรุ่นพิเศษ/tmp และภายใน บางทีsystemdอาจช่วยได้และโดยเฉพาะsystemd-nspawn (1)ซึ่งดูเหมือนกับสิ่งที่คุณต้องการ


2

เครื่องเสมือนจะทำให้สคริปต์สามารถเขียนได้ทุกที่โดยไม่ส่งผลกระทบต่อระบบโฮสต์และเพื่อตรวจสอบว่าที่ใดที่พยายามจะเขียนซึ่งจริง ๆ แล้วเป็นเป้าหมาย

ตัวอย่างเช่นคุณสามารถเริ่มต้น Arch Linux ด้วย

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

1
ฉันยังต้องการเรียกใช้โปรแกรมในเครื่องปัจจุบันเพื่อหลีกเลี่ยงการตั้งค่าระบบใหม่สภาพแวดล้อมใหม่ ฯลฯ เครื่องเสมือนมีน้ำหนักมากเกินไปสำหรับกรณีการใช้งานของฉัน
Joachim Breitner

2

ทำการเซ็ตอัพเริ่มต้นเป็นรูทเป็นวิธีที่ง่ายที่สุด โดยเฉพาะอย่างยิ่งchroot ในการผูกติดอ่านอย่างเดียวเป็นเส้นทางของความต้านทานน้อยที่สุด

คุณสามารถใช้bindfsแทนmount --bindการสร้างมุมมองแบบอ่านอย่างเดียวโดยไม่จำเป็นต้องเป็นรูท อย่างไรก็ตามคุณจำเป็นต้องทำบางอย่างเป็นรูทเพื่อป้องกันการเข้าถึงไฟล์อื่นเช่น chroot

อีกวิธีคือLD_PRELOADไลบรารีที่เชื่อมต่อกับการเปิดไฟล์และปฏิเสธที่จะอนุญาตให้เขียน สิ่งนี้ไม่ต้องการสิทธิ์พิเศษ จากมุมมองด้านความปลอดภัยสิ่งนี้สามารถถูกข้ามได้ แต่มันก็โอเคสำหรับกรณีการใช้งานของคุณซึ่งคุณจะต้องมีคุณสมบัติเฉพาะและไม่ใช่รหัสเนทีฟโดยพลการ อย่างไรก็ตามฉันไม่รู้จักห้องสมุดที่มีอยู่สำหรับเรื่องนี้ LD_PRELOADนอกจากนี้ยังสามารถนำมาใช้เพื่อ จำกัด โปรแกรมที่จะอ่านอย่างเดียวมุมมองที่สร้างขึ้นด้วยmount --bindหรือbindfs; อีกครั้งฉันไม่รู้ห้องสมุดที่มีอยู่

บน Debian และอนุพันธ์คุณสามารถตั้งค่าสภาพแวดล้อมschroot Schroot เป็น setuid root และจำเป็นต้องกำหนดค่าเป็น root แต่สามารถดำเนินการได้โดยผู้ใช้ที่ได้รับอนุญาต

วิธีการที่ไม่ต้องการความร่วมมือจากรูทคือการเรียกใช้กระบวนการในเครื่องเสมือน คุณสามารถตั้งค่า KVM หรือ VirtualBox หรือโหมดผู้ใช้ลินุกซ์ มันเป็นบิตเฮฟวี่เวทและจะหมายถึงการใช้หน่วยความจำเพิ่มเติม แต่ไม่ควรส่งผลกระทบต่อความเร็วของการคำนวณสัญลักษณ์อย่างมีนัยสำคัญ

วิธีการ "คุก" กระบวนการโดยไม่ต้องรูต? อาจให้แรงบันดาลใจบางอย่าง


1

วิธีหนึ่งในการป้องกันไม่ให้กระบวนการเขียนไฟล์ (แต่ไม่ใช่จากการสร้างไฟล์) คือการโทรulimit -f 0ก่อน สิ่งนี้จะยกเลิกกระบวนการทันทีที่พยายามเขียนลงไฟล์ แต่การสร้างไฟล์เปล่ายังคงเป็นไปได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.