Verwendung von umask() mit chmod-style Argument

Beschreibung

Verwendung von umask() mit chmod-style Argument ist eine Schwachstelle, bei der ein Programm die umask()-Funktion fälschlicherweise mit einem Argument aufruft, das so angegeben ist, als wäre es ein Argument für chmod(). Dies resultiert aus einem grundlegenden Missverständnis darüber, wie umask() funktioniert. Während chmod() Berechtigungen setzt, die gewährt werden, setzt umask() Berechtigungen, die verweigert (maskiert) werden. Wenn Entwickler diese Semantik verwechseln und chmod-style Argumente mit umask() verwenden, werden Dateien mit falschen Berechtigungen erstellt - typischerweise freizügiger als beabsichtigt.

Risiko

Falsche umask()-Verwendung erzeugt erhebliche Dateiberechtigungsschwachstellen. Wenn Entwickler beabsichtigen, Berechtigungen einzuschränken, aber chmod-style Argumente verwenden, haben die resultierenden Dateien die entgegengesetzten Berechtigungen von dem, was beabsichtigt war. Zum Beispiel erzeugt der Aufruf umask(0644) im Glauben, Dateien mit rw-r--r-- Berechtigungen zu erstellen, tatsächlich Dateien mit -------w- (0022) Berechtigungen. Dies kann zu world-writable Dateien, Ausführungsberechtigungen wo keine sein sollten, oder für alle lesbare Dateien führen, wenn sie privat sein sollten.

Lösung

Verstehen Sie, dass umask() invers zu chmod() arbeitet: Berechtigungen in der umask werden vom mode-Argument für open() und andere Dateierstellungsfunktionen ausgeschaltet. Verwenden Sie umask() mit dem korrekten Argument, das die zu verweigernden, nicht die zu gewährenden Berechtigungen darstellt. Für restriktive Dateierstellung verwenden Sie umask(0077), um alle Gruppen- und Ändere-Berechtigungen zu verweigern. Erwägen Sie die Verwendung von explizitem chmod() oder fchmod() nach der Dateierstellung für präzise Berechtigungskontrolle.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Dateien oder Verzeichnisse lesen - Falsche umask-Einstellungen können Dateien erstellen, die von unbefugten Benutzern lesbar sind.
IntegritätBereich: Integrität

Dateien oder Verzeichnisse ändern - Dateien können mit Schreibberechtigungen für unbeabsichtigte Benutzer erstellt werden.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Beabsichtigte Dateizugriffsbeschränkungen sind aufgrund invertierter Berechtigungslogik unwirksam.

Beispielcode

Verwundbarer Code

// Verwundbar: chmod-style Argument mit umask()
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void vulnerable_create_config_file(const char* filename, const char* content) {
    // Verwundbar: Entwickler denkt, dies setzt rw-r--r-- (0644) Berechtigungen
    // Aber umask arbeitet invers - dies maskiert tatsächlich 0644 AUS
    // Resultierende Berechtigungen: ~0644 & 0777 = 0133 (--x-wx-wx)
    umask(0644);

    // Datei mit sehr falschen Berechtigungen erstellt!
    int fd = open(filename, O_CREAT | O_WRONLY, 0777);
    // Tatsächliche Berechtigungen: 0777 & ~0644 = 0133

    write(fd, content, strlen(content));
    close(fd);
}

void vulnerable_create_private_file(const char* filename) {
    // Verwundbar: Entwickler denkt, dies beschränkt auf Eigentümer-only (0600)
    // Erstellt tatsächlich Dateien mit Berechtigungen 0066 (----rw-rw-)
    umask(0600);

    int fd = open(filename, O_CREAT | O_WRONLY, 0666);
    // Beabsichtigt: rw------- (0600)
    // Tatsächlich: 0666 & ~0600 = 0066
    // Datei ist schreibbar für Gruppe und Ändere!

    close(fd);
}

void vulnerable_create_secret_file(const char* filename, const char* secret) {
    // Verwundbar: Denkt "Ich will 0700 Berechtigungen"
    umask(0700);

    int fd = open(filename, O_CREAT | O_WRONLY, 0777);
    // Beabsichtigt: rwx------ (0700)
    // Tatsächlich: 0777 & ~0700 = 0077 (----rwxrwx)
    // Datei ist vollständig zugänglich für Gruppe und Ändere!

    write(fd, secret, strlen(secret));
    close(fd);
}
// Verwundbar: Häufiges Missverständnismuster
int main() {
    // Verwundbar: Entwickler will restriktive Berechtigungen
    // Verwendet fälschlicherweise gewünschte Berechtigungen als umask-Wert
    mode_t old_umask = umask(0644);  // FALSCH!

    // Erstellt Datei - Berechtigungen sind invertiert
    FILE* fp = fopen("/tmp/config.txt", "w");
    if (fp) {
        fprintf(fp, "DB_PASSWORD=secret123\n");
        fclose(fp);
        // Datei hat falsche Berechtigungen, potenziell world-writable
    }

    // Verwundbar: Ein weiterer häufiger Fehler
    umask(0755);  // Denkt, dies gibt rwxr-xr-x
    // Tatsächlich maskiert: Eigentümer write+read, Gruppe execute, Andere execute
    // Resultat für 0777 open: ----w--w- (0022)

    return 0;
}

Lösungscode

// Behoben: Korrekte umask-Verwendung
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void secure_create_config_file(const char* filename, const char* content) {
    // Behoben: umask spezifiziert Berechtigungen zum VERWEIGERN
    // Um rw-r--r-- (0644) zu erhalten, verweigere: ----w--w- (0022)
    mode_t old_umask = umask(0022);

    int fd = open(filename, O_CREAT | O_WRONLY, 0644);
    // Tatsächliche Berechtigungen: 0644 & ~0022 = 0644 (rw-r--r--)
    // Korrekt!

    if (fd >= 0) {
        write(fd, content, strlen(content));
        close(fd);
    }

    umask(old_umask);  // Vorherige umask wiederherstellen
}

void secure_create_private_file(const char* filename) {
    // Behoben: Um rw------- (0600) zu erhalten, verweigere alles für Gruppe/Ändere
    // Verweigere: ----rwxrwx (0077)
    mode_t old_umask = umask(0077);

    int fd = open(filename, O_CREAT | O_WRONLY, 0600);
    // Tatsächliche Berechtigungen: 0600 & ~0077 = 0600 (rw-------)
    // Korrekt!

    if (fd >= 0) {
        close(fd);
    }

    umask(old_umask);
}

void secure_create_secret_file(const char* filename, const char* secret) {
    // Behoben: Für Eigentümer-only Zugriff (0700), verweigere alle Gruppe/Ändere
    mode_t old_umask = umask(0077);

    int fd = open(filename, O_CREAT | O_WRONLY, 0700);
    // Tatsächlich: 0700 & ~0077 = 0700 (rwx------)
    // Korrekt!

    if (fd >= 0) {
        write(fd, secret, strlen(secret));
        close(fd);
    }

    umask(old_umask);
}
// Behoben: Verwendung von explizitem chmod() für präzise Kontrolle
void secure_create_with_chmod(const char* filename, const char* content,
                              mode_t desired_mode) {
    // Behoben: Zuerst mit restriktiven Berechtigungen erstellen
    mode_t old_umask = umask(0077);  // Am restriktivsten

    int fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, desired_mode);
    if (fd < 0) {
        umask(old_umask);
        return;
    }

    write(fd, content, strlen(content));
    close(fd);

    // Behoben: Explizites chmod() für exakte Berechtigungen verwenden
    if (chmod(filename, desired_mode) != 0) {
        perror("chmod fehlgeschlagen");
        unlink(filename);  // Datei entfernen wenn Berechtigungen nicht setzbar
    }

    umask(old_umask);
}

// Behoben: Referenztabelle für umask-Werte
/*
 * UMASK REFERENZ:
 *
 * umask-Wert | Dateien mit 0666 | Verzeichnisse mit 0777
 * ----------+--------------------------+----------------------
 * 0000       | rw-rw-rw- (0666)        | rwxrwxrwx (0777)
 * 0022       | rw-r--r-- (0644)        | rwxr-xr-x (0755) [typischer Benutzer]
 * 0027       | rw-r----- (0640)        | rwxr-x--- (0750) [typischer Daemon]
 * 0077       | rw------- (0600)        | rwx------ (0700) [privat]
 *
 * Merke: umask VERWEIGERT die angegebenen Berechtigungen
 * Endgültiger Modus = angeforderter_modus & ~umask
 */

// Makros für Klarheit
#define UMASK_PRIVATE      0077  // Verweigere alle Gruppe/Ändere
#define UMASK_USER_DEFAULT 0022  // Verweigere Gruppe/Andere Schreiben
#define UMASK_DAEMON       0027  // Verweigere Gruppe Schreiben, alle Ändere

void example_usage() {
    // Für private Dateien (Anmeldeinformationen, Schlüssel)
    umask(UMASK_PRIVATE);

    // Für normale Benutzerdateien
    umask(UMASK_USER_DEFAULT);

    // Für Daemon-Dateien
    umask(UMASK_DAEMON);
}

CVE-Beispiele

Keine spezifischen CVEs für diese CWE, aber falsche umask-Verwendung hat zu zahlreichen lokalen Privilegieneskalations-Schwachstellen in Unix/Linux-Anwendungen beigetragen.


Referenzen

  1. MITRE Corporation. "CWE-560: Use of umask() with chmod-style Argument." https://cwe.mitre.org/data/definitions/560.html
  2. IEEE Std 1003.1 (POSIX). "umask - set and get the file mode creation mask."
  3. Linux man pages. "umask(2) - set file mode creation mask."