Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

setgid et mpd

10 réponses
Avatar
Eric Belhomme
Bonjour,

En configurant un serveur MPD pour accéder à un DAC 24 bits, je suis
tombé sur un problème de droits que je n'arrive pas à m'expliquer, et qui
me semble anormal. Voici le cas:

Soit un DAC banché en USB sur une orangepi+2e tournant sous
"armbian" (Ubuntu Xenial porté sur le hard de l'Orangepi)

Le DAC est correctement détecté par le noyau et Alsa l'auto-configure les
doigts dans le nez. Systemd-udevd me créé des entrées dans /dev avec les
privilèges suitants :
crw-rw---- 1 root audio 116, 80 Jan 24 23:14 pcmC2D0p

J'installe le paquet pour mpd à coup de apt-get install mpd. Ce dernier
me créé un user "mpd" avec comme groupe principal le groupe 'audio'.
Juste là tout va bien.
Je rajoute comme groupe secondaire à mpd le groupe 'music', qui est le
groupe propriétaire de ma discothèque sur mon NAS.

Je configure ensuite le daemon mpd, entre autre avec les paramètres
suivants :

user "mpd"
group "music"

Et la section "output" qui va bien pour envoyer via Alsa la music par le
DAC. Je suis sûr de ma config puisqu'un "speaker-test" fonctionne
correctement.

Je démarre le daemon, et tente de lui faire ouvrir un fichier, et MPD
m'insulte avec ceci:

alsa_mixer: Failed to read mixer for 'My ALSA Device': failed to attach
to default: Permission denied

J'ai passé des heures essayer de le faire tomber en marche, en exécutant
MPD en root, ça fonctionne, dès que je remets le user "mpd", ça ne
fonctionne plus !

Finalement, je modifie group:

group "audio"

Et là miracle, ça tombe en marche, MPD arrive enfin à accéder au device
Alsa !

On est d'accord, l'erreur était entre la chaise et le clavier. mais
pourant :
id mpd
uid=112(mpd) gid=29(audio) groups=29(audio),1001(music)

Même si le groupe positionné par MPD lors de son impersonalisation (j'ai
vérifié dans le code, il simple appel à setgid()...) n'est pas le bon, mon
user mpd, lui, est bien membre du groupe audio !
Il me semble donc que malgré tout mpd aurait dû pouvoir accéder au device
(en root:audio 0660) ?

Alors soit il y a un biais dans mon raisonnement, et je voudrais bien
savoir ou, soit il y a une couille dans le potage... Quoi qu'il en soit ça
me titille de pas comprendre, donc si quelqu'un a l'explication, je l'en
remercie par avance :)

--
Rico

10 réponses

Avatar
Marc SCHAEFER
Eric Belhomme <rico-{nospam}@ricozome.net> wrote:
Je configure ensuite le daemon mpd, entre autre avec les paramètres
suivants :
user "mpd"
group "music"

Je suppose que mpd est lancé comme root, et qu'ensuite il
fait un setuid/seteuid du numéro de /etc/passwd de l'utilisateur
mpd, puis un setgid/setegid du numéro de /etc/group du
groupe mentionné.
Il ne va pas chercher manuellement dans /etc/group quels
groupes additionnels il doit en plus supporter.
Cela serait différent si vous aviez fait, dans les scripts de
démarrage:
su - mpd
lancement-du-daemon &
group "audio"

signifie: forcer mpd à prendre le groupe audio, que l'utilisateur
défini sous user ait ou non ce groupe dans les groupes supplémentaires
de /etc/group
id mpd
uid2(mpd) gid)(audio) groups)(audio),1001(music)

su (ou login) est assez sympa pour ajouter tous les groupes supplémentaires,
ce qu'un simple setuid/setueid() ne fera jamais (il ne mettra même pas
les groupes primaires: le kernel ne va pas aller lire /etc/group).
C'est mpd qui devrait le faire, mais ils ne l'ont pas fait, vu que le
groupe désiré est à configurer dans "group" ci-dessus.
Avatar
Marc SCHAEFER
Eric Belhomme <rico-{nospam}@ricozome.net> wrote:
Je configure ensuite le daemon mpd, entre autre avec les paramètres
suivants :
user "mpd"
group "music"

Je suppose que mpd est lancé comme root, et qu'ensuite il
fait un setuid/seteuid du numéro de /etc/passwd de l'utilisateur
mpd, puis un setgid/setegid du numéro de /etc/group du
groupe mentionné.
Il ne va pas chercher manuellement dans /etc/group quels
groupes additionnels il doit en plus supporter.
Cela serait différent si vous aviez fait, dans les scripts de
démarrage:
su - mpd
lancement-du-daemon &
ou, d'une seule ligne: su - mpd -c 'lancement-du-daemon' &
group "audio"

signifie: forcer mpd à prendre le groupe audio, que l'utilisateur
défini sous user ait ou non ce groupe dans les groupes supplémentaires
de /etc/group
id mpd
uid2(mpd) gid)(audio) groups)(audio),1001(music)

su (ou login) est assez sympa pour ajouter tous les groupes supplémentaires,
ce qu'un simple setuid/setueid() ne fera jamais (il ne mettra même pas
les groupes primaires: le kernel ne va pas aller lire /etc/group).
C'est mpd qui devrait le faire, mais ils ne l'ont pas fait, vu que le
groupe désiré est à configurer dans "group" ci-dessus.
Avatar
Marc SCHAEFER
Marc SCHAEFER wrote:
Cela serait différent si vous aviez fait, dans les scripts de
démarrage:
su - mpd
lancement-du-daemon &

Je me réponds, vu que le Supersedes: ne marche pas toujours.
Dans les scripts de démarrage, quelque chose comme
su - mpd -c lancement-du-daemon &
en interactif, ce qui est ci-dessus marche.
Avatar
Eric Belhomme
Le Fri, 26 Jan 2018 16:08:09 +0100, Marc SCHAEFER a écrit :
Je suppose que mpd est lancé comme root, et qu'ensuite il fait un
setuid/seteuid du numéro de /etc/passwd de l'utilisateur mpd, puis un
setgid/setegid du numéro de /etc/group du groupe mentionné.
Il ne va pas chercher manuellement dans /etc/group quels groupes
additionnels il doit en plus supporter.

Jusque là, on est d'accord. Je suis même allé vérifier dans le code
(uniquement sur la branche master, je n'ai pas poussé le vice jusqu'à
aller voir le code packagé par Ubuntu pour Xenial !) et à
l'initialisation du démon, le code fait un appel à setuid() et setgid()
group "audio"

signifie: forcer mpd à prendre le groupe audio, que l'utilisateur défini
sous user ait ou non ce groupe dans les groupes supplémentaires de
/etc/group

Soit. Je suis toujours d'accord.
id mpd uid2(mpd) gid)(audio) groups)(audio),1001(music)

su (ou login) est assez sympa pour ajouter tous les groupes
supplémentaires,
ce qu'un simple setuid/setueid() ne fera jamais (il ne mettra même pas
les groupes primaires: le kernel ne va pas aller lire /etc/group).

Une fois de plus on est d'accord. J'ajouterais même que seteuid() n'a pas
à toucher au groupe, puisque sa fonction est de s'occuper de l'UID !
C'est mpd qui devrait le faire, mais ils ne l'ont pas fait, vu que le
groupe désiré est à configurer dans "group" ci-dessus.

Là je ne suis plus.
On est donc d'accord que l'on a un daemon lancé par root:root (via
systemd) qui s'est impersonalisé sous mpd:music en démarrant un processus
enfant avec cette identité. Donc tous les accès postérieurs aux devices
et fichiers sont faits avec l'identité mpd:music
Par ailleurs, on sait que mpd est membre du groupe 'audio', et que mes
devices /dev/snd/* appartiennent à ce groupe 'audio' avec les droits 'rw'.
Je m'attends donc à ce que mon démon mpd, qui tourne avec l'identité
'mpd' et qui va tenter de lire /dev/snd/* avec un utilisateur /
normalement/ autorisé à le faire puisque membre du groupe 'audio' puisse
y accéder, or ce n'est pas le cas.
Je ne comprends toujours pas pourquoi :-(
--
Rico
Avatar
Marc SCHAEFER
Eric Belhomme <rico-{nospam}@ricozome.net> wrote:
C'est mpd qui devrait le faire, mais ils ne l'ont pas fait, vu que le
groupe désiré est à configurer dans "group" ci-dessus.

Là je ne suis plus.
On est donc d'accord que l'on a un daemon lancé par root:root (via
systemd) qui s'est impersonalisé sous mpd:music en démarrant un processus

oui.
enfant avec cette identité. Donc tous les accès postérieurs aux devices
et fichiers sont faits avec l'identité mpd:music

oui.
Par ailleurs, on sait que mpd est membre du groupe 'audio', et que mes
devices /dev/snd/* appartiennent à ce groupe 'audio' avec les droits 'rw'.

oui, mais non: les groupes supplémentaires de l'utilisateur mpd ne font
pas partie de ce qu'a configuré mpd.
Je m'attends donc à ce que mon démon mpd, qui tourne avec l'identité
'mpd' et qui va tenter de lire /dev/snd/* avec un utilisateur /
normalement/ autorisé à le faire puisque membre du groupe 'audio' puisse
y accéder, or ce n'est pas le cas.
Je ne comprends toujours pas pourquoi :-(

C'est la différence entre
su - mpd
et
setuid/setuid "uid-de-mpd-vue-dans-/etc/passwd"
setgid/stegid "gid-de-music-vu-dans-/etc/group"
mpd ne lit pas les groupes secondaires de mpd dans /etc/group et n'effectue
pas les set correspondants; donc audio n'est pas activé comme groupe de
ce processus.
Pour que ce que tu veux marche il faudrait un pseudo-code du genre:
pour tous les groupes dont mpd fait partie dans /etc/group
ajouter ce groupe
c'est mpd qui doit faire ça, le kernel n'a pas à deviner ça tout seul
et à ouvrir des fichiers et je ne sais encore.
Voici ce que fait su: (sous root pour que strace fonctionne avec un exécutable SUID)
:/home/schaefer# strace su - schaefer 2>/tmp/bla
setgroups(18, [1000, 4, 20, 24, 25, 27, 29, 30, 44, 46, 109, 110, 111, 113, 116, 133, 141, 142]) = 0
effectivement:
:/home/schaefer# grep schaefer /etc/passwd /etc/group
/etc/passwd:schaefer:x:1000:1000:Marc SCHAEFER,,,:/home/schaefer:/bin/bash
/etc/group:adm:x:4:schaefer
/etc/group:dialout:x:20:schaefer
/etc/group:cdrom:x:24:schaefer
/etc/group:floppy:x:25:schaefer
/etc/group:sudo:x:27:schaefer
/etc/group:audio:x:29:schaefer,testuser2,testuser,testuser3,skypeuser,timidity,pulse
/etc/group:dip:x:30:schaefer
/etc/group:video:x:44:schaefer
/etc/group:plugdev:x:46:schaefer
/etc/group:netdev:x:109:schaefer
/etc/group:bluetooth:x:110:schaefer
/etc/group:lpadmin:x:111:schaefer
/etc/group:fuse:x:113:schaefer,testuser3
/etc/group:scanner:x:116:saned,schaefer
/etc/group:sambashare:x:133:schaefer
/etc/group:schaefer:x:1000:
/etc/group:kismet:x:141:schaefer
/etc/group:wireshark:x:142:schaefer
Avatar
Marc SCHAEFER
[ pour étendre le sujet à systemd :-> ]
Marc SCHAEFER wrote:
c'est mpd qui doit faire ça, le kernel n'a pas à deviner ça tout seul
et à ouvrir des fichiers et je ne sais encore.

En fait, je suppose que systemd pourrait faire ça, y compris préparer
l'environnement réseau et autre dans un cgroup, et que l'on pourrait
retirer tous ces setU/Gid des processus daemons, ce qui serait
plus sûr, mais cela n'a pas encore l'air d'être la pratique.
Et je ne connais pas assez bien systemd pour savoir si ça marche
vraiment.
Avatar
Eric Masson
Marc SCHAEFER writes:
'Lut Marc,
<snip explications su>
Merci, c'est très clair. Archivé ;)
--
Je protest,e la véritable andouille est de Vire ou de Guéméné. Mais pas
de Lyon. Enfin je ne crois pas. La rosette est de Lyon. Oui. Quoique.
On l'épingle souvent sur des andouilles.
-+- JdC in GNU : Bon an, mal an, douille Si La Rose êtes.
Avatar
Eric Belhomme
Le Sat, 27 Jan 2018 08:57:32 +0100, Marc SCHAEFER a écrit :
Pour que ce que tu veux marche il faudrait un pseudo-code du genre:
pour tous les groupes dont mpd fait partie dans /etc/group
ajouter ce groupe
c'est mpd qui doit faire ça, le kernel n'a pas à deviner ça tout seul et
à ouvrir des fichiers et je ne sais encore.

Merci pour ces explications. Je ne code pus beaucoup, et encore moins du
code système... Je pensais naïvement que le noyau se démerdait pour gérer
les droits et ownership par lui même, ce qui à la lumière de tes
explications et après reflexion etait stupide.
--
Rico
Avatar
Marc SCHAEFER
Eric Belhomme <rico-{nospam}@ricozome.net> wrote:
Merci pour ces explications. Je ne code pus beaucoup, et encore moins du
code système... Je pensais naïvement que le noyau se démerdait pour gérer
les droits et ownership par lui même, ce qui à la lumière de tes

Disons, on pourrait imaginer que la libc offre une fonction
initialize_user_rights("username");
et que cela fasse tout le bazar dont je parle (uid, gid, gid suppl) puis
appelle les appels systèmes nécessaires.
Mais je crois que cela n'existe pas, et ça correspond bien à l'approche
KISS UNIX.
D'un autre côté, le concept même d'un daemon qui soit lancé sous root
puis devienne un autre utilisateur est mauvais: il y a depuis longtemps
d'autres façons d'obtenir ces droits (avec des helpers, etc).
Et je pense sincèrement que c'est là que systemd pourrait se
démarquer.
D'un autre côté, cela reste la méthode classique UNIX.
Avatar
Eric Belhomme
Le Mon, 29 Jan 2018 10:25:33 +0100, Marc SCHAEFER a écrit :
D'un autre côté, le concept même d'un daemon qui soit lancé sous root
puis devienne un autre utilisateur est mauvais: il y a depuis longtemps
d'autres façons d'obtenir ces droits (avec des helpers, etc).
Et je pense sincèrement que c'est là que systemd pourrait se démarquer.

De nombreux projets écrits en Python ou Ruby (et qui démarrent un mini
serveur HTTP pour leur back-end) l'ont bien compris et fournissent des
"unit" prêts à l'emploi qui utilisent justement Systemd pour ces choses ;)
Mais Mpd est un service à l'ancienne, écrit en c++, et conçu pour être
portable là ou systemd n'existe pas (et à priori ne risque pas d'exister
avant très longtemps !)
--
Rico