Closed Bug 518435 Opened 11 years ago Closed 11 years ago

xpcshell crashes when registering components on x86-64 Leopard


(Core :: XPCOM, defect)

Not set





(Reporter: joelr, Assigned: joelr)




(2 files, 1 obsolete file)

From the Apple Insider [1]

Security in 64-bit Snow Leopard

In addition to expanded sandboxing, the move to 64-bit computing will provide a series of other benefits related to security. Apple's 64-bit binaries set all writable memory as non-executable by default, including thread stacks, the heap, and any other writable data segments. 

This is already present to an extent in today's Leopard Server, which runs some services, such as the Apache web server, as 64-bit processes. Using the vmmap command reveals that no memory allocated by these 64-bit apps is both writable and executable. On 32-bit Intel systems, while no memory is marked as both writable and executable, the legacy x86 processor design does not enforce the permissions bits, but 64-bit CPUs do. This feature prevents exploits from injecting malicious executable code into memory and tricking the app to run it as it if were its own instructions. 

This results in a crash when running xpcshell, e.g.

Starting program: /Users/joelr/Work/mozilla/debug/dist/bin/xpcshell 
warning: Trying to remove a section from the ordered section list that did not exist at 0x51eb851ed41000.
Reading symbols for shared libraries .++++++++++++..................................................................................................... done
*** Registering components in: xpconnect

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x0000000101e2e078
0x0000000101e2e078 in nsXPTCStubBase::Stub5 ()
(gdb) where
#0  0x0000000101e2e078 in nsXPTCStubBase::Stub5 ()
#1  0x000000010154e65f in ~nsFixedString [inlined] () at ../../../mozilla-central/xpcom/components/nsCategoryManager.cpp:547
#2  0x000000010154e65f in ~nsString [inlined] () at ../../../mozilla-central/xpcom/components/nsCategoryManager.cpp:479
#3  0x000000010154e65f in ~nsAutoString [inlined] () at ../../../mozilla-central/xpcom/components/nsCategoryManager.cpp:429
#4  0x000000010154e65f in ~NS_ConvertUTF8toUTF16 [inlined] () at /Users/joelr/Work/mozilla/debug/dist/include/nsString.h:168
#5  0x000000010154e65f in nsCategoryManager::NotifyObservers (this=<value temporarily unavailable, due to optimizations>, aTopic=0x1017e31be "xpcom-category-entry-added", aCategoryName=0x1017b1a9d "module-loader", aEntryName=<value temporarily unavailable, due to optimizations>) at ../../../mozilla-central/xpcom/components/nsCategoryManager.cpp:547
#6  0x000000010154fe31 in nsCategoryManager::AddCategoryEntry (this=0x103a00020, aCategoryName=0x1017b1a9d "module-loader", aEntryName=0x101861258 "text/javascript", aValue=0x1017ad1c7 ";1", aPersist=1, aReplace=1, _retval=0x7fff5fbfed48) at ../../../mozilla-central/xpcom/components/nsCategoryManager.cpp:625
#7  0x00000001000a2bca in RegisterJSLoader (aCompMgr=<value temporarily unavailable, due to optimizations>, aPath=<value temporarily unavailable, due to optimizations>, registryLocation=<value temporarily unavailable, due to optimizations>, componentType=<value temporarily unavailable, due to optimizations>, info=<value temporarily unavailable, due to optimizations>) at mozJSLoaderConstructors.h:70
#8  0x00000001014ee1bf in nsGenericModule::RegisterSelf (this=0x103a001e0, aCompMgr=0x103917100, aPath=0x0, registryLocation=0x1017a8a90 "xpconnect", componentType=0x1018d1768 "application/x-mozilla-static") at nsGenericFactory.cpp:420
#9  0x0000000101551aca in RegisterStaticModule (key=0x1017a8a90 "xpconnect", module=<value temporarily unavailable, due to optimizations>, deferred=@0x7fff5fbff080) at ../../../mozilla-central/xpcom/components/nsComponentManager.cpp:3255
#10 0x0000000101561eee in nsStaticModuleLoader::EnumerateModules (this=<value temporarily unavailable, due to optimizations>, cb=0x101551a90 <RegisterStaticModule(char const*, nsIModule*, nsTArray<DeferredModule>&)>, deferred=@0x7fff5fbff080) at ../../../mozilla-central/xpcom/components/nsStaticComponentLoader.cpp:141
#11 0x0000000101558bbf in nsComponentManagerImpl::AutoRegister (this=0x103917100, aSpec=0x0) at ../../../mozilla-central/xpcom/components/nsComponentManager.cpp:3298
#12 0x00000001014f472a in NS_InitXPCOM3_P (result=0x7fff5fbff330, binDirectory=<value temporarily unavailable, due to optimizations>, appFileLocationProvider=0x7fff5fbff280, staticComponents=<value temporarily unavailable, due to optimizations>, componentCount=48) at ../../../mozilla-central/xpcom/build/nsXPComInit.cpp:692
#13 0x00000001000040f8 in main (argc=1, argv=0x7fff5fbff3c0, envp=0x7fff5fbff3d0) at ../../../../../mozilla-central/js/src/xpconnect/shell/xpcshell.cpp:1631
Blocks: 468509
Assignee: general → joelr
Indeed, I hit this last night - called mprotect() from GDB and the process started up fine.

But the code didn't look dynamically generated... it was sitting in an asm() block that had a ".section text" line. So I'm not sure what's needed there, if I was even reading the right place.
How did you tell from gdb that it was an asm() block with a .section text line?
Summary: mprotect should be used on x86-64 Leopard to mark JIT data pages as executable → xpcshell crashes when registering components on x86-64 Leopard
Component: JavaScript Engine → XPCOM
QA Contact: general → xpcom
0000000001dfc078 S __ZN14nsXPTCStubBase5Stub5Ev
0000000001dfc294 S __ZN14nsXPTCStubBase6Stub50Ev
Here's the issue...

On Leopard x86-32 the stubs are local and belonging to the text segment:

nm XUL|grep Stub5
00c1c3c0 t __ZN14nsXPTCStubBase5Stub5Ev
00c1cc30 t __ZN14nsXPTCStubBase6Stub50Ev
00c1cc60 t __ZN14nsXPTCStubBase6Stub51Ev
00c1cc90 t __ZN14nsXPTCStubBase6Stub52Ev
00c1ccc0 t __ZN14nsXPTCStubBase6Stub53Ev
00c1ccf0 t __ZN14nsXPTCStubBase6Stub54Ev
00c1cd20 t __ZN14nsXPTCStubBase6Stub55Ev
00c1cd50 t __ZN14nsXPTCStubBase6Stub56Ev
00c1cd80 t __ZN14nsXPTCStubBase6Stub57Ev
00c1cdb0 t __ZN14nsXPTCStubBase6Stub58Ev
00c1cde0 t __ZN14nsXPTCStubBase6Stub59Ev

On x86-64 Snow Leopard, and on Leopard I'm sure, the stubs belong to the "other" segment, one that's neither code, data or any other standard segment:

0000000001dfc2a0 S __ZN14nsXPTCStubBase6Stub51Ev
0000000001dfc2ac S __ZN14nsXPTCStubBase6Stub52Ev
0000000001dfc2b8 S __ZN14nsXPTCStubBase6Stub53Ev
0000000001dfc2c4 S __ZN14nsXPTCStubBase6Stub54Ev
0000000001dfc2d0 S __ZN14nsXPTCStubBase6Stub55Ev
0000000001dfc2dc S __ZN14nsXPTCStubBase6Stub56Ev
0000000001dfc2e8 S __ZN14nsXPTCStubBase6Stub57Ev
0000000001dfc2f4 S __ZN14nsXPTCStubBase6Stub58Ev
0000000001dfc300 S __ZN14nsXPTCStubBase6Stub59Ev

What segment do the stubs belong to on x86-64 Leopard?

Load command 2
      cmd LC_SEGMENT_64
  cmdsize 152
  segname ".text"
   vmaddr 0x0000000001dfc000
   vmsize 0x0000000000001000
  fileoff 31350784
 filesize 4096
  maxprot 0x00000007
 initprot 0x00000003
   nsects 1
    flags 0x0
  sectname regular
   segname ".text"
      addr 0x0000000001dfc000
      size 0x0000000000000bf2
    offset 31350784
     align 2^2 (4)
    reloff 0
    nreloc 0
     flags 0x00000000
 reserved1 0
 reserved2 0

What does the text segment look like?

Load command 0
      cmd LC_SEGMENT_64
  cmdsize 712
  segname __TEXT
   vmaddr 0x0000000000000000
   vmsize 0x0000000001c3d000
  fileoff 0
 filesize 29609984
  maxprot 0x00000007
 initprot 0x00000005
   nsects 8
    flags 0x0
  sectname __text
   segname __TEXT
      addr 0x0000000000001f80
      size 0x00000000016583a0
    offset 8064
     align 2^4 (16)
    reloff 0
    nreloc 0
     flags 0x80000400
 reserved1 0
 reserved2 0

These are the page protection flags on Mac OSX:

#define PROT_NONE       0x00    /* [MC2] no permissions */
#define PROT_READ       0x01    /* [MC2] pages can be read */
#define PROT_WRITE      0x02    /* [MC2] pages can be written */
#define PROT_EXEC       0x04    /* [MC2] pages can be executed */

Note that initial protection (initprot) for the text segment pages is 5 (READ+EXEC) whereas on the stub segment it's 3 (READ+WRITE). Maximum protection on the stub segment is 7 (READ+WRITE+EXEC) which is why David was able to call mprotect to set the stubs as executable.

I just need to fix the stubs asm() block in to produce a __TEXT, __text section and we'll be done.
I think .align 2 in this case is a 4 byte alignment, at least according to the .align section of the GNU ASM manual [1]:

For other systems, including the i386 using a.out format, and the arm and strongarm, it is the number of low-order zero bits the location counter must have after advancement. For example .align 3 advances the location counter until it a multiple of 8. If the location counter is already a multiple of 8, no change is needed. 

If we are aligning to 32 bits on x86-32 then we should probably align to 64 bits on x86-64. Right?

Attachment #402460 - Flags: review?(benjamin)
Attached patch Align to 64 bitsSplinter Review
Forgot to adjust alignment, fixed now.
Attachment #402460 - Attachment is obsolete: true
Attachment #402460 - Flags: review?(benjamin)
Attachment #402463 - Flags: review?(benjamin)
I also forgot to say that I now have Firefox x86-64 up and running on Snow Leopard.
Attachment #402463 - Flags: review?(benjamin) → review+
Keywords: checkin-needed
Keywords: checkin-needed
Hardware: x86 → x86_64
Precisely the same patch as reviewed by :bs, just properly formatted.
pushed to mozilla-central
Closed: 11 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.