Comment empêcher un process d'écrire des files

Je veux exécuter une command sur Linux de manière à ce qu'elle ne puisse pas créer ou ouvrir de files à écrire. Il devrait toujours être capable de lire les files normalement (donc un chroot vide n'est pas une option), et encore être en mesure d'écrire dans les files déjà ouverts (en particulier stdout).

Points bonus si écrire des files dans certains directorys (c'est-à-dire le directory courant) est toujours possible.

Je search une solution locale, c'est-à-dire n'impliquant pas de configuration comme AppArmor ou SELinux pour l'set du système, ni les privilèges root. Cela peut impliquer l'installation de leurs modules kernel, cependant.

Je regardais les capacités et cela aurait été agréable et facile, s'il y avait une capacité pour créer des files. ulimit est une autre approche qui serait pratique, si elle couvrait ce cas d'utilisation.

Que diriez-vous de créer un chroot vide, puis de lier le système de files principal en lecture seule dans le chroot?

Devrait probablement être quelque chose comme ça pour créer un bind-mount en lecture seule:

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

Vous pouvez lier d'autres directorys dans lesquels vous souhaitez que la prison dispose également d'un access en écriture. Soyez prudent si vous avez besoin de bind-mount directorys spéciaux (/ dev /, / proc /, / sys /), les monter en tant que-est peut-être non sécurisé.

Considérez-vous écrire un substitut pour open(…) et le charger en utilisant LD_PRELOAD?

La solution la plus simple est probablement un programme d'encapsulation qui crée un nouvel espace de noms de système de files avec les filesystems appropriés montés en lecture seule, puis exécute le programme que vous essayez de restreindre.

C'est ce que systemd fait lorsque vous utilisez ReadOnlyDirectories= pour marquer certains directorys en lecture seule pour un service. Il y a aussi une command unshare dans util-linux qui peut faire le travail de création d'un nouvel espace de noms, vous pouvez donc faire quelque chose comme:

 unshare -m <wrapper> 

wrapper devra simplement remonter les filesystems au besoin avant de lancer le véritable programme cible.

Le seul problème est que vous devez être root pour créer le nouvel espace de noms …

Il semble que le bon outil pour ce travail est fseccomp Basé sur le code f de sync-ignoring par Bastian Blank, je suis venu avec ce file relativement petit qui fait que tous ses enfants ne peuvent pas ouvrir un file pour écrire:

 /* * Copyright (C) 2013 Joachim Breitner <[email protected]> * * Based on code Copyright (C) 2013 Bastian Blank <[email protected]> * * Redissortingbution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redissortingbutions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redissortingbutions 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 dissortingbution. * * 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 <ssortingng.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(__atsortingbute__((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; } 

Ici vous pouvez voir qu'il est encore possible de lire des files:

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

Cela n'empêche pas de supprimer des files ou de les déplacer, ou d'autres opérations de files en plus de l'ouverture, mais cela pourrait être ajouté.

Un outil qui permet cela sans avoir à écrire de code C est syscall_limiter .

Vous pourriez l'exécuter dans un chroot, en installant des versions spéciales de /tmp et à l'intérieur. Peut-être systemd est utile, et en particulier systemd-nspawn (1) , qui ressemble à ce que vous voulez.

Une machine virtuelle permettrait au script d'écrire n'importe où sans affecter le système hôte et d'inspecter là où il essaye d'écrire, ce qui semble être les objectives.

Par exemple, vous pouvez facilement démarrer Arch Linux avec

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

Faire une configuration initiale en tant que root est vraiment la manière la plus simple. Spécifiquement, un chroot dans un assembly de binding en lecture seule est le path de moindre résistance.

Vous pouvez utiliser bindfs au lieu de mount --bind pour créer la vue en lecture seule sans avoir besoin d'être root. Cependant, vous devez faire quelque chose en tant que root pour empêcher l'access à d'autres files, tels que chroot.

Une autre approche consiste à LD_PRELOAD une bibliothèque qui s'intègre dans l'ouverture du file et refuse d'autoriser l'écriture. Cela ne nécessite aucun privilège spécial. Du sharepoint vue de la security, cela peut être contourné, mais c'est correct pour votre cas d'utilisation où il vous suffit de contenir une fonctionnalité spécifique et non un code natif arbitraire. Je ne connais pas une bibliothèque existante pour cela, cependant. LD_PRELOAD pourrait également être utilisé pour limiter le programme à la vue en lecture seule créée avec mount --bind ou bindfs ; encore une fois, je ne connais pas une bibliothèque existante.

Sur Debian et les dérivés, vous pouvez configurer un environnement schroot . Schroot est root setuid et doit être configuré en tant que root, mais peut être exécuté par n'importe quel user autorisé.

Une méthode qui ne requirejs aucune coopération de la part de root consiste à exécuter le process dans une machine virtuelle. Vous pouvez configurer KVM ou VirtualBox, ou Linux en mode user . Il est un peu lourd, ce qui signifie une consommation de memory supplémentaire, mais ne devrait pas affecter significativement la vitesse du calcul symbolique brut.

Comment "emprisonner" un process sans être root? pourrait fournir de l'inspiration.

Une façon d'empêcher au less le process d'écrire les files (mais pas de les créer) est d'appeler ulimit -f 0 premier. Cela interrompra le process dès qu'il essaie d'écrire dans un file, mais la création de files vides est toujours possible.

Vous pouvez utiliser simple utiliser fcntl pour acquérir le verrou sur le file.

Référence: http://www.thegeekstuff.com/2012/04/linux-file-locking-types/