Làm thế nào để ngăn chặn một quá trình viết tập tin


13

Tôi muốn chạy một lệnh trên Linux theo cách mà nó không thể tạo hoặc mở bất kỳ tệp nào để ghi. Nó vẫn có thể đọc các tệp như bình thường (vì vậy một chroot trống không phải là một tùy chọn) và vẫn có thể ghi vào các tệp đã mở (đặc biệt là thiết bị xuất chuẩn).

Điểm thưởng nếu viết tập tin vào thư mục nhất định (tức là thư mục hiện tại) vẫn có thể.

Tôi đang tìm kiếm một giải pháp theo quy trình cục bộ, tức là không liên quan đến việc định cấu hình những thứ như AppArmor hoặc SELinux cho toàn bộ hệ thống, cũng như các đặc quyền gốc. Nó có thể liên quan đến việc cài đặt các mô-đun hạt nhân của họ, mặc dù.

Tôi đã xem xét các khả năng và chúng sẽ rất tốt và dễ dàng, nếu có khả năng tạo tập tin. ulimit là một cách tiếp cận khác sẽ thuận tiện, nếu nó bao gồm trường hợp sử dụng này.


Quá nhiều chương trình cho rằng họ có thể viết các tệp như một vấn đề tất nhiên (và thất bại theo những cách lạ khi họ không thể). stracecho bạn biết những tập tin chương trình đang mở. tại sao bạn muốn làm việc này? Đây có phải là một chương trình cụ thể, hoặc bạn muốn điều này để thử nghiệm hay cái gì khác? Bạn có thể chạy chương trình với tư cách là người dùng / nhóm không được phép viết gần như mọi nơi trừ trong thư mục hiện tại không? Các bản phân phối Linux hiện đại sử dụng ý tưởng của một nhóm cho mỗi người dùng, vì vậy điều này sẽ tương đối dễ thiết lập.
vonbrand

Đây là một chương trình đặc biệt (Isabelle) diễn giải mã theo cách hơi an toàn (không thực thi mã tùy ý), nhưng vẫn cho phép mã tạo tệp ở những nơi tùy ý. Vì mã không đáng tin cậy, tôi muốn ngăn điều này xảy ra (bằng cách hủy bỏ chương trình). Chương trình đã chạy như một người dùng đặc biệt, nhưng tôi cảm thấy an toàn hơn nếu mã không thể ghi đè, nói, / tmp hoặc các địa điểm tương tự.
Joachim Breitner

Bạn có thể thêm người dùng mới để chạy ứng dụng.
ctrl-alt-delor

Câu trả lời:


9

Làm thế nào về việc tạo một chroot trống, sau đó gắn kết hệ thống tập tin chính dưới dạng chỉ đọc bên trong chroot?

Có lẽ nên là một cái gì đó như thế này để tạo ra một mount-mount chỉ đọc:

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

Bạn có thể liên kết gắn kết các thư mục khác mà bạn muốn nhà tù cũng có quyền truy cập ghi. Hãy cẩn thận nếu bạn cần liên kết các thư mục đặc biệt gắn kết (/ dev /, / Proc /, / sys /), việc gắn chúng như có thể không an toàn.


Một lần nữa, cần đặc quyền gốc và các thiết lập toàn cầu khác. Nhưng một lựa chọn, có.
Joachim Breitner

/foo/đường dẫn đến hệ thống tập tin chính?
Wayne Conrad

5

Có vẻ như công cụ phù hợp cho công việc này là fseccompDựa trên sync-ignoringmã f của Bastian Blank, tôi đã nghĩ ra tệp tương đối nhỏ này khiến tất cả trẻ em của nó không thể mở tệp để viết:

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

Ở đây bạn có thể thấy rằng vẫn có thể đọc các tệp:

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

Nó không ngăn chặn việc xóa các tập tin, hoặc di chuyển chúng, hoặc các hoạt động tập tin khác ngoài việc mở, nhưng điều đó có thể được thêm vào.

Một công cụ cho phép điều này mà không phải viết mã C là syscall_limiter .


4
Lưu ý rằng phương pháp an toàn là các tòa nhà danh sách trắng, không đưa vào danh sách đen chúng. Nếu quá nhiều bị từ chối, người trợ giúp không có hộp thư bên ngoài có thể được sử dụng để hỗ trợ chương trình. Với LD_PRELOAD, những người trợ giúp như vậy có thể được minh bạch cho chương trình chúng tôi đang chạy.
Vi.

4

Bạn có xem xét việc viết một thay thế cho open(…)chức năng và tải nó bằng LD_PRELOAD không?


2
Bạn có thể có nghĩa là open... Chà, tôi sẽ xem xét sử dụng một giải pháp hiện có sử dụng phương pháp này, vâng.
Joachim Breitner

2
Có một cái gì đó như thế này tại github.com/certik/restrict , nhưng nó được cấu hình bằng cách biên dịch và dường như không được sử dụng rộng rãi.
Joachim Breitner

Vâng, xin lỗi, lỗi của tôi, cập nhật câu trả lời Nhưng dường như với tôi bạn cũng sẽ phải thay thế một câu hỏi write(…).
Leonid

Đối với github.com/certik/restrict , vâng, bạn hoàn toàn đúng.
Leonid

3

Giải pháp đơn giản nhất có lẽ là một chương trình bao bọc tạo ra một không gian tên hệ thống tệp mới với các hệ thống tệp có liên quan được gắn ở chế độ chỉ đọc và sau đó thực thi chương trình bạn đang cố gắng hạn chế.

Đây là những gì systemdkhi bạn sử dụng ReadOnlyDirectories=để đánh dấu các thư mục nhất định là chỉ đọc cho một dịch vụ. Ngoài ra còn có một unsharelệnh trong util-linuxđó có thể thực hiện công việc tạo một không gian tên mới, vì vậy bạn có thể làm một cái gì đó như:

unshare -m <wrapper>

nơi mà wrappersau đó sẽ phải kết nối lại các hệ thống tập tin theo yêu cầu trước khi bắt đầu chương trình đích thực sự.

Vấn đề duy nhất là bạn cần phải roottạo không gian tên mới ...


Tôi nghĩ về điều này. Nhưng điều này có thể mà không cần root? Có một kịch bản / chương trình đã sẵn sàng cho điều đó có sẵn không?
Joachim Breitner

1
Vâng, có vẻ như bạn cần phải root, ít nhất là với kernel 3.7.
TomH

Tôi đã tìm kiếm thêm về giải pháp này. Có thể liên kết đệ quy gắn kết / với một /, nhưng không và đệ quy đánh dấu nó là chỉ đọc.
Joachim Breitner

2

Bạn có thể chạy nó trong một chroot, gắn các phiên bản đặc biệt /tmp và như vậy bên trong. Có lẽ systemd là trợ giúp, và đặc biệt là systemd-nspawn (1) , trông giống như những gì bạn muốn.


2

Một máy ảo sẽ giúp tập lệnh có thể viết ở bất cứ đâu mà không ảnh hưởng đến hệ thống máy chủ và kiểm tra xem nó thực sự cố gắng viết ở đâu, dường như là mục tiêu.

Ví dụ: bạn có thể dễ dàng khởi động Arch Linux với

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

1
Tôi vẫn muốn chạy chương trình trong máy hiện tại để tránh phải thiết lập hệ thống mới, môi trường mới, v.v. Một máy ảo quá nặng đối với trường hợp sử dụng của tôi.
Joachim Breitner

2

Thực hiện một số thiết lập ban đầu là root thực sự là cách dễ nhất. Cụ thể, một chroot vào một mount liên kết chỉ đọc là con đường ít kháng cự nhất.

Bạn có thể sử dụng bindfs thay vì mount --bindđể tạo chế độ xem chỉ đọc mà không cần phải root. Tuy nhiên, bạn cần phải làm một cái gì đó như root để ngăn truy cập vào các tệp khác, chẳng hạn như chroot.

Một cách tiếp cận khác là LD_PRELOADthư viện nối vào mở tệp và từ chối cho phép viết. Điều này không đòi hỏi đặc quyền. Từ góc độ bảo mật, điều này có thể được bỏ qua, nhưng với trường hợp sử dụng của bạn, bạn chỉ cần chứa một tính năng cụ thể và không phải là mã gốc tùy ý. Tôi không biết về một thư viện hiện có cho việc này, tuy nhiên. LD_PRELOADcũng có thể được sử dụng để giới hạn chương trình ở chế độ chỉ đọc được tạo bằng mount --bindhoặc bindfs; một lần nữa, tôi không biết về một thư viện hiện có.

Trên Debian và các dẫn xuất, bạn có thể thiết lập môi trường schroot . Schroot là root setuid và cần được cấu hình như root, nhưng có thể được thực thi bởi bất kỳ người dùng được ủy quyền nào.

Một phương pháp không yêu cầu bất kỳ sự hợp tác nào từ root là chạy tiến trình trong một máy ảo. Bạn có thể thiết lập KVM hoặc VirtualBox hoặc Linux ở chế độ người dùng . Đó là một chút nặng nề, và sẽ có nghĩa là tiêu thụ thêm bộ nhớ, nhưng không ảnh hưởng đáng kể đến tốc độ tính toán biểu tượng thô.

Làm thế nào để "bỏ tù" một quá trình mà không cần root? có thể cung cấp một số nguồn cảm hứng.


1

Một cách để ít nhất ngăn quá trình ghi các tệp (nhưng không tạo ra chúng) là gọi ulimit -f 0trước. Điều này sẽ hủy bỏ quá trình ngay khi nó cố ghi vào một tệp, nhưng vẫn có thể tạo các tệp trống.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.