FoxPro on FreeBSD

Kevin Day toasty at dragondata.com
Thu Oct 24 06:37:55 UTC 2013


On Oct 24, 2013, at 12:54 AM, Xin Li <delphij at delphij.net> wrote:

> Signed PGP part
> On 10/23/13, 8:32 PM, Kevin Day wrote:
> > I did some debugging, and watched how the process was getting
> > launched, and I've managed to get it to load!
> > 
> > The problem was that COFF files expect to be mapped into memory at
> > address 0, something that processes are no longer allowed to do.
> > 
> > Run "sysctl security.bsd.map_at_zero=1”  or add
> > “security.bsd.map_at_zero=1“ to /etc/sysctl.conf and you should
> > have it working. We probably should either make an exception for
> > COFF files to bypass this the sysctl restriction, or at least print
> > a more helpful error than just letting the process segfault because
> > it didn’t get mapped where it was supposed to go.
> 
> Wow, this is impressive find, indeed!  Do they need to do the map at
> startup only, or do they want to explicitly map something at address 0
> during runtime?

It’s the COFF loader in sys/i386/ibcs2 that’s attempting to do this, with some debug printing enabled on the ibcs2 module, you can see the layout of the binary:

i = 0, s_name = .text, s_vaddr = 000000d0, s_scnptr = 208 s_size = 1f9260
i = 1, s_name = .data, s_vaddr = 00400330, s_scnptr = 2069296 s_size = 10598
i = 2, s_name = .bss, s_vaddr = 004108c8, s_scnptr = 0 s_size = 1ebb0
i = 3, s_name = .comment, s_vaddr = 00000000, s_scnptr = 2136264 s_size = feb4

which maps to these calls:

vm_mmap(&vmspace->vm_map, &0x00000000, 0x1fa000, 0x5, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, 0x0)
vm_mmap(&vmspace->vm_map, &0x00400000, 0x10000, 0x7, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, 0x1f9000)
vm_map_find(&vmspace->vm_map, NULL, 0, &0x00410000,0x20000, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0)
vm_map_find(&vmspace->vm_map, NULL, 0, &0x430000, PAGE_SIZE, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0)

Nothing is returning any errors, but the .text session isn’t getting mapped to the desired location (0x0). If map_at_zero is set to 0, the process’s vm_map has min_offset set to PAGE_SIZE instead of 0. 

What’s actually happening is pretty subtle. if MAP_FIXED is set, vm_mmap() uses vm_map_fixed() to create the mapping. Inside vm_map_fixed(), it uses vm_map_insert() which would properly error out that this mapping is impossible (we want 0x0, but the process’s vm_map.min_offset is 0x1000), but vm_map_fixed() calls VM_MAP_RANGE_CHECK first:

        VM_MAP_RANGE_CHECK(map, start, end);
        (void) vm_map_delete(map, start, end);
        result = vm_map_insert(map, object, offset, start, end, prot,

VM_MAP_RANGE_CHECK does:

                if (start < vm_map_min(map))            \
                        start = vm_map_min(map);        \

which looks like the wrong thing to do here. vm_mmap() thinks it’s requesting 0x0 through 0x1fa000, but now the request just silently got changed to 0x1000 through 0x1fa000.

So what the ibcs2 module thinks .text is being loaded at 0, ends up being loaded at 0x1000, and is 0x1000 bytes too small.  It then jumps to the wrong starting address, and the process crashes. 

Also to clarify my original posting, COFF itself isn’t the issue here, just that this specific binary wants its .text section to begin at a virtual address below 0x1000. 

— Kevin


-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 4891 bytes
Desc: not available
URL: <http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20131024/d5e269c8/attachment.bin>


More information about the freebsd-hackers mailing list