Udostępnij przez


Tworzenie procesu

W przypadku systemu plików większość interesujących działań związanych z bezpieczeństwem odbywa się podczas przetwarzania IRP_MJ_CREATE. Jest to krok, który musi przeanalizować żądanie przychodzące, określić, czy obiekt wywołujący ma odpowiednie prawa do wykonania operacji, i udzielić lub odmówić operacji zgodnie z potrzebami. Na szczęście w przypadku deweloperów systemu plików większość mechanizmu decyzyjnego jest implementowana w monitorze referencyjnym zabezpieczeń. W związku z tym w większości przypadków system plików musi wywołać tylko odpowiednie procedury monitora referencyjnego zabezpieczeń, aby prawidłowo określić dostęp. Ryzyko związane z systemem plików występuje, gdy system nie wywołuje tych procedur w razie potrzeby i niewłaściwie udziela dostępu osobie wywołującej.

W przypadku standardowego systemu plików, takiego jak system plików FAT, kontrole wykonywane w ramach IRP_MJ_CREATE są przede wszystkim kontroli semantyki. Na przykład system plików FAT ma wiele kontroli, aby upewnić się, że przetwarzanie IRP_MJ_CREATE jest dozwolone na podstawie stanu pliku lub katalogu. Kontrole wykonywane przez system plików FAT obejmują kontrole nośników przeznaczonych tylko do odczytu (na przykład próby wykonania destrukcyjnych operacji "tworzenia", takich jak nadpisywanie lub wymiana, na nośnikach tylko do odczytu są niedozwolone), kontrole dostępu współdzielonego i kontrole oplock. Jedną z najtrudniejszych części tej analizy jest uświadomienie sobie, że operacja na jednym poziomie (na przykład poziom pliku) może być niedozwolona ze względu na stan innego poziomu zasobu (na przykład poziom woluminu). Na przykład plik może nie zostać otwarty, jeśli inny proces zablokował wolumin wyłącznie. Typowe przypadki sprawdzania obejmują:

  • Czy poziom pliku jest otwarty zgodny ze stanem poziomu woluminu? Trzeba przestrzegać blokady na poziomie woluminu. W związku z tym, jeśli jeden proces przechowuje wyłączną blokadę na poziomie woluminu, tylko wątki w ramach tego procesu mogą otwierać pliki. Wątkom z innych procesów nie wolno pozwalać na otwieranie plików.

  • Czy poziom otwarcia pliku jest zgodny ze stanem nośnika? Niektóre operacje "create" modyfikują plik w ramach operacji "create". Obejmuje to nadpisanie, zastąpienie, a nawet zaktualizowanie czasu ostatniego dostępu do pliku. Operacje „tworzenia” nie są dozwolone na nośnikach tylko do odczytu, a czas ostatniego dostępu nie jest aktualizowany.

  • Czy poziom głośności jest zgodny ze stanem poziomu pliku? Otwarcie woluminu na wyłączność nie byłoby dozwolone, jeśli na woluminie są otwierane istniejące pliki. Jest to typowy problem dla nowych deweloperów, ponieważ próbują otworzyć wolumin i stwierdzają, że się nie udaje. Jeśli to się nie powiedzie, można użyć FSCTL_DISMOUNT_VOLUME do unieważnienia otwartych uchwytów i wymuszenia odmontowania, umożliwiając wyłączny dostęp do nowo zamontowanego woluminu.

Ponadto atrybuty plików muszą być zgodne. Nie można otworzyć pliku z atrybutem tylko do odczytu w celu uzyskania dostępu do zapisu. Należy pamiętać, że żądany dostęp należy sprawdzić po rozszerzeniu i rozwinięciu praw ogólnych. Na przykład to sprawdzenie w systemie plików FASTFAT znajduje się w funkcji FatCheckFileAccess (zobacz plik źródłowy Acchksup.c z przykładowych kodów fastfat zawartych w WDK).

Poniższy przykład kodu jest specyficzny dla semantyki FAT. System plików, który implementuje również listy DACLs, wykonuje dodatkowe sprawdzanie zabezpieczeń przy użyciu procedur monitora odwołań zabezpieczeń (na przykładSeAccessCheck).

    //
    //  check for a read-only Dirent
    //

    if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {

        //
        //  Check the desired access for a read-only Dirent
        // Don't allow 
        //  WRITE, FILE_APPEND_DATA, FILE_ADD_FILE,
        //  FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD
        //

        if (FlagOn(*DesiredAccess, ~(DELETE |
                                     READ_CONTROL |
                                     WRITE_OWNER |
                                     WRITE_DAC |
                                     SYNCHRONIZE |
                                     ACCESS_SYSTEM_SECURITY |
                                     FILE_READ_DATA |
                                     FILE_READ_EA |
                                     FILE_WRITE_EA |
                                     FILE_READ_ATTRIBUTES |
                                     FILE_WRITE_ATTRIBUTES |
                                     FILE_EXECUTE |
                                     FILE_LIST_DIRECTORY |
                                     FILE_TRAVERSE))) {

            DebugTrace(0, Dbg, "Cannot open readonly\n", 0);

            try_return( Result = FALSE );
        }

Bardziej subtelne sprawdzenie zaimplementowane przez FASTFAT polega na upewnieniu się, że dostęp żądany przez obiekt wywołujący odpowiada czemuś, z czego system plików FAT zdaje sobie sprawę (w funkcji FatCheckFileAccess w Acchksup.c z próbki fastfat zawartej w zestawie WDK).

Poniższy przykład kodu przedstawia ważną koncepcję zabezpieczeń systemu plików. Upewnij się, że dane przekazywane do systemu plików nie wykraczają poza granice oczekiwanej wartości. Konserwatywne i właściwe podejście z punktu widzenia zabezpieczeń polega na tym, że jeśli nie rozumiesz żądania dostępu, należy odrzucić to żądanie.

    //
    // Check the desired access for the object. 
    // Reject what we do not understand.
    // The model of file systems using ACLs is that
    // they do not type the ACL to the object that the 
    // ACL is on. 
    // Permissions are not checked for consistency vs.
    // the object type - dir/file.
    //

    if (FlagOn(*DesiredAccess, ~(DELETE |
                                 READ_CONTROL |
                                 WRITE_OWNER |
                                 WRITE_DAC |
                                 SYNCHRONIZE |
                                 ACCESS_SYSTEM_SECURITY |
                                 FILE_WRITE_DATA |
                                 FILE_READ_EA |
                                 FILE_WRITE_EA |
                                 FILE_READ_ATTRIBUTES |
                                 FILE_WRITE_ATTRIBUTES |
                                 FILE_LIST_DIRECTORY |
                                 FILE_TRAVERSE |
                                 FILE_DELETE_CHILD |
                                 FILE_APPEND_DATA))) {

        DebugTrace(0, Dbg, "Cannot open object\n", 0);

        try_return( Result = FALSE );
    }

Na szczęście w przypadku systemów plików po zakończeniu sprawdzania zabezpieczeń podczas początkowego przetwarzania tworzenia kolejne kontrole zabezpieczeń są wykonywane przez menedżera we/wy. Na przykład menedżer we/wy zapewnia, że aplikacje w trybie użytkownika nie wykonują operacji zapisu względem pliku, który został otwarty tylko w celu uzyskania dostępu do odczytu. W rzeczywistości system plików nie powinien próbować wymuszać semantyki tylko do odczytu względem obiektu pliku, nawet jeśli został otwarty tylko do odczytu, podczas procedury wysyłania IRP_MJ_WRITE. Jest to spowodowane tym, że menedżer pamięci kojarzy określony obiekt pliku z danym obiektem sekcji. Kolejne zapisy w tej sekcji będą wysyłane jako operacje IRP_MJ_WRITE na obiekcie pliku, mimo że plik został otwarty tylko do odczytu. Innymi słowy wymuszanie dostępu odbywa się po przekonwertowaniu dojścia pliku do odpowiedniego obiektu pliku w punktach wejścia usługi systemu Nt przez ObReferenceObjectByHandle.

Istnieją dwa dodatkowe miejsca w systemie plików, w których należy przeprowadzić semantyczne kontrole zabezpieczeń podobne do przetwarzania "create":

  • Podczas zmiany nazwy lub przetwarzania twardego łącza.

  • Podczas przetwarzania operacji sterowania systemem plików.

W kolejnych sekcjach omówiono przetwarzanie zmian nazw i przetwarzanie sterowania systemem plików.

Należy pamiętać, że nie jest to wyczerpująca lista problemów semantycznych związanych z przetwarzaniem "create". Celem tej sekcji jest zwrócenie uwagi na te problemy dla deweloperów systemu plików. Wszystkie problemy semantyczne muszą zostać zidentyfikowane dla określonego systemu plików, zaimplementowane w celu spełnienia określonych semantyki i przetestowane w celu zapewnienia, że implementacja obsługuje różne przypadki.