Skip to content

Commit 4bbf04a

Browse files
melvertorvalds
authored andcommitted
kfence: show cpu and timestamp in alloc/free info
Record cpu and timestamp on allocations and frees, and show them in reports. Upon an error, this can help correlate earlier messages in the kernel log via allocation and free timestamps. Link: https://lkml.kernel.org/r/[email protected] Suggested-by: Joern Engel <[email protected]> Signed-off-by: Marco Elver <[email protected]> Acked-by: Alexander Potapenko <[email protected]> Acked-by: Joern Engel <[email protected]> Cc: Yuanyuan Zhong <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 1108605 commit 4bbf04a

File tree

4 files changed

+71
-51
lines changed

4 files changed

+71
-51
lines changed

Documentation/dev-tools/kfence.rst

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -65,25 +65,27 @@ Error reports
6565
A typical out-of-bounds access looks like this::
6666

6767
==================================================================
68-
BUG: KFENCE: out-of-bounds read in test_out_of_bounds_read+0xa3/0x22b
68+
BUG: KFENCE: out-of-bounds read in test_out_of_bounds_read+0xa6/0x234
6969

70-
Out-of-bounds read at 0xffffffffb672efff (1B left of kfence-#17):
71-
test_out_of_bounds_read+0xa3/0x22b
72-
kunit_try_run_case+0x51/0x85
70+
Out-of-bounds read at 0xffff8c3f2e291fff (1B left of kfence-#72):
71+
test_out_of_bounds_read+0xa6/0x234
72+
kunit_try_run_case+0x61/0xa0
7373
kunit_generic_run_threadfn_adapter+0x16/0x30
74-
kthread+0x137/0x160
74+
kthread+0x176/0x1b0
7575
ret_from_fork+0x22/0x30
7676

77-
kfence-#17 [0xffffffffb672f000-0xffffffffb672f01f, size=32, cache=kmalloc-32] allocated by task 507:
78-
test_alloc+0xf3/0x25b
79-
test_out_of_bounds_read+0x98/0x22b
80-
kunit_try_run_case+0x51/0x85
77+
kfence-#72: 0xffff8c3f2e292000-0xffff8c3f2e29201f, size=32, cache=kmalloc-32
78+
79+
allocated by task 484 on cpu 0 at 32.919330s:
80+
test_alloc+0xfe/0x738
81+
test_out_of_bounds_read+0x9b/0x234
82+
kunit_try_run_case+0x61/0xa0
8183
kunit_generic_run_threadfn_adapter+0x16/0x30
82-
kthread+0x137/0x160
84+
kthread+0x176/0x1b0
8385
ret_from_fork+0x22/0x30
8486

85-
CPU: 4 PID: 107 Comm: kunit_try_catch Not tainted 5.8.0-rc6+ #7
86-
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014
87+
CPU: 0 PID: 484 Comm: kunit_try_catch Not tainted 5.13.0-rc3+ #7
88+
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
8789
==================================================================
8890

8991
The header of the report provides a short summary of the function involved in
@@ -96,61 +98,65 @@ Use-after-free accesses are reported as::
9698
==================================================================
9799
BUG: KFENCE: use-after-free read in test_use_after_free_read+0xb3/0x143
98100

99-
Use-after-free read at 0xffffffffb673dfe0 (in kfence-#24):
101+
Use-after-free read at 0xffff8c3f2e2a0000 (in kfence-#79):
100102
test_use_after_free_read+0xb3/0x143
101-
kunit_try_run_case+0x51/0x85
103+
kunit_try_run_case+0x61/0xa0
102104
kunit_generic_run_threadfn_adapter+0x16/0x30
103-
kthread+0x137/0x160
105+
kthread+0x176/0x1b0
104106
ret_from_fork+0x22/0x30
105107

106-
kfence-#24 [0xffffffffb673dfe0-0xffffffffb673dfff, size=32, cache=kmalloc-32] allocated by task 507:
107-
test_alloc+0xf3/0x25b
108+
kfence-#79: 0xffff8c3f2e2a0000-0xffff8c3f2e2a001f, size=32, cache=kmalloc-32
109+
110+
allocated by task 488 on cpu 2 at 33.871326s:
111+
test_alloc+0xfe/0x738
108112
test_use_after_free_read+0x76/0x143
109-
kunit_try_run_case+0x51/0x85
113+
kunit_try_run_case+0x61/0xa0
110114
kunit_generic_run_threadfn_adapter+0x16/0x30
111-
kthread+0x137/0x160
115+
kthread+0x176/0x1b0
112116
ret_from_fork+0x22/0x30
113117

114-
freed by task 507:
118+
freed by task 488 on cpu 2 at 33.871358s:
115119
test_use_after_free_read+0xa8/0x143
116-
kunit_try_run_case+0x51/0x85
120+
kunit_try_run_case+0x61/0xa0
117121
kunit_generic_run_threadfn_adapter+0x16/0x30
118-
kthread+0x137/0x160
122+
kthread+0x176/0x1b0
119123
ret_from_fork+0x22/0x30
120124

121-
CPU: 4 PID: 109 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7
122-
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014
125+
CPU: 2 PID: 488 Comm: kunit_try_catch Tainted: G B 5.13.0-rc3+ #7
126+
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
123127
==================================================================
124128

125129
KFENCE also reports on invalid frees, such as double-frees::
126130

127131
==================================================================
128132
BUG: KFENCE: invalid free in test_double_free+0xdc/0x171
129133

130-
Invalid free of 0xffffffffb6741000:
134+
Invalid free of 0xffff8c3f2e2a4000 (in kfence-#81):
131135
test_double_free+0xdc/0x171
132-
kunit_try_run_case+0x51/0x85
136+
kunit_try_run_case+0x61/0xa0
133137
kunit_generic_run_threadfn_adapter+0x16/0x30
134-
kthread+0x137/0x160
138+
kthread+0x176/0x1b0
135139
ret_from_fork+0x22/0x30
136140

137-
kfence-#26 [0xffffffffb6741000-0xffffffffb674101f, size=32, cache=kmalloc-32] allocated by task 507:
138-
test_alloc+0xf3/0x25b
141+
kfence-#81: 0xffff8c3f2e2a4000-0xffff8c3f2e2a401f, size=32, cache=kmalloc-32
142+
143+
allocated by task 490 on cpu 1 at 34.175321s:
144+
test_alloc+0xfe/0x738
139145
test_double_free+0x76/0x171
140-
kunit_try_run_case+0x51/0x85
146+
kunit_try_run_case+0x61/0xa0
141147
kunit_generic_run_threadfn_adapter+0x16/0x30
142-
kthread+0x137/0x160
148+
kthread+0x176/0x1b0
143149
ret_from_fork+0x22/0x30
144150

145-
freed by task 507:
151+
freed by task 490 on cpu 1 at 34.175348s:
146152
test_double_free+0xa8/0x171
147-
kunit_try_run_case+0x51/0x85
153+
kunit_try_run_case+0x61/0xa0
148154
kunit_generic_run_threadfn_adapter+0x16/0x30
149-
kthread+0x137/0x160
155+
kthread+0x176/0x1b0
150156
ret_from_fork+0x22/0x30
151157

152-
CPU: 4 PID: 111 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7
153-
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014
158+
CPU: 1 PID: 490 Comm: kunit_try_catch Tainted: G B 5.13.0-rc3+ #7
159+
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
154160
==================================================================
155161

156162
KFENCE also uses pattern-based redzones on the other side of an object's guard
@@ -160,23 +166,25 @@ These are reported on frees::
160166
==================================================================
161167
BUG: KFENCE: memory corruption in test_kmalloc_aligned_oob_write+0xef/0x184
162168

163-
Corrupted memory at 0xffffffffb6797ff9 [ 0xac . . . . . . ] (in kfence-#69):
169+
Corrupted memory at 0xffff8c3f2e33aff9 [ 0xac . . . . . . ] (in kfence-#156):
164170
test_kmalloc_aligned_oob_write+0xef/0x184
165-
kunit_try_run_case+0x51/0x85
171+
kunit_try_run_case+0x61/0xa0
166172
kunit_generic_run_threadfn_adapter+0x16/0x30
167-
kthread+0x137/0x160
173+
kthread+0x176/0x1b0
168174
ret_from_fork+0x22/0x30
169175

170-
kfence-#69 [0xffffffffb6797fb0-0xffffffffb6797ff8, size=73, cache=kmalloc-96] allocated by task 507:
171-
test_alloc+0xf3/0x25b
176+
kfence-#156: 0xffff8c3f2e33afb0-0xffff8c3f2e33aff8, size=73, cache=kmalloc-96
177+
178+
allocated by task 502 on cpu 7 at 42.159302s:
179+
test_alloc+0xfe/0x738
172180
test_kmalloc_aligned_oob_write+0x57/0x184
173-
kunit_try_run_case+0x51/0x85
181+
kunit_try_run_case+0x61/0xa0
174182
kunit_generic_run_threadfn_adapter+0x16/0x30
175-
kthread+0x137/0x160
183+
kthread+0x176/0x1b0
176184
ret_from_fork+0x22/0x30
177185

178-
CPU: 4 PID: 120 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7
179-
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014
186+
CPU: 7 PID: 502 Comm: kunit_try_catch Tainted: G B 5.13.0-rc3+ #7
187+
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
180188
==================================================================
181189

182190
For such errors, the address where the corruption occurred as well as the

mm/kfence/core.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/moduleparam.h>
2121
#include <linux/random.h>
2222
#include <linux/rcupdate.h>
23+
#include <linux/sched/clock.h>
2324
#include <linux/sched/sysctl.h>
2425
#include <linux/seq_file.h>
2526
#include <linux/slab.h>
@@ -196,6 +197,8 @@ static noinline void metadata_update_state(struct kfence_metadata *meta,
196197
*/
197198
track->num_stack_entries = stack_trace_save(track->stack_entries, KFENCE_STACK_DEPTH, 1);
198199
track->pid = task_pid_nr(current);
200+
track->cpu = raw_smp_processor_id();
201+
track->ts_nsec = local_clock(); /* Same source as printk timestamps. */
199202

200203
/*
201204
* Pairs with READ_ONCE() in

mm/kfence/kfence.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ enum kfence_object_state {
3636
/* Alloc/free tracking information. */
3737
struct kfence_track {
3838
pid_t pid;
39+
int cpu;
40+
u64 ts_nsec;
3941
int num_stack_entries;
4042
unsigned long stack_entries[KFENCE_STACK_DEPTH];
4143
};

mm/kfence/report.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/kernel.h>
1111
#include <linux/lockdep.h>
12+
#include <linux/math.h>
1213
#include <linux/printk.h>
1314
#include <linux/sched/debug.h>
1415
#include <linux/seq_file.h>
@@ -100,6 +101,13 @@ static void kfence_print_stack(struct seq_file *seq, const struct kfence_metadat
100101
bool show_alloc)
101102
{
102103
const struct kfence_track *track = show_alloc ? &meta->alloc_track : &meta->free_track;
104+
u64 ts_sec = track->ts_nsec;
105+
unsigned long rem_nsec = do_div(ts_sec, NSEC_PER_SEC);
106+
107+
/* Timestamp matches printk timestamp format. */
108+
seq_con_printf(seq, "%s by task %d on cpu %d at %lu.%06lus:\n",
109+
show_alloc ? "allocated" : "freed", track->pid,
110+
track->cpu, (unsigned long)ts_sec, rem_nsec / 1000);
103111

104112
if (track->num_stack_entries) {
105113
/* Skip allocation/free internals stack. */
@@ -126,15 +134,14 @@ void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *met
126134
return;
127135
}
128136

129-
seq_con_printf(seq,
130-
"kfence-#%td [0x%p-0x%p"
131-
", size=%d, cache=%s] allocated by task %d:\n",
132-
meta - kfence_metadata, (void *)start, (void *)(start + size - 1), size,
133-
(cache && cache->name) ? cache->name : "<destroyed>", meta->alloc_track.pid);
137+
seq_con_printf(seq, "kfence-#%td: 0x%p-0x%p, size=%d, cache=%s\n\n",
138+
meta - kfence_metadata, (void *)start, (void *)(start + size - 1),
139+
size, (cache && cache->name) ? cache->name : "<destroyed>");
140+
134141
kfence_print_stack(seq, meta, true);
135142

136143
if (meta->state == KFENCE_OBJECT_FREED) {
137-
seq_con_printf(seq, "\nfreed by task %d:\n", meta->free_track.pid);
144+
seq_con_printf(seq, "\n");
138145
kfence_print_stack(seq, meta, false);
139146
}
140147
}

0 commit comments

Comments
 (0)