簡體   English   中英

運行在10.6到10.9的OS X應用程序不能在10.10(約塞米蒂)上運行 - 為什么?

[英]OS X app that runs on 10.6 to 10.9 doesn't run on 10.10 (Yosemite) — why?

一年多以來,我一直在使用XCode 4.5使用OS X 10.7 sdk構建應用程序,目標部署為10.6。

該應用程序在10.6,10.7,10.8和10.9上運行良好。 但是當我在10.10上運行它時,我在控制台中收到一條消息,說“該應用程序無法強制執行硬頁面零”。

谷歌搜索“不能強制執行硬頁面零”返回沒有任何幫助。

有誰知道這意味着什么?

一個有用的信息是使用XCode 5構建應用程序不會導致問題,所以我認為它與舊的XCode 4.5有關。

如果它是一個簡單的解決方案,我寧願堅持使用較舊的XCode,因為如果我不需要,我會猶豫是否轉移到XCode 5。

非常感謝任何見解。

編輯1:我發現以32位模式打開應用程序可以在Yosemite上運行。 所以它只有64位模式才有問題。

編輯2:這是Ken要求的otool的輸出:

Load command 0
      cmd LC_SEGMENT_64
  cmdsize 72
  segname __TEXT
   vmaddr 0x00000001007f9000
   vmsize 0x0000000000225dba
  fileoff 0
 filesize 2251422
  maxprot rwx
 initprot rwx
   nsects 0
    flags (none)
Load command 1
        cmd LC_UNIXTHREAD
    cmdsize 184
     flavor x86_THREAD_STATE64
      count x86_THREAD_STATE64_COUNT
   rax  0x0000000000000000 rbx 0x0000000000000000 rcx  0x0000000000000000
   rdx  0x0000000000000000 rdi 0x0000000000000000 rsi  0x0000000000000000
   rbp  0x0000000000000000 rsp 0x0000000000000000 r8   0x0000000000000000
    r9  0x0000000000000000 r10 0x0000000000000000 r11  0x0000000000000000
   r12  0x0000000000000000 r13 0x0000000000000000 r14  0x0000000000000000
   r15  0x0000000000000000 rip 0x0000000100a1e3d8
rflags  0x0000000000000000 cs  0x0000000000000000 fs   0x0000000000000000
    gs  0x0000000000000000

來自OS X 10.10的Apple內核(xnu)現在強制實施“硬頁面零”,而過去並非如此。 請注意,此要求僅適用於64位MachO可執行文件。

通過確保存在__PAGEZERO段,您的應用程序將解決該問題。 重要的是,此__PAGEZERO段必須具有0x0(NULL)的vmaddr和至少0x1000的vmsize。 實際上並不需要該段的特定名稱“__PAGEZERO”,但大多數編譯器將以這種方式使用它。

一個硬(有限的權限)PAGEZERO使得很難利用NULL deference軟件漏洞。

來自xnu源代碼的以下代碼片段解釋了:

// From xnu-2782.1.97/bsd/kern/mach_loader.c
load_return_t
load_machfile(
    struct image_params *imgp,
    struct mach_header  *header,
    thread_t        thread,
    vm_map_t        new_map,
    load_result_t       *result
)
{
    ...
    boolean_t enforce_hard_pagezero = TRUE;
    ...
    // Second vm_map_create() argument sets map->min_offset to zero.
    map = vm_map_create(pmap,
            0,
            vm_compute_max_offset((imgp->ip_flags & IMGPF_IS_64BIT)),
            TRUE);
    ...
    #if __x86_64__
    /*
     * On x86, for compatibility, don't enforce the hard page-zero restriction for 32-bit binaries.
     */         
    if ((imgp->ip_flags & IMGPF_IS_64BIT) == 0) {
        enforce_hard_pagezero = FALSE;
    }
    #endif
    /*
     * Check to see if the page zero is enforced by the map->min_offset.
     */
    // Note: vm_map_has_hard_pagezero(map, 0x1000) checks if map->min_offset >= 0x1000
    // Refer xnu-2782.1.97/osfmk/vm/vm_map.c
    if (enforce_hard_pagezero && (vm_map_has_hard_pagezero(map, 0x1000) == FALSE)) {
        if (create_map) {
            vm_map_deallocate(map); /* will lose pmap reference too */
        }
        printf("Cannot enforce a hard page-zero for %s\n", imgp->ip_strings);
        return (LOAD_BADMACHO);
    }

在段加載代碼中將map-> min_offset提升到零以上:

// From xnu-2782.1.97/bsd/kern/mach_loader.c
static
load_return_t
load_segment(
    struct load_command     *lcp,
    uint32_t            filetype,
    void *              control,
    off_t               pager_offset,
    off_t               macho_size,
    struct vnode            *vp,
    vm_map_t            map,
    int64_t             slide,
    load_result_t       *result
)
{
...
/*
 *  Round sizes to page size.
 */
seg_size = round_page_64(scp->vmsize);
map_size = round_page_64(scp->filesize);
map_addr = trunc_page_64(scp->vmaddr); /* JVXXX note that in XNU TOT this is round instead of trunc for 64 bits */

seg_size = vm_map_round_page(seg_size, vm_map_page_mask(map));
map_size = vm_map_round_page(map_size, vm_map_page_mask(map));

...
// This if test is key, checking for a 0x0 vmaddr, vmsize, and initprot and maxprot
// memory protections. 
// Note a segment name of "__PAGEZERO" is not actually required.
if (map_addr == 0 &&
    map_size == 0 &&
    seg_size != 0 &&
    (scp->initprot & VM_PROT_ALL) == VM_PROT_NONE &&
    (scp->maxprot & VM_PROT_ALL) == VM_PROT_NONE) {
    /*
     * For PIE, extend page zero rather than moving it.  Extending
     * page zero keeps early allocations from falling predictably
     * between the end of page zero and the beginning of the first
     * slid segment.
     */
    seg_size += slide;
    slide = 0;

    /*
     * This is a "page zero" segment:  it starts at address 0,
     * is not mapped from the binary file and is not accessible.
     * User-space should never be able to access that memory, so
     * make it completely off limits by raising the VM map's
     * minimum offset.
     */
    ret = vm_map_raise_min_offset(map, seg_size);


// From xnu-2782.1.97/osfmk/vm/vm_map.c
/*
 * Raise a VM map's minimum offset.
 * To strictly enforce "page zero" reservation.
 */
kern_return_t
vm_map_raise_min_offset(
    vm_map_t    map,
    vm_map_offset_t new_min_offset)
{
...
}

至於為什么你的老Xcode 4.x沒有設置它,它似乎很奇怪 - 也許有一個項目文件設置,但clang編譯器和鏈接器的版本附帶更新的Xcode 5(甚至Xcode 6)應該更接近地反映現代OS X 10.10內核的要求。

注意:早期iOS版本中存在一種硬頁面零強制執行形式,但之前在OS X中沒有。

Valgrind是一個工具套件,它提供了許多調試和分析工具,可以幫助您更快,更正確地運行程序,這也遇到了這個新的OS X 10.10內核要求的相關問題: https//bugs.kde.org/ show_bug.cgi?ID = 339045

我遇到了一個非常類似的問題。 otool -lV顯示了類似的段結構。 我發現這個問題實際上是由使用UPX(3.08)的可執行打包引起的。 如果您已將UPX應用於二進制文件,請運行upx -d解壓縮二進制文件並嘗試再次在Yosemite上運行它。 我剛剛提交的錯誤報告中描述了我的問題的相關討論:

https://sourceforge.net/p/upx/bugs/238/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM