Pregunta

Yo estaba pensando en probar mi mano en algún compilataion JIT (justo por el bien de aprendizaje) y sería bueno tener que funcione multiplataforma ya que corro todos los principales tres en casa (Windows, OS X, Linux) . Con esto en mente, me gustaría saber si hay alguna manera de salir de la utilización de las funciones de las ventanas de memoria virtual para asignar memoria con permisos de ejecución. Sería bueno usar solo o malloc nuevo y apuntar con el procesador a un bloque de este tipo.

¿Algún consejo?

¿Fue útil?

Solución

Una posibilidad es que sea un requisito de que las instalaciones de Windows ejecutar el programa o bien ser configurado para DEP AlwaysOff (mala idea) o DEP OptOut (mejor idea).

Esto se puede configurar (bajo WinXP SP2 + y + SP1 Win2k3 al menos) cambiando el archivo boot.ini para tener la configuración:

/noexecute=OptOut

y después de configurar el programa individual de optar por la elección (en XP):

Start button
    Control Panel
        System
            Advanced tab
                Performance Settings button
                    Data Execution Prevention tab

Esto debería permitirle ejecutar código de su programa de que se crea sobre la marcha en los bloques malloc().

Tenga en cuenta que esto hace que su programa sea más susceptible a los ataques que el DEP estaba destinado a prevenir.

Parece que esto también es posible en Windows 2008 con el comando:

bcdedit.exe /set {current} nx OptOut

Pero, para ser honesto, si lo que desea reducir al mínimo el código dependiente de la plataforma, eso es fácil de hacer simplemente aislando el código en una sola función, algo como:

void *MallocWithoutDep(size_t sz) {
    #if defined _IS_WINDOWS
        return VirtualMalloc(sz, OPT_DEP_OFF); // or whatever
    #elif defined IS_LINUX
        // Do linuxy thing
    #elif defined IS_MACOS
        // Do something almost certainly inexplicable
    #endif
}

Si usted pone todas sus funciones dependientes de la plataforma en sus propios archivos, el resto de su código es independiente de la plataforma de forma automática.

Otros consejos

DEP se acaba apagando el permiso de ejecución de cada página no código de la memoria. El código de aplicación se carga en la memoria que tiene permiso de ejecución; y hay gran cantidad de equipos conjuntos de investigación que trabaja en Windows / Linux / MacOSX, incluso cuando DEP está activo. Esto es porque no es una manera de asignar dinámicamente memoria con el conjunto de permisos necesarios.

Por lo general, malloc llanura no se debe utilizar, porque los permisos son por página. Alineación de la memoria malloced a páginas todavía es posible a un precio de cierta sobrecarga. Si no va a utilizar malloc, algunos de gestión de memoria a medida (sólo para el código ejecutable). gestión personalizada es una forma común de hacer JIT.

Hay una solución a partir de proyectos de cromo, que utiliza JIT JavaScript V8 máquina virtual y que es multiplataforma. Para ser multiplataforma, la función necesaria se implementa en varios archivos y que se seleccionan en tiempo de compilación.

Linux: (cromo src / V8 / src / platform-linux.cc) bandera es PROT_EXEC de mmap ()

.
void* OS::Allocate(const size_t requested,
                   size_t* allocated,
                   bool is_executable) {
  const size_t msize = RoundUp(requested, AllocateAlignment());
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
  void* addr = OS::GetRandomMmapAddr();
  void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (mbase == MAP_FAILED) {
    /** handle error */
    return NULL;
  }
  *allocated = msize;
  UpdateAllocatedSpaceLimits(mbase, msize);
  return mbase;
}

Win32 (src / V8 / src / platform-win32.cc): flag es PAGE_EXECUTE_READWRITE de VirtualAlloc

void* OS::Allocate(const size_t requested,
                   size_t* allocated,
                   bool is_executable) {
  // The address range used to randomize RWX allocations in OS::Allocate
  // Try not to map pages into the default range that windows loads DLLs
  // Use a multiple of 64k to prevent committing unused memory.
  // Note: This does not guarantee RWX regions will be within the
  // range kAllocationRandomAddressMin to kAllocationRandomAddressMax
#ifdef V8_HOST_ARCH_64_BIT
  static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
  static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000;
#else
  static const intptr_t kAllocationRandomAddressMin = 0x04000000;
  static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000;
#endif

  // VirtualAlloc rounds allocated size to page size automatically.
  size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
  intptr_t address = 0;

  // Windows XP SP2 allows Data Excution Prevention (DEP).
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;

  // For exectutable pages try and randomize the allocation address
  if (prot == PAGE_EXECUTE_READWRITE &&
      msize >= static_cast<size_t>(Page::kPageSize)) {
    address = (V8::RandomPrivate(Isolate::Current()) << kPageSizeBits)
      | kAllocationRandomAddressMin;
    address &= kAllocationRandomAddressMax;
  }

  LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address),
                              msize,
                              MEM_COMMIT | MEM_RESERVE,
                              prot);
  if (mbase == NULL && address != 0)
    mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);

  if (mbase == NULL) {
    LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed"));
    return NULL;
  }

  ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment()));

  *allocated = msize;
  UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize));
  return mbase;
}

MacOS (src / V8 / src / platform-macos.cc): bandera es PROT_EXEC de MMAP, al igual que Linux u otro POSIX

.
void* OS::Allocate(const size_t requested,
                   size_t* allocated,
                   bool is_executable) {
  const size_t msize = RoundUp(requested, getpagesize());
  int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
  void* mbase = mmap(OS::GetRandomMmapAddr(),
                     msize,
                     prot,
                     MAP_PRIVATE | MAP_ANON,
                     kMmapFd,
                     kMmapFdOffset);
  if (mbase == MAP_FAILED) {
    LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
    return NULL;
  }
  *allocated = msize;
  UpdateAllocatedSpaceLimits(mbase, msize);
  return mbase;
}

Y también quiero señalar, de esa manera bcdedit.exe-como debe ser utilizado sólo para los programas de edad muy avanzada, lo que crea nuevo código ejecutable en la memoria, pero no fija una propiedad Exec en esta página. Para los programas más nuevos, como Firefox o Chrome / Chromium, o cualquier JIT moderna, DEP debe estar activo, y JIT administrar los permisos de memoria en forma de grano fino.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top