Skip to content

Commit 940b809

Browse files
Mossakaclaude
andauthored
fix(cli): fix secure_getenv() bypass of one-shot token protection (#1244)
* fix(cli): fix secure_getenv() bypass of one-shot token protection secure_getenv() was calling get_token_index() before init_token_list() and without the mutex, causing all token protection to be bypassed when secure_getenv() was the first call into the library (empty token list returns -1 for all lookups). Added initialization, mutex acquisition, and recursion guard matching the getenv() implementation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: move token init to constructor to prevent contention Multi-threaded programs like rustc call getenv() from many threads during startup. The previous fix held the mutex for every getenv() call to protect lazy initialization, which serialized all threads and caused rustc to timeout (60s) in CI. Move init_token_list() into the library constructor which runs before any threads are created. This eliminates the data race without needing the mutex for non-sensitive variable lookups. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9b55519 commit 940b809

File tree

1 file changed

+22
-12
lines changed

1 file changed

+22
-12
lines changed

containers/agent/one-shot-token/one-shot-token.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,12 @@ __attribute__((constructor))
295295
static void one_shot_token_init(void) {
296296
ensure_real_getenv();
297297
ensure_real_secure_getenv();
298+
/* Initialize the token list eagerly - this runs before any threads are
299+
* created, so there is no data race on sensitive_tokens[]/num_tokens.
300+
* This avoids needing to lock the mutex on every getenv() call just to
301+
* protect initialization, which would serialize multi-threaded programs
302+
* like rustc that call getenv() from many threads during startup. */
303+
init_token_list();
298304
}
299305

300306
/* Check if a variable name is a sensitive token */
@@ -331,23 +337,18 @@ char *getenv(const char *name) {
331337
}
332338
in_getenv = 1;
333339

334-
/* Initialize token list on first call (thread-safe) */
335-
pthread_mutex_lock(&token_mutex);
336-
if (!tokens_initialized) {
337-
init_token_list();
338-
}
339-
340-
/* Get token index while holding mutex to avoid race with initialization */
340+
/* Token list is initialized eagerly in constructor - no mutex needed here.
341+
* get_token_index() only reads the immutable token list. */
341342
int token_idx = get_token_index(name);
342343

343-
/* Not a sensitive token - release mutex and pass through */
344+
/* Not a sensitive token - pass through to real getenv */
344345
if (token_idx < 0) {
345-
pthread_mutex_unlock(&token_mutex);
346346
in_getenv = 0;
347347
return real_getenv(name);
348348
}
349349

350-
/* Sensitive token - handle cached access (mutex already held) */
350+
/* Sensitive token - lock mutex for cache access */
351+
pthread_mutex_lock(&token_mutex);
351352
char *result = NULL;
352353

353354
if (!token_accessed[token_idx]) {
@@ -404,16 +405,24 @@ char *secure_getenv(const char *name) {
404405
return getenv(name);
405406
}
406407

408+
/* Skip interception during recursive calls (e.g., fprintf -> secure_getenv) */
409+
if (in_getenv) {
410+
return real_secure_getenv(name);
411+
}
412+
in_getenv = 1;
413+
414+
/* Token list is initialized eagerly in constructor - no mutex needed here.
415+
* get_token_index() only reads the immutable token list. */
407416
int token_idx = get_token_index(name);
408417

409418
/* Not a sensitive token - pass through to real secure_getenv */
410419
if (token_idx < 0) {
420+
in_getenv = 0;
411421
return real_secure_getenv(name);
412422
}
413423

414-
/* Sensitive token - handle cached access with secure_getenv semantics */
424+
/* Sensitive token - lock mutex for cache access */
415425
pthread_mutex_lock(&token_mutex);
416-
417426
char *result = NULL;
418427

419428
if (!token_accessed[token_idx]) {
@@ -445,6 +454,7 @@ char *secure_getenv(const char *name) {
445454
}
446455

447456
pthread_mutex_unlock(&token_mutex);
457+
in_getenv = 0;
448458

449459
return result;
450460
}

0 commit comments

Comments
 (0)