Skip to content

Commit e4365e3

Browse files
committed
Merge tag 'trace-v5.16-6' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing fixes from Steven Rostedt: - Fix double free in destroy_hist_field - Harden memset() of trace_iterator structure - Do not warn in trace printk check when test buffer fills up * tag 'trace-v5.16-6' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: tracing: Don't use out-of-sync va_list in event printing tracing: Use memset_startat() to zero struct trace_iterator tracing/histogram: Fix UAF in destroy_hist_field()
2 parents 8b98436 + 2ef75e9 commit e4365e3

File tree

2 files changed

+35
-22
lines changed

2 files changed

+35
-22
lines changed

kernel/trace/trace.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3812,6 +3812,18 @@ void trace_check_vprintf(struct trace_iterator *iter, const char *fmt,
38123812
iter->fmt[i] = '\0';
38133813
trace_seq_vprintf(&iter->seq, iter->fmt, ap);
38143814

3815+
/*
3816+
* If iter->seq is full, the above call no longer guarantees
3817+
* that ap is in sync with fmt processing, and further calls
3818+
* to va_arg() can return wrong positional arguments.
3819+
*
3820+
* Ensure that ap is no longer used in this case.
3821+
*/
3822+
if (iter->seq.full) {
3823+
p = "";
3824+
break;
3825+
}
3826+
38153827
if (star)
38163828
len = va_arg(ap, int);
38173829

@@ -6706,9 +6718,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
67066718
cnt = PAGE_SIZE - 1;
67076719

67086720
/* reset all but tr, trace, and overruns */
6709-
memset(&iter->seq, 0,
6710-
sizeof(struct trace_iterator) -
6711-
offsetof(struct trace_iterator, seq));
6721+
memset_startat(iter, 0, seq);
67126722
cpumask_clear(iter->started);
67136723
trace_seq_init(&iter->seq);
67146724
iter->pos = -1;

kernel/trace/trace_events_hist.c

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2576,42 +2576,40 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
25762576

25772577
/* Split the expression string at the root operator */
25782578
if (!sep)
2579-
goto free;
2579+
return ERR_PTR(-EINVAL);
2580+
25802581
*sep = '\0';
25812582
operand1_str = str;
25822583
str = sep+1;
25832584

25842585
/* Binary operator requires both operands */
25852586
if (*operand1_str == '\0' || *str == '\0')
2586-
goto free;
2587+
return ERR_PTR(-EINVAL);
25872588

25882589
operand_flags = 0;
25892590

25902591
/* LHS of string is an expression e.g. a+b in a+b+c */
25912592
operand1 = parse_expr(hist_data, file, operand1_str, operand_flags, NULL, n_subexprs);
2592-
if (IS_ERR(operand1)) {
2593-
ret = PTR_ERR(operand1);
2594-
operand1 = NULL;
2595-
goto free;
2596-
}
2593+
if (IS_ERR(operand1))
2594+
return ERR_CAST(operand1);
2595+
25972596
if (operand1->flags & HIST_FIELD_FL_STRING) {
25982597
hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(operand1_str));
25992598
ret = -EINVAL;
2600-
goto free;
2599+
goto free_op1;
26012600
}
26022601

26032602
/* RHS of string is another expression e.g. c in a+b+c */
26042603
operand_flags = 0;
26052604
operand2 = parse_expr(hist_data, file, str, operand_flags, NULL, n_subexprs);
26062605
if (IS_ERR(operand2)) {
26072606
ret = PTR_ERR(operand2);
2608-
operand2 = NULL;
2609-
goto free;
2607+
goto free_op1;
26102608
}
26112609
if (operand2->flags & HIST_FIELD_FL_STRING) {
26122610
hist_err(file->tr, HIST_ERR_INVALID_STR_OPERAND, errpos(str));
26132611
ret = -EINVAL;
2614-
goto free;
2612+
goto free_operands;
26152613
}
26162614

26172615
switch (field_op) {
@@ -2629,12 +2627,12 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
26292627
break;
26302628
default:
26312629
ret = -EINVAL;
2632-
goto free;
2630+
goto free_operands;
26332631
}
26342632

26352633
ret = check_expr_operands(file->tr, operand1, operand2, &var1, &var2);
26362634
if (ret)
2637-
goto free;
2635+
goto free_operands;
26382636

26392637
operand_flags = var1 ? var1->flags : operand1->flags;
26402638
operand2_flags = var2 ? var2->flags : operand2->flags;
@@ -2653,12 +2651,13 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
26532651
expr = create_hist_field(hist_data, NULL, flags, var_name);
26542652
if (!expr) {
26552653
ret = -ENOMEM;
2656-
goto free;
2654+
goto free_operands;
26572655
}
26582656

26592657
operand1->read_once = true;
26602658
operand2->read_once = true;
26612659

2660+
/* The operands are now owned and free'd by 'expr' */
26622661
expr->operands[0] = operand1;
26632662
expr->operands[1] = operand2;
26642663

@@ -2669,7 +2668,7 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
26692668
if (!divisor) {
26702669
hist_err(file->tr, HIST_ERR_DIVISION_BY_ZERO, errpos(str));
26712670
ret = -EDOM;
2672-
goto free;
2671+
goto free_expr;
26732672
}
26742673

26752674
/*
@@ -2709,18 +2708,22 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
27092708
expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
27102709
if (!expr->type) {
27112710
ret = -ENOMEM;
2712-
goto free;
2711+
goto free_expr;
27132712
}
27142713

27152714
expr->name = expr_str(expr, 0);
27162715
}
27172716

27182717
return expr;
2719-
free:
2720-
destroy_hist_field(operand1, 0);
2718+
2719+
free_operands:
27212720
destroy_hist_field(operand2, 0);
2722-
destroy_hist_field(expr, 0);
2721+
free_op1:
2722+
destroy_hist_field(operand1, 0);
2723+
return ERR_PTR(ret);
27232724

2725+
free_expr:
2726+
destroy_hist_field(expr, 0);
27242727
return ERR_PTR(ret);
27252728
}
27262729

0 commit comments

Comments
 (0)