PID reuse agent session attribution को कैसे भ्रष्ट करता है
PID reuse agent actions को गलत process से जोड़ सकता है। Process start data, signer checks, parent snapshots और सख्त revalidation से सुरक्षित macOS agent sessions बनाएं।

Bare PID status screen के लिए ठीक हो सकता है। लेकिन approval, audit record या credential रखने वाले agent session के पीछे identity के रूप में यह स्वीकार्य नहीं है। Operating system process IDs को दोबारा इस्तेमाल करता है। अगर agent system recycled number को उसी actor की पहचान मान ले, तो वह बाद के process को पहले process की approval से जोड़ सकता है।
इसके लिए kernel access वाला attacker या कोई असाधारण race जरूरी नहीं है। कोई short-lived agent बंद होता है, व्यस्त machine इतने processes बनाती है कि उसका PID दोबारा मिल जाता है, और कोई component PID के आधार पर call reconnect करता है, display refresh करता है या पुरानी audit row ढूंढता है। बाद वाला process सामान्य software हो सकता है। Attribution फिर भी गलत है, और गलत attribution पर चलने वाली approval system ने approvals रखने का उद्देश्य ही खो दिया है।
Fix मुश्किल नहीं है, लेकिन vocabulary बदलनी होगी। PID को process identity कहना बंद करें। Captured process record रखें जिसमें PID, start time, code-signing facts और authorization decision के समय collected parent provenance हो। इसके बाद हर comparison में साबित करें कि live process अभी भी उसी record से मेल खाता है।
PID slot का नाम है, process lifetime का नहीं
Process ID उस समय allocated kernel process entry की पहचान करता है। यह हमेशा के लिए किसी एक program का नाम नहीं होता और समय के साथ global uniqueness की गारंटी नहीं देता। Process बंद होने पर उसका PID फिर इस्तेमाल के लिए उपलब्ध हो जाता है।
यह अंतर तब महत्वपूर्ण हो जाता है जब system पुरानी approval को आगे ले जाता है। मान लें agent client PID 4812 से शुरू होता है, deployment credential इस्तेमाल करने की request करता है और user उस run को approve कर देता है। Client बंद हो जाता है। बाद में किसी दूसरे process को PID 4812 मिल जाता है। अगर आपका gateway पूछता है, «क्या PID 4812 का approved session है?», तो वह पुरानी approval निकालकर नए process से जोड़ सकता है।
खतरनाक बात यह है कि पुराने और नए process का एक साथ चलना जरूरी नहीं है। कई implementations database join, cache lookup या देर से चलने वाले enrichment job में यह गलती करती हैं। वे approval को pid = 4812 के रूप में save करती हैं, calls को भी इसी तरह save करती हैं और मानती हैं कि बाद की query पहले वाला अर्थ रखती है। ऐसा नहीं है।
Human-facing record में PID फिर भी उपयोगी है, क्योंकि इससे operator live system की जांच कर सकता है। इसे रखें। बस authorization या attribution में इस्तेमाल होने वाली primary identity न बनाएं।
एक दूसरी समस्या fork और exec से आती है। Fork अलग PID वाला नया child बनाता है। Exec मौजूदा process में program image बदलता है और PID वही रखता है। अगर आप shell runner को approve करते हैं और वह किसी दूसरे binary को exec करता है, तो PID परिचित रहता है, लेकिन अगली request करने वाला code बदल सकता है। Identity design को exit के बाद PID reuse और जीवित process के भीतर program replacement, दोनों का ध्यान रखना चाहिए।
Session शुरू होते ही process record capture करें
विश्वसनीय session record security boundary पर लिया गया snapshot होता है, बाद में जोड़ी गई facts का संग्रह नहीं। Agent process पहली बार session बनाने की request करे, उसी समय इसे capture करें, approval में caller को दिखाने से पहले।
macOS agent gateway के लिए मैं इन fields को एक immutable process snapshot में रखूंगा:
- PID और effective user ID।
- Process start time, जिसमें platform उपलब्ध कराए तो seconds और microseconds भी हों।
- Capture के समय देखा गया executable path।
- Signing identifier, team या signer context और उपलब्ध होने पर code directory hash।
- Parent process snapshot, जिसमें उसका अपना PID और start time भी हो।
Process start time PID को एक खास lifetime वाले reference में बदल देता है। Practical tuple ऐसा दिख सकता है:
process_instance = (
pid = 4812,
start_time = 2026-07-22T14:03:18.482911Z,
euid = 501
)
यह tuple संकीर्ण सवाल का जवाब देता है, «क्या यह वही kernel process lifetime है जिसे मैंने पहले देखा था?» यह नहीं बताता कि process trustworthy है या नहीं। Signing record अलग सवाल का जवाब देता है, «जब मैंने process inspect किया, तब macOS ने किस code को validate किया था?» Parent snapshot एक और सवाल का जवाब देता है, «Session शुरू होने पर observed रूप में इस process को किसने बनाया?»
इन सवालों को Claude Code (PID 4812) जैसे एक text label में न समेटें। Approval card के लिए यह label ठीक हो सकता है, लेकिन reviewer जब पूछे कि किसी session को authorize क्यों किया गया, तब जरूरी facts गायब हो जाएंगे।
macOS पर process inspector PROC_PIDTBSDINFO के साथ proc_pidinfo इस्तेमाल करके proc_bsdinfo प्राप्त कर सकता है। इसमें pbi_start_tvsec और pbi_start_tvusec शामिल होते हैं। Apple अपने Endpoint Security process model में process start_time भी देता है। कौन-सी API चुनते हैं, यह मुख्य बात नहीं है। मुख्य बात यह है कि decision boundary पर start time capture हो और बाद में उसकी तुलना की जाए।
Lifetime वाले हिस्से के लिए एक छोटा C helper ऐसा हो सकता है:
#include <libproc.h>
#include <sys/proc_info.h>
#include <cstdio.h>
int read_process_lifetime(pid_t pid) {
struct proc_bsdinfo info = {0};
int size = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0,
&info, sizeof(info));
if (size != sizeof(info)) {
return -1;
}
printf("pid=%d start=%lld.%06d parent=%d uid=%d\n",
info.pbi_pid,
info.pbi_start_tvsec,
info.pbi_start_tvusec,
info.pbi_ppid,
info.pbi_uid);
return 0;
}
Output का format language binding से ज्यादा महत्वपूर्ण है:
pid=4812 start=1784738598.482911 parent=4760 uid=501
अगर बाद की read में वही PID किसी अलग start timestamp के साथ मिले, तो आप अलग process देख रहे हैं। Session match deny करें, भले ही convenience layer उस number को परिचित मानना चाहती हो।
Code signing code के बारे में बताता है, एक running instance के बारे में नहीं
Code-signing data उपयोगी provenance देता है, लेकिन अपने आप process identity नहीं बन जाता। Signing identifier किसी application के हर released version में समान हो सकता है। Team identifier signing organization की पहचान करता है, किसी खास executable की नहीं। Code directory hash signed code content के लिए अधिक specific है, फिर भी एक executable के कई concurrent instances इसे साझा करेंगे।
Apple का code-signing documentation एक महत्वपूर्ण अंतर बताता है जिसे security products अक्सर मिटा देते हैं। Signing identifier कई signers द्वारा claim किया जा सकता है, इसलिए Apple validation category और non-Apple code के लिए team identifier भी जांचने की सलाह देता है। Apple की technical note TN3127 यह भी बताती है कि designated requirement identifier को signing requirements के साथ मिलाकर updates के दौरान code identity स्थापित करती है।
सही mental model यह है: signing facts बताते हैं कि macOS ने किस executable को validate किया है और क्या वह आपकी trust requirement पूरी करता है। वे यह नहीं बताते कि यह वही process है जिसे user ने पांच मिनट पहले approve किया था।
Session authorization में दोनों layers इस्तेमाल करें:
same_process_lifetime:
pid, start_time, euid all match the captured record
same_expected_code:
captured signing requirement still validates for the live process
same_session:
the session token refers to this captured process record, not only its PID
सिर्फ display name, bundle identifier या path की तुलना न करें। Paths बदलते हैं। Unsigned command-line tools की identity कमजोर या केवल local हो सकती है। User किसी परिचित tool की copy दूसरी location से भी चला सकता है। Approval UI friendly label दिखा सकता है, लेकिन authorization code को वही evaluated signing facts सुरक्षित रखने चाहिए जिनसे वह label बना था।
एक आम गलत सलाह कहती है कि application updates के दौरान continuity बनाए रखने के लिए केवल signing identifier से authorize करें। यह इसलिए लोकप्रिय है क्योंकि update continuity सुविधाजनक लगती है। Per-run approval के लिए यह गलत है। अगर किसी व्यक्ति ने एक चल रहे agent process को approve किया है, तो उसी signed program का बाद में शुरू हुआ instance नया run है और उसे नया session decision मिलना चाहिए। Stable code identity approval card को समझने योग्य बनाने का कारण है। यह किसी एक run की approval को भविष्य के हर instance तक चुपचाप बढ़ाने की अनुमति नहीं है।
Parent PID तभी evidence है जब उसका lifetime भी रखें
Parent process data reviewers को यह समझने में मदद करता है कि agent कैसे शुरू हुआ। इससे terminal से शुरू हुए client को editor, scheduler या किसी दूसरे agent से शुरू हुए process से अलग किया जा सकता है। लेकिन ppid = 4760 में भी child PID जैसी reuse समस्या है।
गलत pattern आसानी से दिखता है:
session.agent_pid = 4812
session.parent_pid = 4760
तीन घंटे बाद audit viewer PID 4760 को किसी process से resolve करता है और उसे session का parent बताता है। Original parent बहुत पहले बंद हो चुका हो सकता है। अब 4760 किसी दूसरे process के पास है। Audit page ने historical claim को live lookup में बदलकर चुपचाप history बदल दी।
Child snapshot के साथ parent snapshot भी capture करें:
parent_instance = (
pid = 4760,
start_time = 2026-07-22T14:01:02.117604Z,
euid = 501,
executable_path = "/usr/bin/login",
signing_requirement = "captured evaluation",
relationship = "observed_parent_at_session_open"
)
आखिरी relationship field साधारण लगती है, लेकिन यह गलत भाषा से बचाती है। Parent record का अर्थ है, «जब system ने child को देखा, तब यह उसका direct parent था।» इसका अर्थ यह नहीं है कि «इस parent ने child को authorize किया», «यह parent हमेशा child का owner है» या «यह अभी भी current parent है»। इन दावों के लिए अलग evidence चाहिए।
अगर आपके पास Endpoint Security process events हैं, तो Apple का es_process_t original parent PID देता है और parent_audit_token, responsible_audit_token, start time तथा signing data भी उपलब्ध कराता है। API दे तो audit tokens raw PIDs से बेहतर हैं, क्योंकि उनमें अधिक context रहता है। फिर भी event के process object को captured observation मानें। बाद के PID lookup से उसे बदलकर equivalent न कहें।
Endpoint Security के बिना systems में उपलब्ध सर्वोत्तम process APIs इस्तेमाल करें, जल्दी capture करें और uncertainty स्पष्ट रखें। Child पढ़ने और parent पढ़ने के बीच parent बंद हो सकता है। उस race में certainty गढ़ें नहीं। Parent को unavailable या partial mark करें, captured child identity रखें और ऐसा parent relationship न बताएं जिसे आप देख नहीं सके।
Approved session से action कराने से पहले फिर जांचें
Session approval में identity handling के दो क्षण होने चाहिए: session खुलते समय capture और authority इस्तेमाल करते समय revalidation। एक बार capture करने से audit trail सुरक्षित रहता है। Revalidation अगला action सुरक्षित करती है।
क्रम की कल्पना करें:
- Agent process session खोलता है और आप PID 4812, start time, signer facts और parent details capture करते हैं।
- कोई व्यक्ति उसी agent run को approve करता है।
- Session token memory या local IPC connection में रहते हुए process बंद हो जाता है।
- बाद के process को PID 4812 मिल जाता है और वह stale token पेश करता है या bug के जरिए पुरानी association तक पहुंचता है।
- Credentialed call करने से पहले आपका gateway live process जांचता है।
Final check में PID समान हो सकता है। Start time समान नहीं होगा। इस mismatch पर session बंद होना चाहिए। New timestamp से record को ठीक न करें, चुपचाप replacement session न बनाएं और action को पुराने process से attribute न करें।
Inspection fail होने पर भी check fail closed होना चाहिए। Process बंद हो गया हो, permissions बदल गई हों या operating system ने अधूरा data दिया हो, तो यह साबित नहीं किया जा सकता कि requester approved process है। सही response नया session मांगना है।
Comparison को संकीर्ण और literal रखें। «Same command name», «same working directory» या «same terminal window» जैसी fuzzy matching न करें। ये fields human context समझने में मदद करती हैं, लेकिन adversarial या accidental ambiguity में भरोसेमंद नहीं रहतीं। Process working directory बदल सकता है और दो unrelated processes एक ही command name चुन सकते हैं।
Cache authorization decision को captured process instance से जोड़कर करें। PID से approval state तक map बनाना गलत जगह है। PID-keyed map शांत laptop पर tests पास कर देगा और process churn में fail होगा। Users तक पहुंचने के बाद ऐसी समस्या diagnose करना खास तौर पर कठिन होता है।
Sessions को mutable process rows नहीं, immutable events की तरह model करें
Session journal को gateway द्वारा हर समय देखी गई बात सुरक्षित रखनी चाहिए। «PID 4812 active है» कहने वाली mutable row यह नहीं बता सकती कि fields original agent से आईं, replacement process से या देर से चलने वाले background refresh से।
Explicit references वाले append-only event records रखें। Structure सरल हो सकती है:
{
"event_type": "session_authorized",
"session_id": "sess_7d9f",
"process_instance": {
"pid": 4812,
"start_time": "2026-07-22T14:03:18.482911Z",
"euid": 501,
"signing_id": "com.example.agent",
"team_id": "A1B2C3D4E5",
"cdhash": "captured-code-directory-hash"
},
"parent_instance": {
"pid": 4760,
"start_time": "2026-07-22T14:01:02.117604Z"
},
"approval": {
"scope": "this process run",
"decision": "approved"
}
}
अगला call event sess_7d9f को reference करे और अपना time, requested channel, action target तथा result दर्ज करे। केवल pid: 4812 copy करके यह उम्मीद न करें कि analyst बाकी जानकारी फिर से बना लेगा। Revalidation fail हो तो observed mismatch के साथ अलग denial event लिखें।
{
"event_type": "action_denied",
"session_id": "sess_7d9f",
"reason": "process_start_time_mismatch",
"captured_pid": 4812,
"captured_start_time": "2026-07-22T14:03:18.482911Z",
"observed_start_time": "2026-07-22T15:47:09.031882Z"
}
इससे reviewer को ठोस जानकारी मिलती है: process number reuse हुआ, gateway ने mismatch पहचाना और request deny की। दोनों timestamps के बिना event केवल इतना बताता है कि कुछ fail हुआ। जब software defect और authority पाने की hostile कोशिश में अंतर करना हो, तो इतना काफी नहीं है।
Sallyport का Sessions journal और Activity journal को अलग रखना यहां उपयोगी है, क्योंकि session-level authorization और individual actions अलग audit questions का जवाब देते हैं। दोनों में session decision के समय मौजूद process snapshot रहना चाहिए। बाद के projection या review में bare PID पर निर्भर नहीं होना चाहिए।
Approval card provenance बताए, certainty का दिखावा न करे
«Agent wants access» कहने वाला dialog user को अच्छा decision लेने के लिए पर्याप्त नहीं है। Caller को पहचानने के लिए पर्याप्त identity context दें, लेकिन card को ऐसे fields से न भरें जो precise दिखें और कम जानकारी दें।
जिस code-signing authority का आपने मूल्यांकन किया है, उसे सबसे पहले दिखाएं। जरूरत हो तो executable name या path शामिल करें। Process relationship को सरल भाषा में दिखाएं, जैसे «signed terminal application ने शुरू किया» या «editor helper से launch हुआ», लेकिन केवल तब जब supporting data capture किया गया हो। PID को troubleshooting detail की तरह दिखाएं, claimed identity की तरह नहीं।
Parent chain को certificate chain की तरह प्रस्तुत न करें। Parentage उस समय का operating-system observation है। Signed parent unsigned child शुरू कर सकता है। Expected parent ऐसा wrapper हो सकता है जो किसी और चीज को exec करे। Approval card को स्पष्ट करना चाहिए कि अभी session कौन मांग रहा है, और parent information को context की तरह देना चाहिए।
यह अंतर revocation को भी बदलता है। PID नहीं, session identifier revoke करें। User session revoke करे तो immutable session record को revoked mark करें और उससे जुड़े future action attempts reject करें। Original process अभी चल रहा हो तो access खो दे। वह बंद हो चुका हो और PID reuse हो गया हो, तब भी revocation सही रहेगी, क्योंकि वह numeric PID को control करने पर निर्भर नहीं थी।
एक approval का अर्थ एक observed run होना चाहिए। User को व्यापक trust decision चाहिए तो स्पष्ट scope वाला अलग feature बनाएं, जैसे signed code requirement और तय duration। Per-session approval में ऐसा broader scope सिर्फ इसलिए न छिपाएं कि implementation में convenient PID cache था।
सामान्य process behavior पर भरोसा करने के बजाय failure test करें
PID reuse bugs छिपे रहते हैं क्योंकि सामान्य manual testing पर्याप्त process turnover नहीं बनाती। Test suite को यह साबित करना चाहिए कि inherited number वाले replacement process को reject किया जाता है और surviving process के पीछे code बदलने वाले exec को भी reject किया जाता है।
macOS के किसी खास PID को स्वाभाविक रूप से reuse करने का इंतजार जरूरी नहीं है। Process-inspection layer को interface के पीछे रखें और controlled snapshots दें। अच्छा test approved record और बाद की live observation में same PID, लेकिन अलग start time रखता है:
captured: pid=4812 start=1784738598.482911 signer=team-A
observed: pid=4812 start=1784744029.031882 signer=team-B
expected: deny with process_start_time_mismatch
एक दूसरा case जोड़ें जिसमें PID और start time match हों, लेकिन signing requirement fail हो। एक और case रखें जिसमें child जीवित रहे, पर exec ने उसके executable facts बदल दिए हों। ये tests साबित करते हैं कि authorization code सही fields को जोड़ता है, केवल process inspection से data मिलने की जांच नहीं करता।
Audit view को अलग से test करें। Parent PID वाला पुराना session seed करें, parent के बंद होने का simulation करें और बाद में उसी PID वाला unrelated process दें। Rendered historical session में original captured parent fields बने रहने चाहिए। Current process table से मिले name से उन्हें replace नहीं करना चाहिए।
Cancellation और inspection failures भी test करें। IPC request स्वीकार करने और details query करने के बीच process गायब हो सकता है। Code को स्पष्ट denial reason रिकॉर्ड करना चाहिए और caller से नया session स्थापित करने को कहना चाहिए। ऐसे failures को best-effort matches में बदलने वाले systems वही ambiguity बनाते हैं जिसे identity model हटाने के लिए बनाया गया था।
उपयोगी invariant सरल और सख्त है
हर privileged agent action ऐसे session से जुड़ा होना चाहिए जो एक captured process lifetime से bound हो। Matching live request को साबित करना चाहिए कि वह उसी lifetime से आई है और उसका executable अभी भी approved code identity पूरी करता है। Reused PID पहला test fail करता है। Unchanged PID के पीछे अलग binary दूसरा test fail करती है।
यह invariant process facts की सही भूमिका बनाए रखता है। Start data lifetimes अलग करता है। Signer data validated code की पहचान करता है। Parent details provenance देते हैं। Session ID human decision लेकर चलता है। इनमें से कोई field दूसरे का काम नहीं कर सकती।
Sallyport session authorization की शुरुआत process की code-signing authority से करके और runs तथा calls के अलग records रखकर इस decision को स्पष्ट बना सकता है। Implementation को फिर भी किसी सुविधाजनक number को, log में कितना भी परिचित दिखे, approval पाने वाले process की जगह लेने नहीं देना चाहिए।
अगली बार जब आपको pid से keyed table दिखे, तो पूछें कि process बंद होने के बाद क्या होगा। अगर जवाब है «हम इसे फिर lookup करते हैं», तो वह table session identity store नहीं है। किसी मामूली process lifecycle event के authorization error बनने से पहले इसे ठीक करें।
सामान्य प्रश्न
Process ID को unique process identity क्यों नहीं माना जा सकता?
PID operating system की process table में एक slot होता है, स्थायी identity नहीं। कोई process बंद होने के बाद macOS वही number किसी दूसरे process को दे सकता है। अगर आपके record में सिर्फ «PID 8421» लिखा है, तो पर्याप्त process churn के बाद वह गलत process की ओर इशारा कर सकता है।
Agent process की सुरक्षित पहचान के लिए PID के साथ क्या रखना चाहिए?
कम से कम PID के साथ process start time रखें। Agent control system में user ID, connection के समय capture किया गया executable path, signing information और parent-process snapshot भी रिकॉर्ड करें। हर field अलग तरीके से उस गलती को पकड़ता है जो bare PID से हो सकती है।
क्या PID और process start time agent authorization के लिए पर्याप्त हैं?
नहीं। Start time उन दो process lifetimes को अलग करता है जिन्हें संयोग से एक ही PID मिला हो, लेकिन इससे executable पर भरोसा साबित नहीं होता। इसे validated signing information के साथ इस्तेमाल करें और parent process को supporting provenance के रूप में रखें।
क्या macOS signing identifier पर अकेले भरोसा किया जा सकता है?
Code-signing identifier signing scope के भीतर code का नाम बताता है, लेकिन अपने आप यह साबित नहीं करता कि process वही है जिसे आपने approve किया था। सही identity check में signer या team context शामिल होना चाहिए और code requirement validate होनी चाहिए। Forensic records के लिए, platform उपलब्ध कराए तो code directory hash भी रखें।
PID reuse की गलती के बिना process parent को कैसे रिकॉर्ड करें?
Child के connect करने या exec event दिखने पर parent को capture करें। बाद में parent PID को lookup करके यह न मानें कि मिला हुआ result historical truth है। Parent PIDs भी child PIDs की तरह reuse हो सकते हैं।
PID reuse से गलत agent को approve होने से कैसे रोकें?
Process identity को display label नहीं, authorization input मानें। Session देने से ठीक पहले live process को फिर जांचें, उसके start time और signing facts को captured record से मिलाएं, और process बंद हो गया हो या बदल गया हो तो request deny करें।
क्या Endpoint Security macOS पर process attribution की समस्या हल करता है?
यह उपयोगी हो सकता है, लेकिन lifecycle-aware identity record की जगह नहीं लेता। Endpoint Security अपनी process structures में process start time, audit data, code-signing fields और parent audit data देता है। इसके लिए सही entitlement और operational काम भी चाहिए, जिसकी कई desktop apps को जरूरत नहीं होती।
cdhash और process identity में क्या अंतर है?
नहीं। Code directory hash signed code content की पहचान करता है, जबकि process identity उस code के एक running instance की पहचान करती है। दस concurrent processes का hash एक जैसा हो सकता है, और एक PID समय के साथ कई अलग processes को दिया जा सकता है।
Audit log में agent sessions और process exits को कैसे model करना चाहिए?
एक mutable session row को overwrite करने के बजाय immutable events रखें। Session approval के समय captured identity store करें, उस session identity से जुड़े call records जोड़ें और revocation या exit को बाद के events के रूप में दर्ज करें। इससे reviewers को current-state guess के बजाय जांचने योग्य sequence मिलता है।
क्या exec PID बदले बिना approved agent process बदल सकता है?
Forking के बाद PID बना रह सकता है, जबकि exec उसी process में program image बदल देता है। इसलिए PID और parent relationship वही रह सकते हैं, लेकिन executable और signer बदल सकते हैं। Agent के connect करते समय और लंबे समय की authorization इस्तेमाल होने से पहले identity check करें।