20
#include "trace2/tr2_tmr.h"
21
22
static int trace2_enabled;
23
+static int trace2_redact = 1;
24
25
static int tr2_next_child_id; /* modify under lock */
26
static int tr2_next_exec_id; /* modify under lock */
228
if (!tr2_tgt_want_builtins())
229
return;
230
trace2_enabled = 1;
231
+ if (!git_env_bool("GIT_TRACE2_REDACT", 1))
232
+ trace2_redact = 0;
233
234
tr2_sid_get();
235
250
return trace2_enabled;
251
}
252
253
+/*
254
+ * Redacts an argument, i.e. ensures that no password in
255
+ * https://user:password@host/-style URLs is logged.
256
+ *
257
+ * Returns the original if nothing needed to be redacted.
258
+ * Returns a pointer that needs to be `free()`d otherwise.
259
+ */
260
+static const char *redact_arg(const char *arg)
261
+{
262
+ const char *p, *colon;
263
+ size_t at;
264
+
265
+ if (!trace2_redact ||
266
+ (!skip_prefix(arg, "https://", &p) &&
267
+ !skip_prefix(arg, "http://", &p)))
268
+ return arg;
269
+
270
+ at = strcspn(p, "@/");
271
+ if (p[at] != '@')
272
+ return arg;
273
+
274
+ colon = memchr(p, ':', at);
275
+ if (!colon)
276
+ return arg;
277
+
278
+ return xstrfmt("%.*s:<REDACTED>%s", (int)(colon - arg), arg, p + at);
279
+}
280
+
281
+/*
282
+ * Redacts arguments in an argument list.
283
+ *
284
+ * Returns the original if nothing needed to be redacted.
285
+ * Otherwise, returns a new array that needs to be released
286
+ * via `free_redacted_argv()`.
287
+ */
288
+static const char **redact_argv(const char **argv)
289
+{
290
+ int i, j;
291
+ const char *redacted = NULL;
292
+ const char **ret;
293
+
294
+ if (!trace2_redact)
295
+ return argv;
296
+
297
+ for (i = 0; argv[i]; i++)
298
+ if ((redacted = redact_arg(argv[i])) != argv[i])
299
+ break;
300
+
301
+ if (!argv[i])
302
+ return argv;
303
+
304
+ for (j = 0; argv[j]; j++)
305
+ ; /* keep counting */
306
+
307
+ ALLOC_ARRAY(ret, j + 1);
308
+ ret[j] = NULL;
309
+
310
+ for (j = 0; j < i; j++)
311
+ ret[j] = argv[j];
312
+ ret[i] = redacted;
313
+ for (++i; argv[i]; i++) {
314
+ redacted = redact_arg(argv[i]);
315
+ ret[i] = redacted ? redacted : argv[i];
316
+ }
317
+
318
+ return ret;
319
+}
320
+
321
+static void free_redacted_argv(const char **redacted, const char **argv)
322
+{
323
+ int i;
324
+
325
+ if (redacted != argv) {
326
+ for (i = 0; argv[i]; i++)
327
+ if (redacted[i] != argv[i])
328
+ free((void *)redacted[i]);
329
+ free((void *)redacted);
330
+ }
331
+}
332
+
333
void trace2_cmd_start_fl(const char *file, int line, const char **argv)
334
{
335
struct tr2_tgt *tgt_j;
336
int j;
337
uint64_t us_now;
338
uint64_t us_elapsed_absolute;
339
+ const char **redacted;
340
341
if (!trace2_enabled)
342
return;
344
us_now = getnanotime() / 1000;
345
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
346
347
+ redacted = redact_argv(argv);
348
+
349
for_each_wanted_builtin (j, tgt_j)
350
if (tgt_j->pfn_start_fl)
351
tgt_j->pfn_start_fl(file, line, us_elapsed_absolute,
266
- argv);
352
+ redacted);
353
+
354
+ free_redacted_argv(redacted, argv);
355
}
356
357
void trace2_cmd_exit_fl(const char *file, int line, int code)
497
int j;
498
uint64_t us_now;
499
uint64_t us_elapsed_absolute;
500
+ const char **orig_argv = cmd->args.v;
501
502
if (!trace2_enabled)
503
return;
508
cmd->trace2_child_id = tr2tls_locked_increment(&tr2_next_child_id);
509
cmd->trace2_child_us_start = us_now;
510
511
+ /*
512
+ * The `pfn_child_start_fl` API takes a `struct child_process`
513
+ * rather than a simple `argv` for the child because some
514
+ * targets make use of the additional context bits/values. So
515
+ * temporarily replace the original argv (inside the `strvec`)
516
+ * with a possibly redacted version.
517
+ */
518
+ cmd->args.v = redact_argv(orig_argv);
519
+
520
for_each_wanted_builtin (j, tgt_j)
521
if (tgt_j->pfn_child_start_fl)
522
tgt_j->pfn_child_start_fl(file, line,
523
us_elapsed_absolute, cmd);
524
+
525
+ if (cmd->args.v != orig_argv) {
526
+ free_redacted_argv(cmd->args.v, orig_argv);
527
+ cmd->args.v = orig_argv;
528
+ }
529
}
530
531
void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,
596
int exec_id;
597
uint64_t us_now;
598
uint64_t us_elapsed_absolute;
599
+ const char **redacted;
600
601
if (!trace2_enabled)
602
return -1;
606
607
exec_id = tr2tls_locked_increment(&tr2_next_exec_id);
608
609
+ redacted = redact_argv(argv);
610
+
611
for_each_wanted_builtin (j, tgt_j)
612
if (tgt_j->pfn_exec_fl)
613
tgt_j->pfn_exec_fl(file, line, us_elapsed_absolute,
508
- exec_id, exe, argv);
614
+ exec_id, exe, redacted);
615
+
616
+ free_redacted_argv(redacted, argv);
617
618
return exec_id;
619
}
745
{
746
struct tr2_tgt *tgt_j;
747
int j;
748
+ const char *redacted;
749
750
if (!trace2_enabled)
751
return;
752
753
+ redacted = redact_arg(value);
754
+
755
for_each_wanted_builtin (j, tgt_j)
756
if (tgt_j->pfn_param_fl)
646
- tgt_j->pfn_param_fl(file, line, param, value, kvi);
757
+ tgt_j->pfn_param_fl(file, line, param, redacted, kvi);
758
+
759
+ if (redacted != value)
760
+ free((void *)redacted);
761
}
762
763
void trace2_def_repo_fl(const char *file, int line, struct repository *repo)