Wie erstelle ich einen Unix-Domain-Socket mit bestimmten Berechtigungen in C?

Lesezeit: 5 Minuten

Benutzer-Avatar
Abgrund.7

Ich habe einen einfachen Code, wie:

sockaddr_un address;
address.sun_family = AF_UNIX;
strcpy(address.sun_path, path);
unlink(path);

int fd = socket(AF_UNIX, SOCK_STREAM, 0);
bind(fd, (sockaddr*)(&address), sizeof(address));
listen(fd, 100);

Ich möchte atomar Erstellen Sie die Unix-Domain-Socket-Datei mit bestimmten Berechtigungen, sagen Sie: 0777. Das Handbuch sagt nichts über Socket-Dateiberechtigungen in Bezug auf umask oder Wasauchimmer. Auch wenn die umask wirkt sich auf die Socket-Datei aus, dann ist es kein atomarer Weg – in Multithread-Programmen.

Ich hoffe, es gibt einen Weg, mein Ziel zu erreichen, ohne die Synchronisation von zu verwenden umask() Anrufe.

  • Warum kümmern? Das nachträgliche Festlegen von Berechtigungen hat bei mir nie ein Problem verursacht. Es ist nicht so, dass dort Prozesse sitzen und darauf warten, sich unrechtmäßig auf Ihren Socket zu stürzen – und wenn doch, haben Sie weitaus größere Probleme als Socket-Berechtigungen.

    – chao

    24. November 2013 um 6:34 Uhr


  • @cHao: Möglicherweise gibt es Prozesse, die zuhören inotify und kann versuchen, eine Verbindung zum Socket herzustellen, bevor mein Prozess die richtigen Berechtigungen festgelegt hat – es ist ein “guter” Prozess, aber er wird fehlschlagen. Meine Frage ist eher die theoretische Frage, als ein Versuch, eine Problemumgehung für eine bestimmte Situation zu finden.

    – Abgrund.7

    24. November 2013 um 6:44 Uhr


  • @cHao: Schon mal was von Multiuser-Systemen gehört? Wie Unix? Wie in einem der Schlüsselwörter dieser Frage? Wenn eine Anwendung nicht Umgang mit einem Prozess, der darauf wartet, sich illegitim auf seinen Socket zu stürzen, auf dem sich die Anwendung befindet stark gebrochen.

    – Markus

    7. April 2015 um 22:24 Uhr

  • @cHao: Wenn kein böswilliger Benutzer Root-Zugriff erlangt hat und Der Kernel enthält keine Sicherheitslücken zur Rechteausweitung. Sie können sicher sein, dass der Kernel nicht kompromittiert ist, was genau mein Punkt ist. Durch nicht Wenn Sie Prozessen vertrauen, die als ein anderer Benutzer auf demselben Computer ausgeführt werden, verhindern Sie, dass böswillige Prozesse Root-Zugriff erhalten.

    – Markus

    8. April 2015 um 18:28 Uhr


  • @cHao: Der letzte Teil ist ein guter Punkt – das Festlegen von Berechtigungen zwischen bind() und listen() sollte ausreichen.

    – Markus

    9. April 2015 um 10:05 Uhr

Benutzer-Avatar
Elias Martenson

Eine andere Lösung besteht darin, ein Verzeichnis mit den gewünschten Berechtigungen zu erstellen und dann den Socket darin zu erstellen (Beispielcode ohne Rücksicht auf Fehlerprüfung und Pufferüberläufe):

// Create a directory with the proper permissions
mkdir(path, 0700);
// Append the name of the socket
strcat(path, "/socket_name");

// Create the socket normally
sockaddr_un address;
address.sun_family = AF_UNIX;
strcpy(address.sun_path, path);
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
bind(fd, (sockaddr*)(&address), sizeof(address));
listen(fd, 100);

  • Dies ist die beste vorgeschlagene Lösung, da der Besitz eines übergeordneten Verzeichnisses des Unix-Sockets seine Verbindungsfähigkeit beeinflusst.

    – Abgrund.7

    17. November 2014 um 7:07 Uhr

  • Funktioniert nicht für mich. Das übergeordnete Verzeichnis ist 777, der Sockel ist immer noch 755, also nur vom Eigentümer beschreibbar.

    – Benutzer2804197

    21. Februar 2017 um 16:33 Uhr

  • Das könnte daran liegen, dass sich im Modus ein Tippfehler eingeschlichen hat. Ich habe die Antwort mit der richtigen Antwort bearbeitet.

    – Elias Martenson

    27. Februar 2017 um 7:00 Uhr

Ich hatte das beste Glück mit chmod() (NICHT fchmod) mit dem Dateinamen für den Unix-Domain-Socket nach dem Aufruf von socket(), bind(), aber vor dem Aufruf von listen().

  int return_value;
  const char *sock_path;
  struct sockaddr_un local;

  sock_path = "/tmp/mysocket";

  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (sockfd == -1)
  {
    perror("socket");
    exit(-1);
  }

  local.sun_family = AF_UNIX; 
  strcpy(local.sun_path, sock_path);
  unlink(local.sun_path);
  len = strlen(local.sun_path) + sizeof(local.sun_family);
  bind(sockfd, (struct sockaddr *)&local, len);

  chmod(sock_path, 0777);

  retval = listen(sockfd, BACKLOG);
  if (retval == -1)
  {
    perror("listen");
    exit(-1);
  }

. . . . .

  • Es funktioniert nicht, wenn irgendein Prozess den Socket via überwacht inotify – wie ich in einem Kommentar zu meiner Frage erwähnt habe.

    – Abgrund.7

    3. Juli 2014 um 6:42 Uhr

  • @abyss.7 Eigentlich habe ich gerade getestet (Linux 3.8.0) und es funktioniert. connect() schlägt auf einem Socket fehl, wenn listen() noch nicht aufgerufen wurde. Es scheint also, dass Sie einen Socket sicher chmoden können, bevor Sie listen() aufrufen, ohne befürchten zu müssen, dass ein nicht autorisierter Benutzer eine Verbindung herstellt. Wie Elias bereits erwähnt hat, ist es jedoch am besten, ein Verzeichnis mit den gewünschten Berechtigungen und dem Socket innerhalb des Verzeichnisses zu erstellen.

    – datenlos

    17. November 2014 um 6:48 Uhr

  • Eine andere Methode: Erstellen Sie die Datei mit einem anderen Dateinamen, chmod() und dann rename() auf den endgültigen Dateinamen. Normalerweise erstelle ich die Datei mit angehängtem -TMP und benenne sie dann nach chmod() und listen() um

    – Benutzer2679859

    14. Juni 2021 um 22:04 Uhr


Benutzer-Avatar
Anonym

Gabeln, Verwenden von umask und Zurückgeben des fd ist der einzige tragbare Weg, den ich mir vorstellen kann. Ein Verzeichnis für den Socket zu haben ist in jedem Fall besser, zum Beispiel kann niemand den Socket löschen, wenn das Verzeichnis nicht die richtigen Berechtigungen hat, und das Erstellen von Verzeichnissen kann atomar erfolgen.

Das größere Problem ist, dass das Verlassen auf Berechtigungen nicht portabel ist – viele von BSD abgeleitete Socket-Stacks ignorieren einfach die Berechtigungen von einschließenden Verzeichnissen und/oder dem Socket selbst.

Auf GNU/Linux-Systemen können Sie dies tun, indem Sie fchmod auf dem Socket fd nach socket() und vor bind() aufrufen.

  • Genau, fchmod() vor bind() funktioniert ohne Races in Multithread-Umgebungen, ist aber nicht portierbar, sagen wir mal, auf einige BSD-Varianten. Sogar POSIX sagt, dass fchmod() auf Socket ein nicht spezifiziertes Verhalten hat. Du solltest auf jeden Fall *sollten Achten Sie darauf, dass die Berechtigungen atomar festgelegt werden.

    – nervt

    22. Juli 2014 um 9:30 Uhr

  • Was bedeutet “Forken und Zurückgeben der fd”?

    – Guido

    11. November 2014 um 0:00 Uhr

  • @Guido Sie können Dateideskriptoren über einen Socket übergeben. Sehen normalesup.org/~george/comp/libancillary

    – datenlos

    17. November 2014 um 6:30 Uhr

  • @Anonymous Können Sie nicht einfach Socket, Fork, Umask, Bind erstellen und dann 0 zurückgeben, um dem Elternteil mitzuteilen, dass der Socket bereit ist? Einfacher als Zusatzdaten … Und wissen Sie sicher, welche BSDs Berechtigungen ignorieren? Die beste Information, die ich finden kann, ist, dass 4.2 Socket Perms ignoriert, aber Dir Perms überprüft hat.

    – datenlos

    17. November 2014 um 6:32 Uhr


  • @dataless, das ist erstaunlich. Vielen Dank!

    – Guido

    15. Dezember 2014 um 3:49 Uhr

1379990cookie-checkWie erstelle ich einen Unix-Domain-Socket mit bestimmten Berechtigungen in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy