Crashing in sandbox-exec (FB16964888)

Why are we doing this nonsense?

We want to be able to run builds in a sandbox such that they can only see the paths they are intended to depend on, to improve reproducibility. With builds with a very large number of dependencies, there's a very large number of paths added to the sandbox, and it breaks things inside libsandbox.

Either it hits some sandbox length limit (sandbox-exec: pattern serialization length 66460 exceeds maximum (65535), Nix issue #4119, worked around: Nix PR 12570), or it hits an assert (this report; also Nix issue #2311).

The other options for sandboxing on macOS are not viable; we acknowledge sandbox-exec and sandbox_init_with_parameters are deprecated; App Sandbox is inapplicable because we aren't an app. Our use case is closer to a browser, and all the browsers use libsandbox internally.

We could possibly use SystemExtension or a particularly diabolical use of Virtualization.framework, but the former API requires notarization which is close to a no-go for our use case as open source software: it is nearly impossible to develop the software on one's own computer, and it would require us to ship a binary blob (and have the build processes to produce one in infrastructure completely dissimilar to what we use today); it also requires a bunch of engineering time. Today, we can pretend that code signing/notarization doesn't exist and that we are writing an old-school Unix daemon, because we are one. The latter is absolutely diabolical and hard to implement.

See this saga about the bug we are facing: Nix issue #4119, Nix issue #2311, etc.

What is going wrong

I can't attach the file fail.sb as it is too large (you can view the failing test case at Lix's gerrit, CL 2870) and run this:

$ sandbox-exec -D _GLOBAL_TMP_DIR=/tmp -f fail.sb /bin/sh
Assertion failed: (diff <= INSTR_JUMP_NE_MAX_LENGTH), function push_jne_instr, file serialize.c, line 240.
zsh: abort sandbox-exec -D _GLOBAL_TMP_DIR=/tmp -f fail.sb /bin/sh

Or a stacktrace:

-------------------------------------
Translated Report (Full Report Below)
-------------------------------------

Process:               sandbox-exec [43771]
Path:                  /usr/bin/sandbox-exec
Identifier:            sandbox-exec
Version:               ???
Code Type:             ARM-64 (Native)
Parent Process:        zsh [18718]
Responsible:           iTerm2 [1232]
User ID:               501

Date/Time:             2025-03-21 17:17:57.6542 -0700
OS Version:            macOS 15.3.2 (24D81)
Report Version:        12
Anonymous UUID:        7E0118D6-312C-2449-CC02-25F41EC86EC3

Sleep/Wake UUID:       0628BB12-33D5-4AE7-9952-96FD530B8899

Time Awake Since Boot: 340000 seconds
Time Since Wake:       3871 seconds

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000

Termination Reason:    Namespace SIGNAL, Code 6 Abort trap: 6
Terminating Process:   sandbox-exec [43771]

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	       0x185903720 __pthread_kill + 8
1   libsystem_pthread.dylib       	       0x18593bf70 pthread_kill + 288
2   libsystem_c.dylib             	       0x185848908 abort + 128
3   libsystem_c.dylib             	       0x185847c1c __assert_rtn + 284
4   libsandbox.1.dylib            	       0x189518dcc push_jne_instr + 436
5   libsandbox.1.dylib            	       0x1895184a8 _sb_fsa_serialize + 652
6   libsandbox.1.dylib            	       0x1895211b0 ___sb_fsa_serialize_disjunction_block_invoke.7 + 164
7   libsandbox.1.dylib            	       0x18951884c _sb_fsa_serialize + 1584
8   libsandbox.1.dylib            	       0x189518494 _sb_fsa_serialize + 632
9   libsandbox.1.dylib            	       0x18951819c sb_pattern_serialize + 124
10  libsandbox.1.dylib            	       0x189528320 emit_pattern + 44
11  libsandbox.1.dylib            	       0x189520cd4 emit_instruction + 1860
12  libsandbox.1.dylib            	       0x18952816c __populate_profile_entry_points_block_invoke + 60
13  libsandbox.1.dylib            	       0x18952dd94 sb_policy_iterate_entry_points + 88
14  libsandbox.1.dylib            	       0x189527c74 populate_profile_entry_points + 140
15  libsandbox.1.dylib            	       0x189527ac4 emit_profile + 1212
16  libsandbox.1.dylib            	       0x189505ec8 compile + 7400
17  libsandbox.1.dylib            	       0x1895041ac sandbox_compile_file + 296
18  sandbox-exec                  	       0x1009df8c8 0x1009dc000 + 14536
19  dyld                          	       0x1855bc274 start + 2840


Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x0000000000000000   x2: 0x0000000000000000   x3: 0x0000000000000000
    x4: 0x0000000000000000   x5: 0x000000000000002e   x6: 0x0000000000000000   x7: 0x0000000000000000
    x8: 0xa11e3563fea92d07   x9: 0xa13435621183e547  x10: 0x000000000000000a  x11: 0x0000000000000000
   x12: 0x0000000000000032  x13: 0x0000000138002026  x14: 0x0000000000000002  x15: 0x0000000000000004
   x16: 0x0000000000000148  x17: 0x00000001f78ee2c0  x18: 0x0000000000000000  x19: 0x0000000000000006
   x20: 0x0000000000000103  x21: 0x00000001ef2ac920  x22: 0x0000000100a90000  x23: 0x000000018955dd07
   x24: 0x00000001ece5f000  x25: 0x0000000000000003  x26: 0x0000000000000003  x27: 0x0000000000000663
   x28: 0x000000016f40fc38   fp: 0x000000016f40ed10   lr: 0x000000018593bf70
    sp: 0x000000016f40ecf0   pc: 0x0000000185903720 cpsr: 0x40000000
   far: 0x0000000000000000  esr: 0x56000080  Address size fault

Binary Images:
       0x1009dc000 -        0x1009dffff sandbox-exec (*) <247ee617-2d3b-3972-9802-c478e48112fd> /usr/bin/sandbox-exec
       0x1858fa000 -        0x185934ff7 libsystem_kernel.dylib (*) <eee9d0d3-dffc-37cb-9ced-b27cd0286d8c> /usr/lib/system/libsystem_kernel.dylib
       0x185935000 -        0x185941fff libsystem_pthread.dylib (*) <642faf7a-874e-37e6-8aba-2b0cc09a3025> /usr/lib/system/libsystem_pthread.dylib
       0x1857cf000 -        0x185850ffb libsystem_c.dylib (*) <92699527-645f-3d8d-aed8-1cfb0c034e15> /usr/lib/system/libsystem_c.dylib
       0x189503000 -        0x18955effb libsandbox.1.dylib (*) <42daba39-91ff-35f9-86e0-4e33a5494535> /usr/lib/libsandbox.1.dylib
       0x1855b6000 -        0x185637f3f dyld (*) <398a133c-9bcb-317f-a064-a40d3cea3c0f> /usr/lib/dyld
               0x0 - 0xffffffffffffffff ??? (*) <00000000-0000-0000-0000-000000000000> ???

External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0

VM Region Summary:
ReadOnly portion of Libraries: Total=612.1M resident=0K(0%) swapped_out_or_unallocated=612.1M(100%)
Writable regions: Total=949.8M written=288K(0%) resident=288K(0%) swapped_out=0K(0%) unallocated=949.5M(100%)

                                VIRTUAL   REGION
REGION TYPE                        SIZE    COUNT (non-coalesced)
===========                     =======  =======
Activity Tracing                   256K        1
Kernel Alloc Once                   32K        1
MALLOC                           941.2M       22
MALLOC guard page                   96K        6
STACK GUARD                       56.0M        1
Stack                             8176K        2
VM_ALLOCATE                         16K        1
__AUTH                              35K       14
__AUTH_CONST                       209K       45
__DATA                             215K       41
__DATA_CONST                       160K       45
__DATA_DIRTY                        79K       23
__LINKEDIT                       606.2M        2
__OBJC_RW                         2374K        1
__TEXT                            6068K       47
__TPRO_CONST                       272K        2
owned unmapped memory               16K        1
page table in kernel               288K        1
shared memory                       48K        2
===========                     =======  =======
TOTAL                              1.6G      258

Credits

Full credits to Jade Lovelace (Lix) for writing the above text and filing a bug. This is submitted under FB16964888

Answered by DTS Engineer in 830720022

What you’re doing here is unsupported. While there is a public API for setting up a custom sandbox, albeit a deprecated one, the sandbox programming language (SBPL) has never been documented for third-party use, and thus is not considered API. That’s why everything within <sandbox.h> is deprecated: Without a supported SBPL, the API is effectively useless.

Written by WeetHet in 777509021
all the browsers use libsandbox internally.

Yep. And that raises the subtle question of what “supported” means. I’m using it in the very specific sense that DTS doesn’t support this. From our perspective it’s all considered to be an implementation detail.

Now, plenty of third-party code relies on implementation details, sometimes deliberately but more often accidentally [1]. This is an ongoing binary compatibility concern for our platform engineers. They regularly have to make hard choices between improving the implementation and breaking third-party products. DTS tries not to make this situation worse, and hence our focus on supported APIs.

As to what you should do about this issue.

To start, filing a bug makes sense. It’s possible that the sandbox team will change the implementation to help you out.

Beyond that, you wrote:

Written by WeetHet in 777509021
We could possibly use SystemExtension

You mean an Endpoint Security system extension, right?

Because there are a few other types, and only the ES one seems relevant.

Written by WeetHet in 777509021
App Sandbox is inapplicable because we aren't an app.

True, but there’s definitely a trade-off to be made here. App Sandbox can be used by non-app code, and you have to balance the risks of that against the risks of relying on SBPL. So, yeah, I definitely think you should explore that option in more depth.

Although I’m not sure it’ll actually help. App Sandbox relies on the same underlying sandbox implementation, so it might well run into the same limits. However, I think it’s worth the time creating a quick prototype, just to be sure.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] And hence Hyrum’s law.

What you’re doing here is unsupported. While there is a public API for setting up a custom sandbox, albeit a deprecated one, the sandbox programming language (SBPL) has never been documented for third-party use, and thus is not considered API. That’s why everything within <sandbox.h> is deprecated: Without a supported SBPL, the API is effectively useless.

Written by WeetHet in 777509021
all the browsers use libsandbox internally.

Yep. And that raises the subtle question of what “supported” means. I’m using it in the very specific sense that DTS doesn’t support this. From our perspective it’s all considered to be an implementation detail.

Now, plenty of third-party code relies on implementation details, sometimes deliberately but more often accidentally [1]. This is an ongoing binary compatibility concern for our platform engineers. They regularly have to make hard choices between improving the implementation and breaking third-party products. DTS tries not to make this situation worse, and hence our focus on supported APIs.

As to what you should do about this issue.

To start, filing a bug makes sense. It’s possible that the sandbox team will change the implementation to help you out.

Beyond that, you wrote:

Written by WeetHet in 777509021
We could possibly use SystemExtension

You mean an Endpoint Security system extension, right?

Because there are a few other types, and only the ES one seems relevant.

Written by WeetHet in 777509021
App Sandbox is inapplicable because we aren't an app.

True, but there’s definitely a trade-off to be made here. App Sandbox can be used by non-app code, and you have to balance the risks of that against the risks of relying on SBPL. So, yeah, I definitely think you should explore that option in more depth.

Although I’m not sure it’ll actually help. App Sandbox relies on the same underlying sandbox implementation, so it might well run into the same limits. However, I think it’s worth the time creating a quick prototype, just to be sure.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] And hence Hyrum’s law.

Crashing in sandbox-exec (FB16964888)
 
 
Q