GNU/Linux >> Tutoriels Linux >  >> Linux

Différence entre les capacités Linux et seccomp

Je veux connaître la différence exacte entre les capacités Linux et seccomp.

Je vais vous expliquer le exact différences ci-dessous, mais voici l'explication générale :Les capacités impliquent diverses vérifications dans les fonctions du noyau accessibles par les appels système. Si la vérification échoue (c'est-à-dire que le processus n'a pas la capacité nécessaire), l'appel système est généralement fait pour renvoyer une erreur. La vérification peut être effectuée soit au début d'un appel système spécifique, soit plus profondément dans le noyau dans des zones qui peuvent être accessibles via plusieurs appels système différents (comme l'écriture dans un fichier privilégié spécifique).

Seccomp est un filtre d'appel système qui est appliqué à tous les appels système avant qu'ils ne soient exécutés. Un processus peut mettre en place un filtre qui lui permet de révoquer son droit d'exécuter certains appels système, ou des arguments spécifiques pour certains appels système. Le filtre se présente généralement sous la forme d'un bytecode eBPF, que le noyau utilise pour vérifier si un appel système est autorisé ou non pour ce processus. Une fois qu'un filtre est appliqué, il ne peut pas du tout être relâché, seulement rendu plus strict (en supposant que les appels système responsables du chargement d'une politique seccomp sont toujours autorisés).

Notez que certains appels système ne peuvent être limités ni par seccomp ni par les capacités car ce ne sont pas de véritables appels système. C'est le cas des appels vDSO, qui sont des implémentations en espace utilisateur de plusieurs appels système qui n'ont pas strictement besoin du noyau. Tentative de blocage getcpu() ou gettimeofday() est inutile pour cette raison, car un processus utilisera de toute façon le vDSO au lieu de l'appel système natif. Heureusement, ces appels système (et leurs implémentations virtuelles associées) sont largement inoffensifs.

Est-ce également que les capacités de Linux utilisent seccomp en interne ou est-ce l'inverse ou les deux sont complètement différents.

Ils sont implémentés complètement différemment en interne. J'ai écrit une autre réponse ailleurs sur la mise en œuvre actuelle de diverses technologies de sandboxing expliquant en quoi elles diffèrent et à quoi elles servent.

Capacités

De nombreux appels système qui font des choses privilégiées peuvent inclure une vérification interne pour s'assurer que le processus appelant a des capacités suffisantes. Le noyau stocke la liste des capacités d'un processus, et une fois qu'un processus supprime des capacités, il ne peut pas les récupérer. Par exemple, essayer d'écrire dans /dev/cpu/*/msr échouera à moins que le processus appelant le open() syscall a CAP_SYS_RAWIO . Cela peut être vu dans le code source du noyau responsable de la modification des MSR (fonctionnalités CPU de bas niveau) :

static int msr_open(struct inode *inode, struct file *file)
{
    unsigned int cpu = iminor(file_inode(file));
    struct cpuinfo_x86 *c;

    if (!capable(CAP_SYS_RAWIO))
        return -EPERM;

    if (cpu >= nr_cpu_ids || !cpu_online(cpu))
        return -ENXIO;  /* No such CPU */

    c = &cpu_data(cpu);
    if (!cpu_has(c, X86_FEATURE_MSR))
        return -EIO;    /* MSR not supported */

    return 0;
}

Certains appels système ne fonctionneront pas du tout si la capacité correcte n'est pas présente, comme vhangup() :

SYSCALL_DEFINE0(vhangup)
{
    if (capable(CAP_SYS_TTY_CONFIG)) {
        tty_vhangup_self();
        return 0;
    }
    return -EPERM;
}

Les capacités peuvent être considérées comme de larges classes de fonctionnalités privilégiées qui peuvent être supprimées de manière sélective d'un processus ou d'un utilisateur. Les fonctions spécifiques qui ont des vérifications de capacité varient d'une version du noyau à l'autre, et il y a souvent des querelles entre les développeurs du noyau pour savoir si une fonction donnée doit ou non nécessiter des capacités pour s'exécuter. Généralement , la réduction des capacités d'un processus améliore la sécurité en réduisant le nombre d'actions privilégiées qu'il peut effectuer. Notez que certaines fonctionnalités sont considérées comme équivalent racine , ce qui signifie que, même si vous désactivez toutes les autres fonctionnalités, elles peuvent, dans certaines conditions, être utilisées pour récupérer toutes les autorisations. De nombreux exemples sont donnés par le créateur de grsecurity, Brad Spengler. Un exemple évident serait CAP_SYS_MODULE qui permet de charger des modules de noyau arbitraires. Un autre serait CAP_SYS_ADMIN qui est une capacité fourre-tout presque équivalente à root.

Comp Mode 1 seconde

Il existe deux types de seccomp :le mode 1 (strict) et le mode 2 (filtre). Le mode 1 est extrêmement restrictif et, une fois activé, n'autorise que quatre appels système. Ces appels système sont read() , write() , exit() , et rt_sigreturn() . Un processus reçoit immédiatement le fatal SIGKILL signal du noyau s'il tente un jour d'utiliser un appel système qui ne figure pas sur la liste blanche. Ce mode est le mode seccomp d'origine et ne nécessite pas la génération et l'envoi de bytecode eBPF au noyau. Un appel système spécial est effectué, après quoi le mode 1 sera actif pendant toute la durée de vie du processus :seccomp(SECCOMP_SET_MODE_STRICT) ou prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT) . Une fois activé, il ne peut pas être désactivé.

Voici un exemple de programme qui exécute en toute sécurité le bytecode qui renvoie 42 :

#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <linux/seccomp.h>

/* "mov al,42; ret" aka "return 42" */
static const unsigned char code[] = "\xb0\x2a\xc3";

void main(void)
{
    int fd[2], ret;

    /* spawn child process, connected by a pipe */
    pipe(fd);
    if (fork() == 0) {
        close(fd[0]);

        /* enter mode 1 seccomp and execute untrusted bytecode */
        prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
        ret = (*(uint8_t(*)())code)();

        /* send result over pipe, and exit */
        write(fd[1], &ret, sizeof(ret));
        syscall(SYS_exit, 0);
    } else {
        close(fd[1]);

        /* read the result from the pipe, and print it */
        read(fd[0], &ret, sizeof(ret));
        printf("untrusted bytecode returned %d\n", ret);
    }
}

Le mode 1 est le mode d'origine et a été ajouté dans le but de permettre l'exécution de bytecode non approuvé pour les calculs bruts. Un processus de courtier créerait un enfant (et éventuellement établirait une communication via des canaux), et l'enfant activerait seccomp, l'empêchant de faire autre chose que de lire et d'écrire à partir de descripteurs de fichiers déjà ouverts et de se fermer. Ce processus enfant pourrait alors exécuter un bytecode non approuvé en toute sécurité. Peu de gens utilisaient ce mode, mais avant que Linus ne puisse se plaindre assez fort pour le tuer, l'équipe de Google Chrome a exprimé le désir de l'utiliser pour son navigateur. Cela a suscité un regain d'intérêt pour seccomp et l'a sauvé d'une mort prématurée.

Comp Mode 2 secondes

Le deuxième mode, filtre, également appelé seccomp-bpf, permet au processus d'envoyer une politique de filtrage affinée au noyau, autorisant ou refusant des appels système entiers, ou des arguments d'appel système spécifiques ou des plages d'arguments. La politique spécifie également ce qui se passe en cas de violation (par exemple, le processus doit-il être arrêté ou l'appel système doit-il simplement être refusé ?) et si la violation doit être consignée ou non. Étant donné que les appels système Linux sont conservés dans des registres et ne peuvent donc être que des nombres entiers, il est impossible de filtrer le contenu de la mémoire vers lequel un argument d'appel système pourrait pointer. Par exemple, bien que vous puissiez empêcher open() d'être appelé avec le O_RDWR capable d'écriture ou O_WRONLY flags, vous ne pouvez pas mettre en liste blanche le chemin individuel qui est ouvert. La raison en est que, pour seccomp, le chemin n'est rien de plus qu'un pointeur vers la mémoire contenant le chemin du système de fichiers terminé par un caractère nul. Il n'y a aucun moyen de garantir que la mémoire contenant le chemin n'a pas été modifiée par un thread frère entre le passage de la vérification seccomp et le déréférencement du pointeur, à moins de le mettre en mémoire en lecture seule et de refuser l'accès aux appels système liés à la mémoire. Il est souvent nécessaire d'utiliser des LSM comme AppArmor.

Ceci est un exemple de programme utilisant le mode 2 seccomp pour s'assurer qu'il ne peut imprimer que son PID actuel. Ce programme utilise la bibliothèque libseccomp qui facilite la création de filtres seccomp eBPF, bien qu'il soit également possible de le faire à la dure sans aucune bibliothèque d'abstraction.

#include <seccomp.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

void main(void)
{
    /* initialize the libseccomp context */
    scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);

    /* allow exiting */
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);

    /* allow getting the current pid */
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0);

    /* allow changing data segment size, as required by glibc */
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);

    /* allow writing up to 512 bytes to fd 1 */
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 2,
        SCMP_A0(SCMP_CMP_EQ, 1),
        SCMP_A2(SCMP_CMP_LE, 512));

    /* if writing to any other fd, return -EBADF */
    seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EBADF), SCMP_SYS(write), 1,
        SCMP_A0(SCMP_CMP_NE, 1));

    /* load and enforce the filters */
    seccomp_load(ctx);
    seccomp_release(ctx);

    printf("this process is %d\n", getpid());
}

Le mode 2 seccomp a été créé car le mode 1 avait évidemment ses limites. Toutes les tâches ne peuvent pas être séparées en un processus de pur bytecode qui pourrait s'exécuter dans un processus enfant et communiquer via des canaux ou de la mémoire partagée. Ce mode a beaucoup plus de fonctionnalités et ses fonctionnalités continuent d'être lentement étendues. Cependant, il a toujours ses inconvénients. L'utilisation en toute sécurité du mode 2 seccomp nécessite une compréhension approfondie des appels système (vouloir bloquer kill() de tuer d'autres processus ? Dommage, vous pouvez tuer des processus avec fcntl() aussi!). Il est également fragile, car des modifications de la libc sous-jacente peuvent provoquer des pannes. La glibc open() la fonction, par exemple, n'utilise plus toujours l'appel système de ce nom et peut utiliser à la place openat() , enfreignant les politiques qui ne mettaient sur liste blanche que les premières.


Linux
  1. Quelle est la différence entre un conteneur Linux et une image ?

  2. La Différence Entre [[ $a ==Z* ]] Et [ $a ==Z* ] ?

  3. Linux - Différence entre l'espace utilisateur et l'espace noyau ?

  4. Linux – Quelle est la différence entre `su -` et `su –login` ?

  5. différence Linux entre sudo crontab -e et juste crontab -e

Comprendre la différence entre les commandes sudo et su sous Linux

Quelle est la différence entre les noyaux macOS et Linux

Quelle est la différence entre Linux et Unix ?

Différence entre su et sudo et Comment configurer sudo dans Linux VPS.

différence entre netstat et ss sous linux?

différence copier le dossier de contenu entre /. et /* sous linux