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
|
||||
```
|
||||
@@ -177,3 +177,29 @@ from Apple caching; a later independently owned public-Apple sequence could be
|
||||
justified then. A flat result would not by itself prove a managed bug: omitted
|
||||
managed parsing/matching, registry bookkeeping or lifetime differences remain. No
|
||||
production implementation or additional experiment is approved by this design.
|
||||
|
||||
## Association-driven correction after attempt A
|
||||
|
||||
Attempt A's exact original source is preserved with its failed receipts. The
|
||||
revised child retains all nine native wrapper copies but treats successful null
|
||||
results as unassociated, as the installed TrackItem does. Only non-null copies
|
||||
whose type, pointer and private generated path match the owned keychain create a
|
||||
logical owner. A previously tracked item's missing association at release fails;
|
||||
no owner is silently decremented. A copy of a retired keychain cannot consume a
|
||||
registry owner. Explicit fallback cleanup remains a failed diagnostic outcome.
|
||||
|
||||
The initial import-state owner is still released after original-certificate
|
||||
disposal. The actual last owner determines when the native delete and original
|
||||
CFRelease happen: import-state release if no item owner remains, otherwise the
|
||||
actual final tracked-item Untrack while its copy and item references remain
|
||||
alive. The receipt records that exact stage, live CF ownership at delete, and
|
||||
each copy's logical owner/native owner state before and after. The collector
|
||||
independently reconstructs the transitions from observed associations; it does
|
||||
not assume identity/copied-cert association or a fixed non-null count. Leaf
|
||||
identity checks remain first/last, and all returned CF outputs must reconcile.
|
||||
|
||||
This correction changes only the diagnostic ownership model. It does not alter
|
||||
the pinned bridge, imported material, fixed count, native calls, limits,
|
||||
permissions, cleanup, or production. The corrected code passed a separate Astra gate and coordinator serialization
|
||||
clearance before one fresh fixed-200 attempt. [Attempt B results](NATIVE_IMPORT.md)
|
||||
record its actual association/deletion order and native inventory outcome.
|
||||
|
||||
@@ -130,13 +130,19 @@ static void load_bridge(const char *path){
|
||||
#undef LOAD
|
||||
image_guard();
|
||||
}
|
||||
struct copy_result {const char *stage;int32_t status;int present,associated;};
|
||||
struct copy_result {
|
||||
const char *stage,*action;int32_t status;int present,associated;
|
||||
unsigned owners_before,owners_after;int native_owner_before,native_owner_after;
|
||||
};
|
||||
struct operation_state {
|
||||
SecCertificateRef cert,copied;SecIdentityRef identity;SecKeyRef modern,public_key,legacy;
|
||||
CFDataRef external;SecKeychainRef keychain,keychain_identity,outer;CFErrorRef error;
|
||||
char path[PATH_MAX],backing[PATH_MAX];
|
||||
unsigned logical_owners;int initial_owner,cert_tracked,copied_tracked,identity_tracked;
|
||||
int failed,path_verified,deleted,delete_during_identity_untrack,fallback_cleanup;
|
||||
int failed,path_verified,deleted,fallback_cleanup,import_state_released,leaf_checked,leaf_matches;
|
||||
unsigned import_owners_before,import_owners_after;
|
||||
const char *delete_stage;
|
||||
int delete_copy_live,delete_cert_live,delete_copied_live,delete_identity_live,delete_legacy_live;
|
||||
int32_t cert_return,cert_status,modern_return,create_status,lock_status,external_return,key_return,key_status,move_return,move_status,copy_cert_status,delete_status,path_status;
|
||||
CFIndex modern_error,external_error;int modern_error_present,external_error_present;unsigned copy_count;
|
||||
struct copy_result copies[16];
|
||||
@@ -146,18 +152,19 @@ static int private_path(struct operation_state *s,SecKeychainRef keychain){
|
||||
char actual[PATH_MAX];memset(actual,0,sizeof(actual));int32_t status=keychain_path(keychain,actual);
|
||||
return status==0 && (!strcmp(actual,s->path)||!strcmp(actual,s->backing));
|
||||
}
|
||||
static void delete_owner(struct operation_state *s,const char *stage){
|
||||
static void delete_owner(struct operation_state *s,const char *stage,int copy_live){
|
||||
if(!s->keychain)return;
|
||||
if(s->deleted){s->failed=1;return;}
|
||||
s->path_verified=private_path(s,s->keychain);
|
||||
if(s->path_verified){s->delete_status=delete_chain(s->keychain);s->deleted=1;}
|
||||
if(!s->path_verified||s->delete_status)s->failed=1;
|
||||
s->delete_during_identity_untrack=!strcmp(stage,"release-identity")&&s->identity!=NULL&&s->copied==NULL;
|
||||
s->delete_stage=stage;s->delete_copy_live=copy_live;s->delete_cert_live=s->cert!=NULL;
|
||||
s->delete_copied_live=s->copied!=NULL;s->delete_identity_live=s->identity!=NULL;s->delete_legacy_live=s->legacy!=NULL;
|
||||
DROP(s->keychain);released_refs++;
|
||||
}
|
||||
static void relinquish(struct operation_state *s,const char *stage){
|
||||
static void relinquish(struct operation_state *s,const char *stage,int copy_live){
|
||||
if(!s->logical_owners){s->failed=1;return;}
|
||||
if(--s->logical_owners==0)delete_owner(s,stage);
|
||||
if(--s->logical_owners==0)delete_owner(s,stage,copy_live);
|
||||
}
|
||||
static SecKeychainRef copied_chain(struct operation_state *s,CFTypeRef item,const char *stage,int *associated){
|
||||
*associated=0;if(!item)return NULL;
|
||||
@@ -165,20 +172,29 @@ static SecKeychainRef copied_chain(struct operation_state *s,CFTypeRef item,cons
|
||||
SecKeychainRef result=NULL;int32_t status=copy_chain(item,&result);owned(result);
|
||||
int type_ok=!result||CFGetTypeID(result)==SecKeychainGetTypeID();
|
||||
int belongs=result&&type_ok&&s->keychain_identity==result&&private_path(s,result);
|
||||
if(s->copy_count<16)s->copies[s->copy_count++]=(struct copy_result){stage,status,result!=NULL,belongs};else s->failed=1;
|
||||
if(s->copy_count<16)s->copies[s->copy_count++]=(struct copy_result){stage,"lookup",status,result!=NULL,belongs,
|
||||
s->logical_owners,s->logical_owners,s->keychain!=NULL,s->keychain!=NULL};else s->failed=1;
|
||||
if(status || !type_ok || (result&&!belongs))s->failed=1;
|
||||
*associated=status==0&&belongs;return result;
|
||||
}
|
||||
static void record_copy_action(struct operation_state *s,unsigned index,const char *action){
|
||||
if(s->copy_count==index+1){struct copy_result *copy=&s->copies[index];copy->action=action;
|
||||
copy->owners_after=s->logical_owners;copy->native_owner_after=s->keychain!=NULL;}
|
||||
}
|
||||
static void track(struct operation_state *s,CFTypeRef item,const char *stage,int *tracked){
|
||||
int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
unsigned index=s->copy_count;int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
// Installed TrackItem does nothing for a null copy; never invent an owner.
|
||||
if(associated){if(*tracked||!s->keychain)s->failed=1;else{s->logical_owners++;*tracked=1;}}
|
||||
DROP(copy);
|
||||
record_copy_action(s,index,"track");DROP(copy);
|
||||
}
|
||||
static void untrack(struct operation_state *s,CFTypeRef item,const char *stage,int *tracked){
|
||||
if(!item)return;
|
||||
int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
if(*tracked){if(associated){*tracked=0;relinquish(s,stage);}else s->failed=1;}
|
||||
else if(associated)s->failed=1;
|
||||
unsigned index=s->copy_count;int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
if(*tracked){if(associated){*tracked=0;relinquish(s,stage,copy!=NULL);}else s->failed=1;}
|
||||
// A still-registered private keychain must never consume an untracked owner.
|
||||
// After deletion the installed managed registry has no entry to release.
|
||||
else if(associated&&s->keychain)s->failed=1;
|
||||
record_copy_action(s,index,"untrack");
|
||||
// Final logical-owner release above precedes this copy's CFRelease.
|
||||
DROP(copy);
|
||||
}
|
||||
@@ -222,23 +238,25 @@ static void import_operation(unsigned iteration,const unsigned char *der,size_t
|
||||
if(s.failed)goto cleanup;
|
||||
s.move_return=move_key(s.cert,s.keychain,s.legacy,&s.identity,&s.move_status);owned(s.identity);
|
||||
track(&s,s.cert,"move-cert-track",&s.cert_tracked);track(&s,s.identity,"move-identity-track",&s.identity_tracked);DROP(s.outer);
|
||||
if(s.move_return!=1||s.move_status||!s.identity||CFGetTypeID(s.identity)!=SecIdentityGetTypeID()||!s.cert_tracked||!s.identity_tracked||s.failed){s.failed=1;goto cleanup;}
|
||||
if(s.move_return!=1||s.move_status||!s.identity||CFGetTypeID(s.identity)!=SecIdentityGetTypeID()||s.failed){s.failed=1;goto cleanup;}
|
||||
s.copy_cert_status=copy_cert(s.identity,&s.copied);owned(s.copied);track(&s,s.copied,"identity-cert-track",&s.copied_tracked);
|
||||
if(s.copy_cert_status||!s.copied||CFGetTypeID(s.copied)!=SecCertificateGetTypeID()||!s.copied_tracked||s.failed){s.failed=1;goto cleanup;}
|
||||
if((iteration==1||iteration==REPETITIONS)&&!leaf_equal(s.copied,der,der_length)){s.failed=1;goto cleanup;}
|
||||
if(s.copy_cert_status||!s.copied||CFGetTypeID(s.copied)!=SecCertificateGetTypeID()||s.failed){s.failed=1;goto cleanup;}
|
||||
if(iteration==1||iteration==REPETITIONS){s.leaf_checked=1;s.leaf_matches=leaf_equal(s.copied,der,der_length);
|
||||
if(!s.leaf_matches){s.failed=1;goto cleanup;}}
|
||||
cleanup:
|
||||
wipe(password,sizeof(password));DROP(s.error);DROP(s.external);DROP(s.modern);DROP(s.public_key);DROP(s.outer);
|
||||
untrack(&s,s.cert,"release-original-cert",&s.cert_tracked);DROP(s.cert);
|
||||
if(s.initial_owner){s.initial_owner=0;relinquish(&s,"release-import-state");}
|
||||
if(s.initial_owner){s.initial_owner=0;s.import_state_released=1;s.import_owners_before=s.logical_owners;
|
||||
relinquish(&s,"release-import-state",0);s.import_owners_after=s.logical_owners;}
|
||||
untrack(&s,s.copied,"release-copied-cert",&s.copied_tracked);DROP(s.copied);
|
||||
untrack(&s,s.identity,"release-identity",&s.identity_tracked);DROP(s.identity);
|
||||
DROP(s.legacy); // Explicit lifetime; managed helper does not scope this local with using.
|
||||
if(s.keychain){s.failed=1;s.fallback_cleanup=1;delete_owner(&s,"failure-fallback-after-items");}
|
||||
if(s.keychain){s.failed=1;s.fallback_cleanup=1;delete_owner(&s,"failure-fallback-after-items",0);}
|
||||
unsigned made=all_created-before_created,released=all_released-before_released;
|
||||
if(made!=released||s.logical_owners||s.cert_tracked||s.copied_tracked||s.identity_tracked)s.failed=1;
|
||||
if(!s.failed&&(s.copy_count!=9||!s.delete_during_identity_untrack||!s.deleted))s.failed=1;
|
||||
fprintf(stdout,"{\"kind\":\"operation\",\"iteration\":%u,\"certReturn\":%d,\"certStatus\":%d,\"modernReturn\":%d,\"modernErrorCode\":%ld,\"modernErrorPresent\":%s,\"createStatus\":%d,\"pathStatus\":%d,\"neverLockStatus\":%d,\"externalReturn\":%d,\"externalErrorCode\":%ld,\"externalErrorPresent\":%s,\"legacyReturn\":%d,\"legacyStatus\":%d,\"moveReturn\":%d,\"moveStatus\":%d,\"copyCertStatus\":%d,\"deleteStatus\":%d,\"privatePathVerified\":%s,\"deleteDuringFinalIdentityUntrack\":%s,\"fallbackCleanup\":%s,\"logicalOwnersRemaining\":%u,\"ownedOutputs\":%u,\"releasedOutputs\":%u,\"failed\":%s,\"copies\":[",iteration,s.cert_return,s.cert_status,s.modern_return,(long)s.modern_error,s.modern_error_present?"true":"false",s.create_status,s.path_status,s.lock_status,s.external_return,(long)s.external_error,s.external_error_present?"true":"false",s.key_return,s.key_status,s.move_return,s.move_status,s.copy_cert_status,s.delete_status,s.path_verified?"true":"false",s.delete_during_identity_untrack?"true":"false",s.fallback_cleanup?"true":"false",s.logical_owners,made,released,s.failed?"true":"false");
|
||||
for(unsigned i=0;i<s.copy_count;i++){struct copy_result c=s.copies[i];fprintf(stdout,"%s{\"stage\":\"%s\",\"status\":%d,\"returnedRef\":%s,\"privateAssociation\":%s}",i?",":"",c.stage,c.status,c.present?"true":"false",c.associated?"true":"false");}
|
||||
if(!s.failed&&(s.copy_count!=9||!s.import_state_released||!s.deleted))s.failed=1;
|
||||
fprintf(stdout,"{\"kind\":\"operation\",\"iteration\":%u,\"certReturn\":%d,\"certStatus\":%d,\"modernReturn\":%d,\"modernErrorCode\":%ld,\"modernErrorPresent\":%s,\"createStatus\":%d,\"pathStatus\":%d,\"neverLockStatus\":%d,\"externalReturn\":%d,\"externalErrorCode\":%ld,\"externalErrorPresent\":%s,\"legacyReturn\":%d,\"legacyStatus\":%d,\"moveReturn\":%d,\"moveStatus\":%d,\"copyCertStatus\":%d,\"deleteStatus\":%d,\"privatePathVerified\":%s,\"deleteStage\":\"%s\",\"deleteLiveReferences\":{\"copy\":%s,\"originalCertificate\":%s,\"copiedCertificate\":%s,\"identity\":%s,\"legacyKey\":%s},\"importStateReleased\":%s,\"importOwnersBefore\":%u,\"importOwnersAfter\":%u,\"leafIdentityChecked\":%s,\"leafIdentityMatches\":%s,\"fallbackCleanup\":%s,\"logicalOwnersRemaining\":%u,\"ownedOutputs\":%u,\"releasedOutputs\":%u,\"failed\":%s,\"copies\":[",iteration,s.cert_return,s.cert_status,s.modern_return,(long)s.modern_error,s.modern_error_present?"true":"false",s.create_status,s.path_status,s.lock_status,s.external_return,(long)s.external_error,s.external_error_present?"true":"false",s.key_return,s.key_status,s.move_return,s.move_status,s.copy_cert_status,s.delete_status,s.path_verified?"true":"false",s.delete_stage?s.delete_stage:"not-attempted",s.delete_copy_live?"true":"false",s.delete_cert_live?"true":"false",s.delete_copied_live?"true":"false",s.delete_identity_live?"true":"false",s.delete_legacy_live?"true":"false",s.import_state_released?"true":"false",s.import_owners_before,s.import_owners_after,s.leaf_checked?"true":"false",s.leaf_matches?"true":"false",s.fallback_cleanup?"true":"false",s.logical_owners,made,released,s.failed?"true":"false");
|
||||
for(unsigned i=0;i<s.copy_count;i++){struct copy_result c=s.copies[i];fprintf(stdout,"%s{\"stage\":\"%s\",\"action\":\"%s\",\"status\":%d,\"returnedRef\":%s,\"privateAssociation\":%s,\"logicalOwnersBefore\":%u,\"logicalOwnersAfter\":%u,\"nativeOwnerBefore\":%s,\"nativeOwnerAfter\":%s}",i?",":"",c.stage,c.action,c.status,c.present?"true":"false",c.associated?"true":"false",c.owners_before,c.owners_after,c.native_owner_before?"true":"false",c.native_owner_after?"true":"false");}
|
||||
fprintf(stdout,"]}\n");fflush(stdout);if(s.failed)die("Native bridge import operation failed after ownership cleanup");
|
||||
}
|
||||
static unsigned char *read_fixture(const char *name,size_t *length){
|
||||
|
||||
@@ -217,3 +217,10 @@ then executed 200 successful create/delete/CFRelease operations and kept native
|
||||
AppleDatabase at 1 throughout. That negative result rules out empty native
|
||||
create/delete/release alone as sufficient here; it does not identify the
|
||||
private-key/certificate import retaining owner.
|
||||
|
||||
The subsequent [installed native bridge import control](NATIVE_IMPORT.md)
|
||||
reproduced AppleDatabase growth from 1 to 201 in a measured C process with no
|
||||
managed caller. Native deletes returned zero in that control, all returned CF
|
||||
owners balanced, and keychain files/FDs stayed zero. The installed bridge and
|
||||
Security.framework remain in the path; their respective retaining ownership
|
||||
is unresolved. The native delete statuses of this managed A/B remain unobserved.
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"remainingOwnedKeychainFiles": 0
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"allLaunchedChildrenConfirmedReaped": true,
|
||||
"reapOutcomes": [
|
||||
{
|
||||
"processId": 78484,
|
||||
"confirmedReaped": true,
|
||||
"exitCode": 0
|
||||
},
|
||||
{
|
||||
"processId": 78488,
|
||||
"confirmedReaped": true,
|
||||
"exitCode": 0
|
||||
},
|
||||
{
|
||||
"processId": 78494,
|
||||
"confirmedReaped": true,
|
||||
"exitCode": 0
|
||||
},
|
||||
{
|
||||
"processId": 78495,
|
||||
"confirmedReaped": true,
|
||||
"exitCode": 0
|
||||
}
|
||||
],
|
||||
"privateMaterialOverwrittenThenUnlinkedAfterChildReaping": true,
|
||||
"physicalSecureErasureClaimed": false,
|
||||
"status": "passed",
|
||||
"ownedFixtureRootRemoved": true
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:41:42: warning: 'SecKeychainGetTypeID' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations]
|
||||
41 | if(!keychain||CFGetTypeID(keychain)!=SecKeychainGetTypeID())return errSecParam;
|
||||
| ^
|
||||
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:270:10: note: 'SecKeychainGetTypeID' has been explicitly marked deprecated here
|
||||
270 | CFTypeID SecKeychainGetTypeID(void)
|
||||
| ^
|
||||
<user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:43:21: warning: 'SecKeychainGetPath' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations]
|
||||
43 | OSStatus status=SecKeychainGetPath(keychain,&length,path);
|
||||
| ^
|
||||
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:474:10: note: 'SecKeychainGetPath' has been explicitly marked deprecated here
|
||||
474 | OSStatus SecKeychainGetPath(SecKeychainRef __nullable keychain, UInt32 *ioPathLength, char *pathName)
|
||||
| ^
|
||||
<user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:54:29: warning: 'SecKeychainCopyDefault' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations]
|
||||
54 | OSStatus default_status=SecKeychainCopyDefault(&default_keychain);
|
||||
| ^
|
||||
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:384:10: note: 'SecKeychainCopyDefault' has been explicitly marked deprecated here
|
||||
384 | OSStatus SecKeychainCopyDefault(SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychain)
|
||||
| ^
|
||||
<user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:58:28: warning: 'SecKeychainCopySearchList' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations]
|
||||
58 | OSStatus search_status=SecKeychainCopySearchList(&search);
|
||||
| ^
|
||||
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:404:10: note: 'SecKeychainCopySearchList' has been explicitly marked deprecated here
|
||||
404 | OSStatus SecKeychainCopySearchList(CFArrayRef * __nonnull CF_RETURNS_RETAINED searchList)
|
||||
| ^
|
||||
<user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:151:42: warning: 'SecKeychainGetTypeID' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations]
|
||||
151 | if(!keychain||CFGetTypeID(keychain)!=SecKeychainGetTypeID())return 0;
|
||||
| ^
|
||||
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:270:10: note: 'SecKeychainGetTypeID' has been explicitly marked deprecated here
|
||||
270 | CFTypeID SecKeychainGetTypeID(void)
|
||||
| ^
|
||||
<user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c:173:47: warning: 'SecKeychainGetTypeID' is deprecated: first deprecated in macOS 10.10 - SecKeychain is deprecated [-Wdeprecated-declarations]
|
||||
173 | int type_ok=!result||CFGetTypeID(result)==SecKeychainGetTypeID();
|
||||
| ^
|
||||
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/SecKeychain.h:270:10: note: 'SecKeychainGetTypeID' has been explicitly marked deprecated here
|
||||
270 | CFTypeID SecKeychainGetTypeID(void)
|
||||
| ^
|
||||
6 warnings generated.
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"sourcesSha256": {
|
||||
"NativeImportControl.c": "ed442bacbdbbc3d420864c4b8ddac9bb4a5799d1e1a1e67d33033678e8401648",
|
||||
"ImportSeed.cs": "feaac1c93bdb0f4e59bd0a9fb213d6de53cb89ece7393356c9d12d318b395c1b",
|
||||
"native_import.py": "fc4092ab69a9a8b8213697d83c171632248c84c5c4bcbcf59ea6d2faffa82189",
|
||||
"pure_apple.py": "1b2148f1c20578529355379ab94b439931d7241608a5d5effce8fc86f4af7bc6"
|
||||
},
|
||||
"nativeBridgeSha256": "0333994e217a3d111d36d7f31460eea69a286f9fc819e2d7c746df13d2aec46c",
|
||||
"managedCryptographySha256": "f4957d7218a004a27bf8964e45147df6a88092c6e7344582082840d62c6c579a",
|
||||
"sdkSeedSha256": {
|
||||
"Opc.Ua.Client.dll": "620da406fabdbc75d11f9827ea7e39d2d3c762471bd2264b0d11f1d6cd9247cd",
|
||||
"Opc.Ua.Configuration.dll": "6ed6a594c93c3ff35d1a16539a9fe87c1e2640549cc2f48ed6bae333dc8bf0e7",
|
||||
"Opc.Ua.Core.Schema.dll": "51cfad48657d95d38074bb88be29aea6f5b361a07397247d58838d066b99772e",
|
||||
"Opc.Ua.Core.Types.dll": "a7dd141b8dabe8848ff28c2fb8e16a85a0508e6a49e6b1a1c1e267175b99af96",
|
||||
"Opc.Ua.Core.dll": "9d0857aa6b7f3c49037d4ea557b4da8edf07e146069464481783e66c5c9cd35a",
|
||||
"Opc.Ua.Security.Certificates.dll": "7f4969aceb2f0db5328c6882cb4b117342f3b18905c38acdba600683860c4fd0",
|
||||
"Opc.Ua.Server.dll": "930e714a2f6e15d393840bcdc95e1afa8012bc740c3738a655f958142721864e",
|
||||
"Opc.Ua.Types.dll": "c542f69882f4e8a4ebd5ccc28a3881d6967c7ffb6dcc3c56dc6c776f39c2ede1"
|
||||
},
|
||||
"compileCommand": [
|
||||
"clang",
|
||||
"-std=c11",
|
||||
"-O0",
|
||||
"-g",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"<user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/scripts/validation/opcua-lifecycle-memory/native-retention/NativeImportControl.c",
|
||||
"-framework",
|
||||
"Security",
|
||||
"-framework",
|
||||
"CoreFoundation",
|
||||
"-o",
|
||||
"/private/tmp/opcua2-native-import-20261110b/NativeImportControl"
|
||||
],
|
||||
"compiler": "Apple clang version 21.0.0 (clang-2100.0.123.102)\nTarget: arm64-apple-darwin25.5.0\nThread model: posix\nInstalledDir: /Library/Developer/CommandLineTools/usr/bin\n",
|
||||
"os": "ProductName:\t\tmacOS\nProductVersion:\t\t26.5.2\nBuildVersion:\t\t25F84\n",
|
||||
"architecture": "arm64",
|
||||
"hostDotnet": ".NET SDK:\n Version: 10.0.403\n Commit: 5a2162bea6\n Workload version: 10.0.400-manifests.a00bebb6\n MSBuild version: 18.9.15+5a2162bea\n\nRuntime Environment:\n OS Name: Mac OS X\n OS Version: 26.5\n OS Platform: Darwin\n RID: osx-arm64\n Base Path: /opt/homebrew/Cellar/dotnet/10.0.403/libexec/sdk/10.0.403/\n\n.NET workloads installed:\nThere are no installed workloads to display.\nConfigured to use workload sets when installing new manifests.\nNo workload sets are installed. Run \"dotnet workload restore\" to install a workload set.\n\nHost:\n Version: 10.0.14\n Architecture: arm64\n Commit: 0427b9abbe\n\n.NET SDKs installed:\n 10.0.403 [/opt/homebrew/Cellar/dotnet/10.0.403/libexec/sdk]\n\n.NET runtimes installed:\n Microsoft.AspNetCore.App 10.0.14 [/opt/homebrew/Cellar/dotnet/10.0.403/libexec/shared/Microsoft.AspNetCore.App]\n Microsoft.NETCore.App 10.0.14 [/opt/homebrew/Cellar/dotnet/10.0.403/libexec/shared/Microsoft.NETCore.App]\n\nOther architectures found:\n None\n\nEnvironment variables:\n Not set\n\nglobal.json file:\n <user-home>/.codex/worktrees/opcua2-client-lifecycle/OtOpcUa/global.json\n\nLearn more:\n https://aka.ms/dotnet/info\n\nDownload .NET:\n https://aka.ms/dotnet/download\n",
|
||||
"repetitions": 200,
|
||||
"stages": [
|
||||
"before",
|
||||
"first",
|
||||
"repeated",
|
||||
"idle"
|
||||
],
|
||||
"idleSeconds": 5,
|
||||
"fullSoakGate": false,
|
||||
"managedCallerInMeasuredChild": false,
|
||||
"managedPfxParsingEmulated": false,
|
||||
"legacyKeyLifetime": "Explicit CFRelease after identity disposal; managed local has no explicit using scope.",
|
||||
"wrapperNativeCopyCallsPerOperation": 9,
|
||||
"logicalOwnersFromObservedPrivateAssociationsOnly": true,
|
||||
"checkpointDeadlineSeconds": 180,
|
||||
"deadlineScope": "Checkpoint/child deadline; in-progress bounded probes and bounded reap add overhead.",
|
||||
"defaultOrSearchListSetters": false,
|
||||
"fixtureCreationUmask": "0077",
|
||||
"binarySha256": "6a0d0d1980b505c20b5b270c8e3eceb6d0256b6b8953fbc2dad4b6f66db732cf",
|
||||
"seedBinarySha256": "bc9ea0f2ee2e6bd004bb2ecb801cbc4b1cbc250b1267bf31616d1f334a102893",
|
||||
"linkedLibraries": "/private/tmp/opcua2-native-import-20261110b/NativeImportControl:\n\t/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 61901.101.4)\n\t/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 4424.1.255)\n\t/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1356.0.0)\n"
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"seed": {
|
||||
"kind": "seed",
|
||||
"leafSha256": "3115ab78ee0b71583ff5d7308de64af76aa2dfa33864962b170323afbba151d6",
|
||||
"runtime": "10.0.14",
|
||||
"sdkVersion": "2.0.1.0",
|
||||
"managerDisposed": true,
|
||||
"certificateCoresOutstanding": 0,
|
||||
"keyFormat": "PKCS1-private-RSA",
|
||||
"privateFileMode": "0600",
|
||||
"cryptographyRuntime": {
|
||||
"informationalVersion": "10.0.14+0427b9abbead3fa64c6655eb4290c537397131fa",
|
||||
"sha256": "f4957d7218a004a27bf8964e45147df6a88092c6e7344582082840d62c6c579a"
|
||||
}
|
||||
},
|
||||
"samples": [
|
||||
{
|
||||
"kind": "checkpoint",
|
||||
"mode": "native-bridge-import",
|
||||
"stage": "before",
|
||||
"operations": 0,
|
||||
"processId": 78495,
|
||||
"utc": "2026-11-10T22:35:13.063Z",
|
||||
"elapsedSeconds": 0.005821,
|
||||
"rssBytes": 7749632,
|
||||
"createdRefs": 0,
|
||||
"releasedRefs": 0,
|
||||
"managedRuntimePresent": false,
|
||||
"AppleDatabaseCount": 1,
|
||||
"AppleDatabaseShallowBytes": 768,
|
||||
"AppleDatabaseClassAbsent": false,
|
||||
"databaseManagerClassPresent": true,
|
||||
"fdCount": 3,
|
||||
"ownedTemporaryFdCount": 0,
|
||||
"ownedKeychainFdCount": 0,
|
||||
"ownedKeychainFileCount": 0
|
||||
},
|
||||
{
|
||||
"kind": "checkpoint",
|
||||
"mode": "native-bridge-import",
|
||||
"stage": "first",
|
||||
"operations": 1,
|
||||
"processId": 78495,
|
||||
"utc": "2026-11-10T22:35:13.932Z",
|
||||
"elapsedSeconds": 0.874612,
|
||||
"rssBytes": 10862592,
|
||||
"createdRefs": 1,
|
||||
"releasedRefs": 1,
|
||||
"managedRuntimePresent": false,
|
||||
"AppleDatabaseCount": 2,
|
||||
"AppleDatabaseShallowBytes": 1536,
|
||||
"AppleDatabaseClassAbsent": false,
|
||||
"databaseManagerClassPresent": true,
|
||||
"fdCount": 3,
|
||||
"ownedTemporaryFdCount": 0,
|
||||
"ownedKeychainFdCount": 0,
|
||||
"ownedKeychainFileCount": 0
|
||||
},
|
||||
{
|
||||
"kind": "checkpoint",
|
||||
"mode": "native-bridge-import",
|
||||
"stage": "repeated",
|
||||
"operations": 200,
|
||||
"processId": 78495,
|
||||
"utc": "2026-11-10T22:35:23.504Z",
|
||||
"elapsedSeconds": 10.446548,
|
||||
"rssBytes": 14598144,
|
||||
"createdRefs": 200,
|
||||
"releasedRefs": 200,
|
||||
"managedRuntimePresent": false,
|
||||
"AppleDatabaseCount": 201,
|
||||
"AppleDatabaseShallowBytes": 154368,
|
||||
"AppleDatabaseClassAbsent": false,
|
||||
"databaseManagerClassPresent": true,
|
||||
"fdCount": 3,
|
||||
"ownedTemporaryFdCount": 0,
|
||||
"ownedKeychainFdCount": 0,
|
||||
"ownedKeychainFileCount": 0
|
||||
},
|
||||
{
|
||||
"kind": "checkpoint",
|
||||
"mode": "native-bridge-import",
|
||||
"stage": "idle",
|
||||
"operations": 200,
|
||||
"processId": 78495,
|
||||
"utc": "2026-11-10T22:35:29.177Z",
|
||||
"elapsedSeconds": 16.119616,
|
||||
"rssBytes": 14614528,
|
||||
"createdRefs": 200,
|
||||
"releasedRefs": 200,
|
||||
"managedRuntimePresent": false,
|
||||
"AppleDatabaseCount": 201,
|
||||
"AppleDatabaseShallowBytes": 154368,
|
||||
"AppleDatabaseClassAbsent": false,
|
||||
"databaseManagerClassPresent": true,
|
||||
"fdCount": 3,
|
||||
"ownedTemporaryFdCount": 0,
|
||||
"ownedKeychainFdCount": 0,
|
||||
"ownedKeychainFileCount": 0
|
||||
}
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"kind": "fingerprint",
|
||||
"stage": "before",
|
||||
"defaultStatus": 0,
|
||||
"defaultPathStatus": 0,
|
||||
"searchStatus": 0,
|
||||
"searchPathStatus": 0,
|
||||
"defaultSha256": "08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63",
|
||||
"searchSha256": "c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c",
|
||||
"searchCount": 2,
|
||||
"ownedQueryReferencesReleased": 2
|
||||
},
|
||||
{
|
||||
"kind": "fingerprint",
|
||||
"stage": "after",
|
||||
"defaultStatus": 0,
|
||||
"defaultPathStatus": 0,
|
||||
"searchStatus": 0,
|
||||
"searchPathStatus": 0,
|
||||
"defaultSha256": "08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63",
|
||||
"searchSha256": "c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c",
|
||||
"searchCount": 2,
|
||||
"ownedQueryReferencesReleased": 4
|
||||
}
|
||||
],
|
||||
"complete": {
|
||||
"kind": "complete",
|
||||
"operations": 200,
|
||||
"createdRefs": 200,
|
||||
"releasedRefs": 200,
|
||||
"ownedOutputs": 2402,
|
||||
"releasedOutputs": 2402,
|
||||
"readOnlyDefaultAndSearchListUnchanged": true,
|
||||
"managedRuntimePresent": false,
|
||||
"bridgeSha256": "0333994e217a3d111d36d7f31460eea69a286f9fc819e2d7c746df13d2aec46c",
|
||||
"elapsedSeconds": 16.772098,
|
||||
"fullSoakGate": false
|
||||
},
|
||||
"wallSecondsIncludingProbes": 17.022097916924395,
|
||||
"fullSoakGate": false,
|
||||
"nativeInventoryIsNotOpenHandlesOrExclusiveRss": true,
|
||||
"measuredChildManagedRuntimePresent": false,
|
||||
"actualDeletionStages": {
|
||||
"release-copied-cert": 200
|
||||
},
|
||||
"returnedCopyReferencesByStage": {
|
||||
"import-cert-track": 0,
|
||||
"move-outer-copy": 0,
|
||||
"move-cert-untrack": 0,
|
||||
"move-cert-track": 200,
|
||||
"move-identity-track": 0,
|
||||
"identity-cert-track": 200,
|
||||
"release-original-cert": 200,
|
||||
"release-copied-cert": 200,
|
||||
"release-identity": 0
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
Determining projects to restore...
|
||||
Restored /private/tmp/opcua2-native-import-20261110b/ImportSeed.csproj (in 28 ms).
|
||||
ImportSeed -> /private/tmp/opcua2-native-import-20261110b/bin/Release/net10.0/ImportSeed.dll
|
||||
|
||||
Build succeeded.
|
||||
0 Warning(s)
|
||||
0 Error(s)
|
||||
|
||||
Time Elapsed 00:00:01.35
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"kind":"seed","leafSha256":"3115ab78ee0b71583ff5d7308de64af76aa2dfa33864962b170323afbba151d6","runtime":"10.0.14","sdkVersion":"2.0.1.0","managerDisposed":true,"certificateCoresOutstanding":0,"keyFormat":"PKCS1-private-RSA","privateFileMode":"0600","cryptographyRuntime":{"informationalVersion":"10.0.14\u002B0427b9abbead3fa64c6655eb4290c537397131fa","sha256":"f4957d7218a004a27bf8964e45147df6a88092c6e7344582082840d62c6c579a"}}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{"kind":"fingerprint","stage":"before","defaultStatus":0,"defaultPathStatus":0,"searchStatus":0,"searchPathStatus":0,"defaultSha256":"08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63","searchSha256":"c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c","searchCount":2,"ownedQueryReferencesReleased":2}
|
||||
{"kind":"checkpoint","mode":"native-bridge-import","stage":"before","operations":0,"processId":78495,"utc":"2026-11-10T22:35:13.063Z","elapsedSeconds":0.005821,"rssBytes":7749632,"createdRefs":0,"releasedRefs":0,"managedRuntimePresent":false}
|
||||
{"kind":"operation","iteration":1,"certReturn":1,"certStatus":0,"modernReturn":1,"modernErrorCode":0,"modernErrorPresent":false,"createStatus":0,"pathStatus":0,"neverLockStatus":0,"externalReturn":1,"externalErrorCode":0,"externalErrorPresent":false,"legacyReturn":1,"legacyStatus":0,"moveReturn":1,"moveStatus":0,"copyCertStatus":0,"deleteStatus":0,"privatePathVerified":true,"deleteStage":"release-copied-cert","deleteLiveReferences":{"copy":true,"originalCertificate":false,"copiedCertificate":true,"identity":true,"legacyKey":true},"importStateReleased":true,"importOwnersBefore":2,"importOwnersAfter":1,"leafIdentityChecked":true,"leafIdentityMatches":true,"fallbackCleanup":false,"logicalOwnersRemaining":0,"ownedOutputs":13,"releasedOutputs":13,"failed":false,"copies":[{"stage":"import-cert-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false},{"stage":"move-outer-copy","action":"lookup","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-untrack","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-identity-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":2,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"identity-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":2,"logicalOwnersAfter":3,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-original-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":3,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-copied-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":0,"nativeOwnerBefore":true,"nativeOwnerAfter":false},{"stage":"release-identity","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false}]}
|
||||
{"kind":"checkpoint","mode":"native-bridge-import","stage":"first","operations":1,"processId":78495,"utc":"2026-11-10T22:35:13.932Z","elapsedSeconds":0.874612,"rssBytes":10862592,"createdRefs":1,"releasedRefs":1,"managedRuntimePresent":false}
|
||||
{"kind":"operation","iteration":200,"certReturn":1,"certStatus":0,"modernReturn":1,"modernErrorCode":0,"modernErrorPresent":false,"createStatus":0,"pathStatus":0,"neverLockStatus":0,"externalReturn":1,"externalErrorCode":0,"externalErrorPresent":false,"legacyReturn":1,"legacyStatus":0,"moveReturn":1,"moveStatus":0,"copyCertStatus":0,"deleteStatus":0,"privatePathVerified":true,"deleteStage":"release-copied-cert","deleteLiveReferences":{"copy":true,"originalCertificate":false,"copiedCertificate":true,"identity":true,"legacyKey":true},"importStateReleased":true,"importOwnersBefore":2,"importOwnersAfter":1,"leafIdentityChecked":true,"leafIdentityMatches":true,"fallbackCleanup":false,"logicalOwnersRemaining":0,"ownedOutputs":13,"releasedOutputs":13,"failed":false,"copies":[{"stage":"import-cert-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false},{"stage":"move-outer-copy","action":"lookup","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-untrack","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":1,"logicalOwnersAfter":1,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"move-identity-track","action":"track","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":2,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"identity-cert-track","action":"track","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":2,"logicalOwnersAfter":3,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-original-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":3,"logicalOwnersAfter":2,"nativeOwnerBefore":true,"nativeOwnerAfter":true},{"stage":"release-copied-cert","action":"untrack","status":0,"returnedRef":true,"privateAssociation":true,"logicalOwnersBefore":1,"logicalOwnersAfter":0,"nativeOwnerBefore":true,"nativeOwnerAfter":false},{"stage":"release-identity","action":"untrack","status":0,"returnedRef":false,"privateAssociation":false,"logicalOwnersBefore":0,"logicalOwnersAfter":0,"nativeOwnerBefore":false,"nativeOwnerAfter":false}]}
|
||||
{"kind":"checkpoint","mode":"native-bridge-import","stage":"repeated","operations":200,"processId":78495,"utc":"2026-11-10T22:35:23.504Z","elapsedSeconds":10.446548,"rssBytes":14598144,"createdRefs":200,"releasedRefs":200,"managedRuntimePresent":false}
|
||||
{"kind":"fingerprint","stage":"after","defaultStatus":0,"defaultPathStatus":0,"searchStatus":0,"searchPathStatus":0,"defaultSha256":"08c2c77dd8eaf8042b4020991ea06c6215cc391532869bbf6ced2cf1126c5e63","searchSha256":"c05fae700986dc7a6a147a938ef2adc4a274173420e137929ed58ad986eb2a3c","searchCount":2,"ownedQueryReferencesReleased":4}
|
||||
{"kind":"checkpoint","mode":"native-bridge-import","stage":"idle","operations":200,"processId":78495,"utc":"2026-11-10T22:35:29.177Z","elapsedSeconds":16.119616,"rssBytes":14614528,"createdRefs":200,"releasedRefs":200,"managedRuntimePresent":false}
|
||||
{"kind":"complete","operations":200,"createdRefs":200,"releasedRefs":200,"ownedOutputs":2402,"releasedOutputs":2402,"readOnlyDefaultAndSearchListUnchanged":true,"managedRuntimePresent":false,"bridgeSha256":"0333994e217a3d111d36d7f31460eea69a286f9fc819e2d7c746df13d2aec46c","elapsedSeconds":16.772098,"fullSoakGate":false}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"status": "completed-fixed-200-positive-native-inventory",
|
||||
"projection": "Replace local user-home prefix only; selected samples are exact raw row subset. Raw receipts unchanged.",
|
||||
"rawOutput": "/tmp/opcua2-native-import-20261110b",
|
||||
"rawSha256": {
|
||||
"result.json": "73771e5aea164d0207a1096d3a9ecb92603166a82a905dfc6860598b0b37f8b1",
|
||||
"provenance.json": "e58fb368c5f57051a55394fc193c5466353f202a2667d055c73745f5d9c8e0dc",
|
||||
"native-build.log": "41df119d1bf1538cc52276326ff737e250ac2bbd9cdecd5ed6653e8ac473971e",
|
||||
"seed-build.log": "70996c4b1c82e5356abbc5084c21598e2c3f4d5420f217acb311332a4378d61a",
|
||||
"seed.jsonl": "a08c1997d04efd8288b77ca966a7b4685853202716c8a1c208a37a723a13d682",
|
||||
"fixture-cleanup.json": "27288803ee9cbc51cbea3449748ad0138c6b3ae949a3a002bf6378cde9896ca8",
|
||||
"fixture-before-harness-cleanup.json": "eaaf36a5e7f7d1d3635e987d8f9a2600ce55f6482011ec9a7abf3e4dd759d9c4",
|
||||
"samples.jsonl": "350f35e46e159424c5e552b90e3b4a3a46d572d7ba034df274cd1646636e7498"
|
||||
},
|
||||
"selectedProjectionSha256": {
|
||||
"result.json": "73771e5aea164d0207a1096d3a9ecb92603166a82a905dfc6860598b0b37f8b1",
|
||||
"provenance.json": "20748bd5520d4cc97b8d81fe5bef66d2670dc55863d2331a5a07e98e303ed2d5",
|
||||
"native-build.log": "99cbbdd79e8a0f571fe27d412df912a45335de1b5cc8933bceb68ea7edf81681",
|
||||
"seed-build.log": "70996c4b1c82e5356abbc5084c21598e2c3f4d5420f217acb311332a4378d61a",
|
||||
"seed.jsonl": "a08c1997d04efd8288b77ca966a7b4685853202716c8a1c208a37a723a13d682",
|
||||
"fixture-cleanup.json": "27288803ee9cbc51cbea3449748ad0138c6b3ae949a3a002bf6378cde9896ca8",
|
||||
"fixture-before-harness-cleanup.json": "eaaf36a5e7f7d1d3635e987d8f9a2600ce55f6482011ec9a7abf3e4dd759d9c4",
|
||||
"selected-samples.jsonl": "bfc6d3aef1e1d31174c97e8c12490a5720c5a2547a09bf8e1c6bf0d29f1438ed"
|
||||
},
|
||||
"selectedSampleRawOneBasedLineNumbers": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
203,
|
||||
204,
|
||||
205,
|
||||
206,
|
||||
207
|
||||
],
|
||||
"rawLocalOnlySnapshotsSha256": {
|
||||
"heap-before.txt": "12d73f8832ad156fc0727d8e10d1f9623f5c02e501d195a9edf5c65080d3f3c3",
|
||||
"lsof-before.txt": "b07c92216960744bc485e0661af806119cb5d9350bf5ed23aae12f862032d56e",
|
||||
"heap-first.txt": "0d85a6a6c63af1f4e3a906c120b551514ba6148cd92d38a4136d9fc4d6f63783",
|
||||
"lsof-first.txt": "729482268e18350c8eca54094ea25a262c5cd5aa4bff300ab9260aa2fac76ae7",
|
||||
"heap-repeated.txt": "4d84de1b65110b80c169be28069c972183b28dab0f82995e2f4ab017c94b412e",
|
||||
"lsof-repeated.txt": "729482268e18350c8eca54094ea25a262c5cd5aa4bff300ab9260aa2fac76ae7",
|
||||
"heap-idle.txt": "f5d4007db8902353aca48abb01d9a33dba3730b506ed1dbd032b014d4062527f",
|
||||
"lsof-idle.txt": "729482268e18350c8eca54094ea25a262c5cd5aa4bff300ab9260aa2fac76ae7"
|
||||
},
|
||||
"installedBinaryInspection": "Same pinned binaries and retained inspection hashes as attempt A verification.",
|
||||
"noRetainingOwnerDefectMitigationOrFullSoakInference": true
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""One fixed-200 native bridge import diagnostic; build/run only after review."""
|
||||
import argparse
|
||||
from collections import Counter
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
@@ -92,6 +93,72 @@ def wipe_owned(root):
|
||||
shutil.rmtree(root)
|
||||
|
||||
|
||||
def validate_operation(row):
|
||||
if row['failed'] or row['fallbackCleanup'] or not row['privatePathVerified'] or not row['importStateReleased'] or row['logicalOwnersRemaining'] or row['modernErrorPresent'] or row['externalErrorPresent']:
|
||||
raise RuntimeError('Native ownership/cleanup guard failed')
|
||||
if any(row[k] for k in ['certStatus', 'createStatus', 'pathStatus', 'neverLockStatus', 'legacyStatus', 'moveStatus', 'copyCertStatus', 'deleteStatus', 'modernErrorCode', 'externalErrorCode']) or any(row[k] != 1 for k in ['certReturn', 'modernReturn', 'externalReturn', 'legacyReturn', 'moveReturn']):
|
||||
raise RuntimeError('Native bridge statuses failed')
|
||||
leaf_check = row['iteration'] in [1, 200]
|
||||
if row['leafIdentityChecked'] != leaf_check or row['leafIdentityMatches'] != leaf_check:
|
||||
raise RuntimeError('First/last native identity checks failed')
|
||||
copies = row['copies']
|
||||
if [c['stage'] for c in copies] != COPY_STAGES or any(c['status'] or c['returnedRef'] != c['privateAssociation'] for c in copies):
|
||||
raise RuntimeError('Native wrapper-copy sequence/status/path failed')
|
||||
# Independently reconstruct ownership from observed associations, with no fixed non-null pattern.
|
||||
actions = ['track', 'lookup', 'untrack', 'track', 'track', 'track', 'untrack', 'untrack', 'untrack']
|
||||
items = ['original', None, 'original', 'original', 'identity', 'copied', 'original', 'copied', 'identity']
|
||||
tracked = {'original': False, 'copied': False, 'identity': False}
|
||||
logical = 0
|
||||
native_owner = False
|
||||
deletion = None
|
||||
live_at_delete = None
|
||||
for index, (copy, action, item) in enumerate(zip(copies, actions, items)):
|
||||
if index == 1: # Fresh native keychain created between DER TrackItem and Move wrapper.
|
||||
logical = 1
|
||||
native_owner = True
|
||||
if index == 7: # Initial import state releases after disposing the original certificate.
|
||||
if row['importOwnersBefore'] != logical or not native_owner:
|
||||
raise RuntimeError('Initial import owner release was misplaced')
|
||||
logical -= 1
|
||||
if row['importOwnersAfter'] != logical or logical < 0:
|
||||
raise RuntimeError('Initial import owner accounting failed')
|
||||
if logical == 0:
|
||||
deletion = 'release-import-state'
|
||||
native_owner = False
|
||||
live_at_delete = {'copy': False, 'originalCertificate': False, 'copiedCertificate': True,
|
||||
'identity': True, 'legacyKey': True}
|
||||
if copy['action'] != action or copy['logicalOwnersBefore'] != logical or copy['nativeOwnerBefore'] != native_owner:
|
||||
raise RuntimeError('Native wrapper ownership before copy does not reconcile')
|
||||
associated = copy['privateAssociation']
|
||||
if action == 'track' and associated:
|
||||
if tracked[item] or not native_owner:
|
||||
raise RuntimeError('Track tried to duplicate or use a retired native owner')
|
||||
tracked[item] = True
|
||||
logical += 1
|
||||
elif action == 'untrack':
|
||||
if tracked[item]:
|
||||
if not associated or not native_owner:
|
||||
raise RuntimeError('Previously tracked item lost its association before Untrack')
|
||||
tracked[item] = False
|
||||
logical -= 1
|
||||
if logical == 0:
|
||||
if deletion is not None:
|
||||
raise RuntimeError('Duplicate native deletion')
|
||||
deletion = copy['stage']
|
||||
native_owner = False
|
||||
live_at_delete = {'copy': True, 'originalCertificate': index == 6, 'copiedCertificate': index in [6, 7],
|
||||
'identity': True, 'legacyKey': True}
|
||||
elif associated and native_owner:
|
||||
raise RuntimeError('Untracked item would consume a still-registered owner')
|
||||
if logical < 0 or copy['logicalOwnersAfter'] != logical or copy['nativeOwnerAfter'] != native_owner:
|
||||
raise RuntimeError('Native wrapper ownership after copy does not reconcile')
|
||||
if logical or native_owner or any(tracked.values()) or deletion is None or row['deleteStage'] != deletion or row['deleteLiveReferences'] != live_at_delete:
|
||||
raise RuntimeError('Native logical owners or actual zero-owner delete stage did not reconcile')
|
||||
expected_outputs = 8 + sum(c['returnedRef'] for c in copies) + int(leaf_check)
|
||||
if row['ownedOutputs'] != expected_outputs or row['releasedOutputs'] != expected_outputs:
|
||||
raise RuntimeError('Native returned CF ownership did not reconcile')
|
||||
|
||||
|
||||
def main():
|
||||
os.umask(0o077) # This collector and its children only; includes normal SDK seed PFX files.
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
@@ -117,7 +184,7 @@ def main():
|
||||
'repetitions': 200, 'stages': STAGES, 'idleSeconds': 5, 'fullSoakGate': False,
|
||||
'managedCallerInMeasuredChild': False, 'managedPfxParsingEmulated': False,
|
||||
'legacyKeyLifetime': 'Explicit CFRelease after identity disposal; managed local has no explicit using scope.',
|
||||
'wrapperNativeCopyCallsPerOperation': 9, 'checkpointDeadlineSeconds': 180,
|
||||
'wrapperNativeCopyCallsPerOperation': 9, 'logicalOwnersFromObservedPrivateAssociationsOnly': True, 'checkpointDeadlineSeconds': 180,
|
||||
'deadlineScope': 'Checkpoint/child deadline; in-progress bounded probes and bounded reap add overhead.',
|
||||
'defaultOrSearchListSetters': False, 'fixtureCreationUmask': '0077'}
|
||||
save(output / 'provenance.json', provenance)
|
||||
@@ -180,19 +247,16 @@ def main():
|
||||
if status or len(rows) != 207 or len(operations) != 200 or len(fingerprints) != 2 or len(complete) != 1 or [r['iteration'] for r in operations] != list(range(1, 201)):
|
||||
raise RuntimeError('Native fixed operation/completion counts failed')
|
||||
for row in operations:
|
||||
if row['failed'] or row['fallbackCleanup'] or not row['privatePathVerified'] or not row['deleteDuringFinalIdentityUntrack'] or row['logicalOwnersRemaining'] or row['modernErrorPresent'] or row['externalErrorPresent'] or row['ownedOutputs'] != row['releasedOutputs']:
|
||||
raise RuntimeError('Native ownership order/cleanup failed')
|
||||
if [c['stage'] for c in row['copies']] != COPY_STAGES or any(c['status'] for c in row['copies']) or [c['returnedRef'] for c in row['copies']] != [False] * 3 + [True] * 6:
|
||||
raise RuntimeError('Native wrapper-copy sequence failed')
|
||||
if any(row[k] for k in ['certStatus', 'createStatus', 'pathStatus', 'neverLockStatus', 'legacyStatus', 'moveStatus', 'copyCertStatus', 'deleteStatus', 'modernErrorCode', 'externalErrorCode']) or any(row[k] != 1 for k in ['certReturn', 'modernReturn', 'externalReturn', 'legacyReturn', 'moveReturn']):
|
||||
raise RuntimeError('Native bridge statuses failed')
|
||||
if sha(task / 'seed/leaf.der') != seeds[0]['leafSha256'] or complete[0]['operations'] != 200 or complete[0]['bridgeSha256'] != BRIDGE_SHA or complete[0]['ownedOutputs'] != complete[0]['releasedOutputs']:
|
||||
validate_operation(row)
|
||||
if sha(task / 'seed/leaf.der') != seeds[0]['leafSha256'] or complete[0]['operations'] != 200 or complete[0]['bridgeSha256'] != BRIDGE_SHA or complete[0]['ownedOutputs'] != sum(r['ownedOutputs'] for r in operations) or complete[0]['releasedOutputs'] != sum(r['releasedOutputs'] for r in operations) or complete[0]['createdRefs'] != 200 or complete[0]['releasedRefs'] != 200:
|
||||
raise RuntimeError('Native identity/completion ownership guard failed')
|
||||
if any(samples[-1][k] for k in ['ownedKeychainFdCount', 'ownedKeychainFileCount']):
|
||||
raise RuntimeError('Private keychain files/descriptors retained')
|
||||
save(output / 'result.json', {'status': 'passed', 'seed': seeds[0], 'samples': samples, 'fingerprints': fingerprints,
|
||||
'complete': complete[0], 'wallSecondsIncludingProbes': time.monotonic() - started, 'fullSoakGate': False,
|
||||
'nativeInventoryIsNotOpenHandlesOrExclusiveRss': True, 'measuredChildManagedRuntimePresent': False})
|
||||
'nativeInventoryIsNotOpenHandlesOrExclusiveRss': True, 'measuredChildManagedRuntimePresent': False,
|
||||
'actualDeletionStages': dict(Counter(r['deleteStage'] for r in operations)),
|
||||
'returnedCopyReferencesByStage': {stage: sum(c['returnedRef'] for r in operations for c in r['copies'] if c['stage'] == stage) for stage in COPY_STAGES}})
|
||||
finally:
|
||||
reap(process)
|
||||
finally:
|
||||
|
||||
Reference in New Issue
Block a user