Appartenances aux groupes et processus setuid / setgid

10

Processus qui désescaladent les privilèges via setuid()et setgid()ne semblent pas hériter des appartenances aux groupes de l'uid / gid qu'ils ont définis.

J'ai un processus serveur qui doit être exécuté en tant que root pour ouvrir un port privilégié; après cela, il désescalade en un uid / gid spécifique non privilégié, 1 - par exemple, celui de l'utilisateur foo(UID 73). L'utilisateur fooest membre du groupe bar:

> cat /etc/group | grep bar
bar:x:54:foo

Donc, si je me connecte en tant que foo, je peux lire un fichier /test.txtavec ces caractéristiques:

> ls -l /test.txt
-rw-r----- 1 root bar 10 Mar  8 16:22 /test.txt

Cependant, le programme C suivant (compilation std=gnu99), lors de l'exécution root:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main (void) {
    setgid(73);
    setuid(73);
    int fd = open("/test.txt", O_RDONLY);
    fprintf(stderr,"%d\n", fd);
    return 0;
}   

Signale toujours l' autorisation refusée . J'imagine que cela a à voir avec le fait qu'il ne s'agit pas d'un processus de connexion, mais cela gêne en quelque sorte la façon dont les autorisations sont censées fonctionner.


1. Ce qui est souvent SOP pour les serveurs, et je pense qu'il doit y avoir un moyen de contourner cela car j'ai trouvé un rapport de quelqu'un le faisant avec apache - apache a été ajouté au groupe audio et peut apparemment utiliser le système audio. Bien sûr, cela se produit probablement dans un fork et non dans le processus d'origine, mais en fait, le cas est le même dans mon contexte (c'est un processus enfant forké après l'appel de setuid).

boucle d'or
la source
Basculez les setuid()/ setgid()appels autour.
vonbrand
@vonbrand ROTFL Je pensais que j'étais là pour un facepalm - mais même résultat, donc je vais modifier la question pour éliminer le hareng rouge.
goldilocks
1
Si vous utilisez setgid(54)au lieu de setgid(73)(comme dans /etc/groups, le groupe bara gid 54), cela fonctionne-t-il?
lgeorget
@lgeorget Bien sûr, mais cela va à l'encontre du but. Le processus a besoin de son propre GID pour d'autres raisons, et de même, ces fichiers doivent avoir les autorisations dont ils disposent. C'est pourquoi l'appartenance à des groupes au pluriel est nécessaire - par exemple, que se passe-t-il si deux utilisateurs doivent le faire. Notez que vous ne pouvez plus setuid()recommencer après l'avoir fait ... mais, hmmm ... je pense que vous pouvez avec seteuid()...
goldilocks
1
Ma question était de m'assurer qu'il n'y avait aucun autre problème subtil caché quelque part. :-)
lgeorget

Réponses:

14

Le problème est que , setuidet setgid ne suffisent pas à donner votre processus tous les pouvoirs dont il a besoin. Les autorisations d'un processus dépendent de

  • son UID
  • son GID
  • ses groupes supplémentaires
  • ses capacités.

Voir man 7 credentialspour obtenir un aperçu plus détaillé. Ainsi, dans votre cas, le problème est que vous définissez correctement l'UID et le GID, mais vous ne définissez pas les groupes supplémentaires du processus. Et le groupe bara GID 54, no 73, il n'est donc pas reconnu comme un groupe dans lequel se trouve votre processus.

Tu devrais faire

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <grp.h>

int main (void) {
    gid_t supplementary_groups[] = {54};

    setgroups(1, supplementary_groups);
    setgid(73);
    setuid(73);
    int fd = open("/test.txt", O_RDONLY);
    fprintf(stderr,"%d\n", fd);
    return 0;
}  
lgeorget
la source
1
C'était une question intéressante qui mérite plus de votes positifs car elle pourrait en fait être utile à beaucoup de gens là-bas. :-)
lgeorget
J'avais donc un problème similaire avec les ports série. J'ai implémenté cela pour le dialoutgroupe et cela a fonctionné la première fois.
tl8
0

OK, j'ai fait un peu le tour du filet. J'ai d'abord pensé que l' APUE détiendrait toutes les réponses, mais je me suis trompé. Et ma copie (ancienne édition) est à l'œuvre, donc ... Le chapitre 5 du Manuel d'administration Unix et Linux semble prometteur, mais je ne l'ai pas (juste une copie des deux premières éditions, également à l'œuvre).

Les petites ressources que j'ai trouvées (google pour "daemon writing unix") parlent toutes d'étapes importantes, comme comment se dissocier du tty, etc. Mais rien sur l'UID / GID. Étrangement, même la vaste collection HOWTO sur http://tldp.org ne semble pas avoir de détails. Seul excetion est Jason court Let Ecrivez un Daemon Linux - partie I . Chen, Wagner et Dean SUID ont démystifié tous les détails sur la façon dont SUID / SGID et tout ce désordre fonctionnent (un article dans USENIX 2002). Mais attention, Linux a un UID supplémentaire, le FSUID (voir les notes d'incompatibilité Unix de Wolter : Fonctions de réglage UID pour une discussion).

Démoniser un processus n'est certainement pas pour les âmes sensibles. Des considérations générales sur la sécurité sont données dans le guide de programmation sécurisé de D. Wheeler pour Linux et Unix - Création de logiciels sécurisés . Systemd promet de simplifier la plupart de cela (et donc de réduire la place pour les erreurs qui conduisent à des problèmes de sécurité), voir le manuel du démon .

vonbrand
la source
1
La question ne concerne pas la démonisation. Vous avez confondu le bit SUID (accordant à un processus les autorisations du propriétaire de son exécutable) avec setuid(), ce qui permet au processus de changer arbitrairement son UID. SUID est généralement destiné à permettre une escalade des autorisations (non privilégiées -> privilégiées), alors setuid()qu'il ne peut faire que le contraire.
goldilocks