root/sandbox/win/tools/finder/finder_kernel.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. InitNT
  2. ParseKernelObjects
  3. TestKernelObjectAccess
  4. NtGenericOpen
  5. GetFunctionForType

// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/win/src/restricted_token.h"
#include "sandbox/win/src/restricted_token_utils.h"
#include "sandbox/win/tools/finder/finder.h"
#include "sandbox/win/tools/finder/ntundoc.h"

#define BUFFER_SIZE 0x800
#define CHECKPTR(x) if (!x) return ::GetLastError()

// NT API
NTQUERYDIRECTORYOBJECT    NtQueryDirectoryObject;
NTOPENDIRECTORYOBJECT     NtOpenDirectoryObject;
NTOPENEVENT               NtOpenEvent;
NTOPENJOBOBJECT           NtOpenJobObject;
NTOPENKEYEDEVENT          NtOpenKeyedEvent;
NTOPENMUTANT              NtOpenMutant;
NTOPENSECTION             NtOpenSection;
NTOPENSEMAPHORE           NtOpenSemaphore;
NTOPENSYMBOLICLINKOBJECT  NtOpenSymbolicLinkObject;
NTOPENTIMER               NtOpenTimer;
NTOPENFILE                NtOpenFile;
NTCLOSE                   NtClose;

DWORD Finder::InitNT() {
  HMODULE ntdll_handle = ::LoadLibrary(L"ntdll.dll");
  CHECKPTR(ntdll_handle);

  NtOpenSymbolicLinkObject = (NTOPENSYMBOLICLINKOBJECT) ::GetProcAddress(
  ntdll_handle, "NtOpenSymbolicLinkObject");
  CHECKPTR(NtOpenSymbolicLinkObject);

  NtQueryDirectoryObject = (NTQUERYDIRECTORYOBJECT) ::GetProcAddress(
      ntdll_handle, "NtQueryDirectoryObject");
  CHECKPTR(NtQueryDirectoryObject);

  NtOpenDirectoryObject = (NTOPENDIRECTORYOBJECT) ::GetProcAddress(
      ntdll_handle, "NtOpenDirectoryObject");
  CHECKPTR(NtOpenDirectoryObject);

  NtOpenKeyedEvent = (NTOPENKEYEDEVENT) ::GetProcAddress(
      ntdll_handle, "NtOpenKeyedEvent");
  CHECKPTR(NtOpenKeyedEvent);

  NtOpenJobObject = (NTOPENJOBOBJECT) ::GetProcAddress(
      ntdll_handle, "NtOpenJobObject");
  CHECKPTR(NtOpenJobObject);

  NtOpenSemaphore = (NTOPENSEMAPHORE) ::GetProcAddress(
      ntdll_handle, "NtOpenSemaphore");
  CHECKPTR(NtOpenSemaphore);

  NtOpenSection = (NTOPENSECTION) ::GetProcAddress(
      ntdll_handle, "NtOpenSection");
  CHECKPTR(NtOpenSection);

  NtOpenMutant= (NTOPENMUTANT) ::GetProcAddress(ntdll_handle, "NtOpenMutant");
  CHECKPTR(NtOpenMutant);

  NtOpenEvent = (NTOPENEVENT) ::GetProcAddress(ntdll_handle, "NtOpenEvent");
  CHECKPTR(NtOpenEvent);

  NtOpenTimer = (NTOPENTIMER) ::GetProcAddress(ntdll_handle, "NtOpenTimer");
  CHECKPTR(NtOpenTimer);

  NtOpenFile = (NTOPENFILE) ::GetProcAddress(ntdll_handle, "NtOpenFile");
  CHECKPTR(NtOpenFile);

  NtClose = (NTCLOSE) ::GetProcAddress(ntdll_handle, "NtClose");
  CHECKPTR(NtClose);

  return ERROR_SUCCESS;
}

DWORD Finder::ParseKernelObjects(ATL::CString path) {
  UNICODE_STRING unicode_str;
  unicode_str.Length = (USHORT)path.GetLength()*2;
  unicode_str.MaximumLength = (USHORT)path.GetLength()*2+2;
  unicode_str.Buffer = path.GetBuffer();

  OBJECT_ATTRIBUTES path_attributes;
  InitializeObjectAttributes(&path_attributes,
                             &unicode_str,
                             0,      // No Attributes
                             NULL,   // No Root Directory
                             NULL);  // No Security Descriptor


  DWORD object_index = 0;
  DWORD data_written = 0;

  // TODO(nsylvain): Do not use BUFFER_SIZE. Try to get the size
  // dynamically.
  OBJDIR_INFORMATION *object_directory_info =
    (OBJDIR_INFORMATION*) ::HeapAlloc(GetProcessHeap(),
                                      0,
                                      BUFFER_SIZE);

  HANDLE file_handle;
  NTSTATUS status_code = NtOpenDirectoryObject(&file_handle,
                                               DIRECTORY_QUERY,
                                               &path_attributes);
  if (status_code != 0)
    return ERROR_UNIDENTIFIED_ERROR;

  status_code = NtQueryDirectoryObject(file_handle,
                                       object_directory_info,
                                       BUFFER_SIZE,
                                       TRUE, // Get Next Index
                                       TRUE, // Ignore Input Index
                                       &object_index,
                                       &data_written);

  if (status_code != 0)
    return ERROR_UNIDENTIFIED_ERROR;

  while (NtQueryDirectoryObject(file_handle, object_directory_info,
                                BUFFER_SIZE, TRUE, FALSE, &object_index,
                                &data_written) == 0 ) {
    ATL::CString cur_path(object_directory_info->ObjectName.Buffer,
        object_directory_info->ObjectName.Length / sizeof(WCHAR));

    ATL::CString cur_type(object_directory_info->ObjectTypeName.Buffer,
        object_directory_info->ObjectTypeName.Length / sizeof(WCHAR));

    ATL::CString new_path;
    if (path == L"\\") {
      new_path =  path + cur_path;
    } else {
      new_path = path + L"\\" + cur_path;
    }

    TestKernelObjectAccess(new_path, cur_type);

    // Call the function recursively for all subdirectories
    if (cur_type == L"Directory") {
      ParseKernelObjects(new_path);
    }
  }

  NtClose(file_handle);
  return ERROR_SUCCESS;
}

DWORD Finder::TestKernelObjectAccess(ATL::CString path, ATL::CString type) {
  Impersonater impersonate(token_handle_);

  kernel_object_stats_[PARSE]++;

  NTGENERICOPEN func = NULL;
  GetFunctionForType(type, &func);

  if (!func) {
    kernel_object_stats_[BROKEN]++;
    Output(OBJ_ERR, type + L" Unsupported", path);
    return ERROR_UNSUPPORTED_TYPE;
  }

  UNICODE_STRING unicode_str;
  unicode_str.Length =  (USHORT)path.GetLength()*2;
  unicode_str.MaximumLength = (USHORT)path.GetLength()*2+2;
  unicode_str.Buffer = path.GetBuffer();

  OBJECT_ATTRIBUTES path_attributes;
  InitializeObjectAttributes(&path_attributes,
                             &unicode_str,
                             0,      // No Attributes
                             NULL,   // No Root Directory
                             NULL);  // No Security Descriptor

  HANDLE handle;
  NTSTATUS status_code = 0;

  if (access_type_ & kTestForAll) {
    status_code = NtGenericOpen(GENERIC_ALL, &path_attributes, func, &handle);
    if (STATUS_SUCCESS == status_code) {
      kernel_object_stats_[ALL]++;
      Output(OBJ, L"R/W", path);
      NtClose(handle);
      return GENERIC_ALL;
    } else if (status_code != EXCEPTION_ACCESS_VIOLATION &&
               status_code != STATUS_ACCESS_DENIED) {
      Output(OBJ_ERR, status_code, path);
      kernel_object_stats_[BROKEN]++;
    }
  }

  if (access_type_ & kTestForWrite) {
    status_code = NtGenericOpen(GENERIC_WRITE, &path_attributes, func, &handle);
    if (STATUS_SUCCESS == status_code) {
      kernel_object_stats_[WRITE]++;
      Output(OBJ, L"W", path);
      NtClose(handle);
      return GENERIC_WRITE;
    } else if (status_code != EXCEPTION_ACCESS_VIOLATION &&
               status_code != STATUS_ACCESS_DENIED) {
      Output(OBJ_ERR, status_code, path);
      kernel_object_stats_[BROKEN]++;
    }
  }

  if (access_type_ & kTestForRead) {
    status_code = NtGenericOpen(GENERIC_READ, &path_attributes, func, &handle);
    if (STATUS_SUCCESS == status_code) {
      kernel_object_stats_[READ]++;
      Output(OBJ, L"R", path);
      NtClose(handle);
      return GENERIC_READ;
    } else if (status_code != EXCEPTION_ACCESS_VIOLATION &&
               status_code != STATUS_ACCESS_DENIED) {
      Output(OBJ_ERR, status_code, path);
      kernel_object_stats_[BROKEN]++;
    }
  }

  return 0;
}

NTSTATUS Finder::NtGenericOpen(ACCESS_MASK desired_access,
                               OBJECT_ATTRIBUTES *object_attributes,
                               NTGENERICOPEN func_to_call,
                               HANDLE *handle) {
  return func_to_call(handle, desired_access, object_attributes);
}

bool Finder::GetFunctionForType(ATL::CString type,
                                NTGENERICOPEN * func_to_call) {
  NTGENERICOPEN func = NULL;

  if (type == L"Event")             func = NtOpenEvent;
  else if (type == L"Job")          func = NtOpenJobObject;
  else if (type == L"KeyedEvent")   func = NtOpenKeyedEvent;
  else if (type == L"Mutant")       func = NtOpenMutant;
  else if (type == L"Section")      func = NtOpenSection;
  else if (type == L"Semaphore")    func = NtOpenSemaphore;
  else if (type == L"Timer")        func = NtOpenTimer;
  else if (type == L"SymbolicLink") func = NtOpenSymbolicLinkObject;
  else if (type == L"Directory")    func = NtOpenDirectoryObject;

  if (func) {
    *func_to_call = func;
    return true;
  }

  return false;
}

/* [<][>][^][v][top][bottom][index][help] */