test: reproduce native import retention without managed caller
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# Installed native bridge import reproduces AppleDatabase retention
|
||||
|
||||
The corrected fixed-200 diagnostic reproduced the native heap inventory growth
|
||||
**without a managed caller in the measured process**. With the exact installed
|
||||
.NET Apple cryptography bridge still loaded, `Security::AppleDatabase` rose from
|
||||
**1 to 201 objects** and stayed at 201 after five seconds idle. All observed
|
||||
returned CF references balanced, native delete statuses were zero, and numeric
|
||||
FD counts and owned keychain files/FDs stayed flat. The native bridge plus Apple
|
||||
import/keychain path is sufficient in this control; managed .NET and the OPC UA
|
||||
SDK are not required in the measured process.
|
||||
|
||||
This does not identify the retaining native owner or separate bridge-native
|
||||
ownership from Apple caching. A classified heap object is not an open handle,
|
||||
and its shallow bytes do not explain the full RSS change. The control provides
|
||||
no production mitigation, budget waiver, full-soak/G4 pass or #799 closure.
|
||||
|
||||
## Controlled sequence and actual ownership
|
||||
|
||||
The measured arm ran once in a fresh private root on macOS **26.5.2** build
|
||||
**25F84** arm64. Its C child hash-checked and loaded the exact installed native
|
||||
bridge, verified its export image and rejected CLR/SDK images. The separate
|
||||
.NET **10.0.14** SDK **2.0.1** seed made a normal RSA application fixture, verified
|
||||
its private key against the public leaf, disposed the SDK manager, wrote private
|
||||
mode-0600 inputs under a mode-0700 directory and exited before the measured child.
|
||||
The seed's SDK PKI was removed before native measurement. The child consumed
|
||||
public DER and PKCS1 private key bytes, not a PFX, and did not emulate managed
|
||||
PFX parsing, matching or finalizer timing. The explicit legacy-key release was
|
||||
after identity disposal. [The design](NATIVE_IMPORT_DESIGN.md) maps the actual
|
||||
installed binary ABI, native exports and wrapper copy/release sequence.
|
||||
|
||||
The native child performed the pinned bridge's DER certificate import, modern
|
||||
RSA key creation/public copy/external representation, ephemeral legacy private
|
||||
key import, private keychain move/identity lookup and identity certificate copy.
|
||||
Every operation exercised nine ordered wrapper keychain-copy calls. The logical
|
||||
owner model counted only observed non-null copies whose type, pointer and
|
||||
private generated path matched the initial native keychain. The collector
|
||||
independently replayed those owner transitions and reconciled actual deletion
|
||||
stage and returned CF output counts. No logical owner was invented for a null
|
||||
copy. Any previously tracked item losing its association would fail the run.
|
||||
|
||||
All **200** moves and identity certificate copies succeeded. Native keychain
|
||||
create/path/set-never-lock/delete and the reached native OSStatus outputs were
|
||||
zero. The bridge operations that use return value one did return one. Both
|
||||
first/last returned certificate identity checks matched the unchanged seed leaf.
|
||||
All **1,800** wrapper copies had bridge-normalized status zero. Four calls per
|
||||
operation returned an owned private keychain reference: post-move original cert
|
||||
Track, copied cert Track, original cert Untrack and copied cert Untrack. The
|
||||
other five calls returned null, including both identity calls. All **800**
|
||||
returned keychain copies were released. Across all outputs the ledger was
|
||||
**2,402 acquired / 2,402 released**, including **200/200** initial keychain refs.
|
||||
There were no fallback cleanups or remaining logical owners.
|
||||
|
||||
In all 200 operations, the original cert was released, then the initial
|
||||
import-state logical owner was relinquished. Deletion occurred inside the final
|
||||
**copied-certificate Untrack**, while that keychain copy, copied certificate,
|
||||
identity and legacy key references were still alive. The native delete returned
|
||||
zero, then the initial native keychain owner, copied keychain ref and copied
|
||||
certificate were released in order. The identity's subsequent Untrack returned
|
||||
no keychain association. This observed order differs from the fixed identity
|
||||
association wrongly assumed by [attempt A](NATIVE_IMPORT_ATTEMPT.md), which
|
||||
stopped during its first operation and remains preserved separately.
|
||||
|
||||
## Native observations and cleanup
|
||||
|
||||
| Checkpoint | AppleDatabase count / shallow bytes | Numeric FDs | Owned keychain files / FDs | RSS bytes |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Before | 1 / 768 | 3 | 0 / 0 | 7,749,632 |
|
||||
| First | 2 / 1,536 | 3 | 0 / 0 | 10,862,592 |
|
||||
| 200 | 201 / 154,368 | 3 | 0 / 0 | 14,598,144 |
|
||||
| Five-second idle | 201 / 154,368 | 3 | 0 / 0 | 14,614,528 |
|
||||
|
||||
Default and search-list fingerprints were equal before and after, with all
|
||||
query statuses zero and search-list count two. Four owned query copies were
|
||||
released; no setter or restore API was called. All temporary private keychains
|
||||
were generated with unrelated filenames, prompt disabled, and path-verified
|
||||
before deletion. There were zero owned keychain files before harness cleanup.
|
||||
Both builds, seed and measured process exited zero and were reaped. The remaining
|
||||
private fixture files were overwritten and unlinked only after reaping; the task
|
||||
root was removed. No physical secure-erasure guarantee is claimed.
|
||||
|
||||
Native child time was **16.772 seconds**, parent time including probes **17.022
|
||||
seconds**. Heap probes were `heap --noContent -s`, numeric descriptors from
|
||||
`lsof`, and RSS from Mach task info. Parent and child checkpoints use a
|
||||
180-second limit, with separate bounded probe and process-reap overhead. The
|
||||
C build succeeded with **six unsuppressed deprecation warnings** for the legacy
|
||||
public keychain APIs it exercises. The seed build had zero warnings/errors.
|
||||
|
||||
The [empty native keychain control](PURE_APPLE.md) stayed at one database object
|
||||
throughout its 200 operations, so empty create/delete/release alone was
|
||||
insufficient. The [SDK configured-store A/B](README.md) reproduced inventory
|
||||
growth despite its observed SDK and managed owner release. This native import
|
||||
control narrows that observation to the installed native bridge plus
|
||||
Security.framework path. It does not assign a particular .NET, SDK or Apple
|
||||
defect, establish native delete status for the separate managed A/B, or show
|
||||
that a public-Apple-only import sequence reproduces the result.
|
||||
|
||||
## Pinned evidence
|
||||
|
||||
The unchanged private raw result is `/tmp/opcua2-native-import-20261110b`.
|
||||
[Selected receipts and hashes](evidence/2026-11-10-native-import-attempt-b/verification.json)
|
||||
retain build logs, provenance, seed and cleanup receipts, and a subset of the
|
||||
207 exact raw JSONL rows. Full raw heap/FD inventories and all 200 operation
|
||||
rows remain local. There is no retained private fixture. Source, installed
|
||||
bridge, native executable and seed DLL hashes are in the provenance.
|
||||
|
||||
- Result JSON SHA-256: `73771e5aea164d0207a1096d3a9ecb92603166a82a905dfc6860598b0b37f8b1`
|
||||
- Full raw JSONL SHA-256: `350f35e46e159424c5e552b90e3b4a3a46d572d7ba034df274cd1646636e7498`
|
||||
- Native executable SHA-256: `6a0d0d1980b505c20b5b270c8e3eceb6d0256b6b8953fbc2dad4b6f66db732cf`
|
||||
- Seed DLL SHA-256: `bc9ea0f2ee2e6bd004bb2ecb801cbc4b1cbc250b1267bf31616d1f334a102893`
|
||||
|
||||
The fixed collector invocation requires the pinned binary set and a fresh
|
||||
private output. Any further run needs its own scope and serialization review.
|
||||
|
||||
```sh
|
||||
PYTHONDONTWRITEBYTECODE=1 python3 \
|
||||
scripts/validation/opcua-lifecycle-memory/native-retention/native_import.py \
|
||||
--references /tmp/opcua2-native-reload-20261110a/bin/Release/net10.0 \
|
||||
--output /tmp/opcua2-native-import-FRESH
|
||||
```
|
||||
Reference in New Issue
Block a user