Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/kernel/bpf/liveness.c
49129 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3
4
#include <linux/bpf_verifier.h>
5
#include <linux/hashtable.h>
6
#include <linux/jhash.h>
7
#include <linux/slab.h>
8
9
/*
10
* This file implements live stack slots analysis. After accumulating
11
* stack usage data, the analysis answers queries about whether a
12
* particular stack slot may be read by an instruction or any of it's
13
* successors. This data is consumed by the verifier states caching
14
* mechanism to decide which stack slots are important when looking for a
15
* visited state corresponding to the current state.
16
*
17
* The analysis is call chain sensitive, meaning that data is collected
18
* and queried for tuples (call chain, subprogram instruction index).
19
* Such sensitivity allows identifying if some subprogram call always
20
* leads to writes in the caller's stack.
21
*
22
* The basic idea is as follows:
23
* - As the verifier accumulates a set of visited states, the analysis instance
24
* accumulates a conservative estimate of stack slots that can be read
25
* or must be written for each visited tuple (call chain, instruction index).
26
* - If several states happen to visit the same instruction with the same
27
* call chain, stack usage information for the corresponding tuple is joined:
28
* - "may_read" set represents a union of all possibly read slots
29
* (any slot in "may_read" set might be read at or after the instruction);
30
* - "must_write" set represents an intersection of all possibly written slots
31
* (any slot in "must_write" set is guaranteed to be written by the instruction).
32
* - The analysis is split into two phases:
33
* - read and write marks accumulation;
34
* - read and write marks propagation.
35
* - The propagation phase is a textbook live variable data flow analysis:
36
*
37
* state[cc, i].live_after = U [state[cc, s].live_before for s in bpf_insn_successors(i)]
38
* state[cc, i].live_before =
39
* (state[cc, i].live_after / state[cc, i].must_write) U state[i].may_read
40
*
41
* Where:
42
* - `U` stands for set union
43
* - `/` stands for set difference;
44
* - `cc` stands for a call chain;
45
* - `i` and `s` are instruction indexes;
46
*
47
* The above equations are computed for each call chain and instruction
48
* index until state stops changing.
49
* - Additionally, in order to transfer "must_write" information from a
50
* subprogram to call instructions invoking this subprogram,
51
* the "must_write_acc" set is tracked for each (cc, i) tuple.
52
* A set of stack slots that are guaranteed to be written by this
53
* instruction or any of its successors (within the subprogram).
54
* The equation for "must_write_acc" propagation looks as follows:
55
*
56
* state[cc, i].must_write_acc =
57
* ∩ [state[cc, s].must_write_acc for s in bpf_insn_successors(i)]
58
* U state[cc, i].must_write
59
*
60
* (An intersection of all "must_write_acc" for instruction successors
61
* plus all "must_write" slots for the instruction itself).
62
* - After the propagation phase completes for a subprogram, information from
63
* (cc, 0) tuple (subprogram entry) is transferred to the caller's call chain:
64
* - "must_write_acc" set is intersected with the call site's "must_write" set;
65
* - "may_read" set is added to the call site's "may_read" set.
66
* - Any live stack queries must be taken after the propagation phase.
67
* - Accumulation and propagation phases can be entered multiple times,
68
* at any point in time:
69
* - "may_read" set only grows;
70
* - "must_write" set only shrinks;
71
* - for each visited verifier state with zero branches, all relevant
72
* read and write marks are already recorded by the analysis instance.
73
*
74
* Technically, the analysis is facilitated by the following data structures:
75
* - Call chain: for given verifier state, the call chain is a tuple of call
76
* instruction indexes leading to the current subprogram plus the subprogram
77
* entry point index.
78
* - Function instance: for a given call chain, for each instruction in
79
* the current subprogram, a mapping between instruction index and a
80
* set of "may_read", "must_write" and other marks accumulated for this
81
* instruction.
82
* - A hash table mapping call chains to function instances.
83
*/
84
85
struct callchain {
86
u32 callsites[MAX_CALL_FRAMES]; /* instruction pointer for each frame */
87
/* cached subprog_info[*].start for functions owning the frames:
88
* - sp_starts[curframe] used to get insn relative index within current function;
89
* - sp_starts[0..current-1] used for fast callchain_frame_up().
90
*/
91
u32 sp_starts[MAX_CALL_FRAMES];
92
u32 curframe; /* depth of callsites and sp_starts arrays */
93
};
94
95
struct per_frame_masks {
96
u64 may_read; /* stack slots that may be read by this instruction */
97
u64 must_write; /* stack slots written by this instruction */
98
u64 must_write_acc; /* stack slots written by this instruction and its successors */
99
u64 live_before; /* stack slots that may be read by this insn and its successors */
100
};
101
102
/*
103
* A function instance created for a specific callchain.
104
* Encapsulates read and write marks for each instruction in the function.
105
* Marks are tracked for each frame in the callchain.
106
*/
107
struct func_instance {
108
struct hlist_node hl_node;
109
struct callchain callchain;
110
u32 insn_cnt; /* cached number of insns in the function */
111
bool updated;
112
bool must_write_dropped;
113
/* Per frame, per instruction masks, frames allocated lazily. */
114
struct per_frame_masks *frames[MAX_CALL_FRAMES];
115
/* For each instruction a flag telling if "must_write" had been initialized for it. */
116
bool *must_write_set;
117
};
118
119
struct live_stack_query {
120
struct func_instance *instances[MAX_CALL_FRAMES]; /* valid in range [0..curframe] */
121
u32 curframe;
122
u32 insn_idx;
123
};
124
125
struct bpf_liveness {
126
DECLARE_HASHTABLE(func_instances, 8); /* maps callchain to func_instance */
127
struct live_stack_query live_stack_query; /* cache to avoid repetitive ht lookups */
128
/* Cached instance corresponding to env->cur_state, avoids per-instruction ht lookup */
129
struct func_instance *cur_instance;
130
/*
131
* Below fields are used to accumulate stack write marks for instruction at
132
* @write_insn_idx before submitting the marks to @cur_instance.
133
*/
134
u64 write_masks_acc[MAX_CALL_FRAMES];
135
u32 write_insn_idx;
136
};
137
138
/* Compute callchain corresponding to state @st at depth @frameno */
139
static void compute_callchain(struct bpf_verifier_env *env, struct bpf_verifier_state *st,
140
struct callchain *callchain, u32 frameno)
141
{
142
struct bpf_subprog_info *subprog_info = env->subprog_info;
143
u32 i;
144
145
memset(callchain, 0, sizeof(*callchain));
146
for (i = 0; i <= frameno; i++) {
147
callchain->sp_starts[i] = subprog_info[st->frame[i]->subprogno].start;
148
if (i < st->curframe)
149
callchain->callsites[i] = st->frame[i + 1]->callsite;
150
}
151
callchain->curframe = frameno;
152
callchain->callsites[callchain->curframe] = callchain->sp_starts[callchain->curframe];
153
}
154
155
static u32 hash_callchain(struct callchain *callchain)
156
{
157
return jhash2(callchain->callsites, callchain->curframe, 0);
158
}
159
160
static bool same_callsites(struct callchain *a, struct callchain *b)
161
{
162
int i;
163
164
if (a->curframe != b->curframe)
165
return false;
166
for (i = a->curframe; i >= 0; i--)
167
if (a->callsites[i] != b->callsites[i])
168
return false;
169
return true;
170
}
171
172
/*
173
* Find existing or allocate new function instance corresponding to @callchain.
174
* Instances are accumulated in env->liveness->func_instances and persist
175
* until the end of the verification process.
176
*/
177
static struct func_instance *__lookup_instance(struct bpf_verifier_env *env,
178
struct callchain *callchain)
179
{
180
struct bpf_liveness *liveness = env->liveness;
181
struct bpf_subprog_info *subprog;
182
struct func_instance *result;
183
u32 subprog_sz, size, key;
184
185
key = hash_callchain(callchain);
186
hash_for_each_possible(liveness->func_instances, result, hl_node, key)
187
if (same_callsites(&result->callchain, callchain))
188
return result;
189
190
subprog = bpf_find_containing_subprog(env, callchain->sp_starts[callchain->curframe]);
191
subprog_sz = (subprog + 1)->start - subprog->start;
192
size = sizeof(struct func_instance);
193
result = kvzalloc(size, GFP_KERNEL_ACCOUNT);
194
if (!result)
195
return ERR_PTR(-ENOMEM);
196
result->must_write_set = kvcalloc(subprog_sz, sizeof(*result->must_write_set),
197
GFP_KERNEL_ACCOUNT);
198
if (!result->must_write_set) {
199
kvfree(result);
200
return ERR_PTR(-ENOMEM);
201
}
202
memcpy(&result->callchain, callchain, sizeof(*callchain));
203
result->insn_cnt = subprog_sz;
204
hash_add(liveness->func_instances, &result->hl_node, key);
205
return result;
206
}
207
208
static struct func_instance *lookup_instance(struct bpf_verifier_env *env,
209
struct bpf_verifier_state *st,
210
u32 frameno)
211
{
212
struct callchain callchain;
213
214
compute_callchain(env, st, &callchain, frameno);
215
return __lookup_instance(env, &callchain);
216
}
217
218
int bpf_stack_liveness_init(struct bpf_verifier_env *env)
219
{
220
env->liveness = kvzalloc(sizeof(*env->liveness), GFP_KERNEL_ACCOUNT);
221
if (!env->liveness)
222
return -ENOMEM;
223
hash_init(env->liveness->func_instances);
224
return 0;
225
}
226
227
void bpf_stack_liveness_free(struct bpf_verifier_env *env)
228
{
229
struct func_instance *instance;
230
struct hlist_node *tmp;
231
int bkt, i;
232
233
if (!env->liveness)
234
return;
235
hash_for_each_safe(env->liveness->func_instances, bkt, tmp, instance, hl_node) {
236
for (i = 0; i <= instance->callchain.curframe; i++)
237
kvfree(instance->frames[i]);
238
kvfree(instance->must_write_set);
239
kvfree(instance);
240
}
241
kvfree(env->liveness);
242
}
243
244
/*
245
* Convert absolute instruction index @insn_idx to an index relative
246
* to start of the function corresponding to @instance.
247
*/
248
static int relative_idx(struct func_instance *instance, u32 insn_idx)
249
{
250
return insn_idx - instance->callchain.sp_starts[instance->callchain.curframe];
251
}
252
253
static struct per_frame_masks *get_frame_masks(struct func_instance *instance,
254
u32 frame, u32 insn_idx)
255
{
256
if (!instance->frames[frame])
257
return NULL;
258
259
return &instance->frames[frame][relative_idx(instance, insn_idx)];
260
}
261
262
static struct per_frame_masks *alloc_frame_masks(struct bpf_verifier_env *env,
263
struct func_instance *instance,
264
u32 frame, u32 insn_idx)
265
{
266
struct per_frame_masks *arr;
267
268
if (!instance->frames[frame]) {
269
arr = kvcalloc(instance->insn_cnt, sizeof(*arr), GFP_KERNEL_ACCOUNT);
270
instance->frames[frame] = arr;
271
if (!arr)
272
return ERR_PTR(-ENOMEM);
273
}
274
return get_frame_masks(instance, frame, insn_idx);
275
}
276
277
void bpf_reset_live_stack_callchain(struct bpf_verifier_env *env)
278
{
279
env->liveness->cur_instance = NULL;
280
}
281
282
/* If @env->liveness->cur_instance is null, set it to instance corresponding to @env->cur_state. */
283
static int ensure_cur_instance(struct bpf_verifier_env *env)
284
{
285
struct bpf_liveness *liveness = env->liveness;
286
struct func_instance *instance;
287
288
if (liveness->cur_instance)
289
return 0;
290
291
instance = lookup_instance(env, env->cur_state, env->cur_state->curframe);
292
if (IS_ERR(instance))
293
return PTR_ERR(instance);
294
295
liveness->cur_instance = instance;
296
return 0;
297
}
298
299
/* Accumulate may_read masks for @frame at @insn_idx */
300
static int mark_stack_read(struct bpf_verifier_env *env,
301
struct func_instance *instance, u32 frame, u32 insn_idx, u64 mask)
302
{
303
struct per_frame_masks *masks;
304
u64 new_may_read;
305
306
masks = alloc_frame_masks(env, instance, frame, insn_idx);
307
if (IS_ERR(masks))
308
return PTR_ERR(masks);
309
new_may_read = masks->may_read | mask;
310
if (new_may_read != masks->may_read &&
311
((new_may_read | masks->live_before) != masks->live_before))
312
instance->updated = true;
313
masks->may_read |= mask;
314
return 0;
315
}
316
317
int bpf_mark_stack_read(struct bpf_verifier_env *env, u32 frame, u32 insn_idx, u64 mask)
318
{
319
int err;
320
321
err = ensure_cur_instance(env);
322
err = err ?: mark_stack_read(env, env->liveness->cur_instance, frame, insn_idx, mask);
323
return err;
324
}
325
326
static void reset_stack_write_marks(struct bpf_verifier_env *env,
327
struct func_instance *instance, u32 insn_idx)
328
{
329
struct bpf_liveness *liveness = env->liveness;
330
int i;
331
332
liveness->write_insn_idx = insn_idx;
333
for (i = 0; i <= instance->callchain.curframe; i++)
334
liveness->write_masks_acc[i] = 0;
335
}
336
337
int bpf_reset_stack_write_marks(struct bpf_verifier_env *env, u32 insn_idx)
338
{
339
struct bpf_liveness *liveness = env->liveness;
340
int err;
341
342
err = ensure_cur_instance(env);
343
if (err)
344
return err;
345
346
reset_stack_write_marks(env, liveness->cur_instance, insn_idx);
347
return 0;
348
}
349
350
void bpf_mark_stack_write(struct bpf_verifier_env *env, u32 frame, u64 mask)
351
{
352
env->liveness->write_masks_acc[frame] |= mask;
353
}
354
355
static int commit_stack_write_marks(struct bpf_verifier_env *env,
356
struct func_instance *instance)
357
{
358
struct bpf_liveness *liveness = env->liveness;
359
u32 idx, frame, curframe, old_must_write;
360
struct per_frame_masks *masks;
361
u64 mask;
362
363
if (!instance)
364
return 0;
365
366
curframe = instance->callchain.curframe;
367
idx = relative_idx(instance, liveness->write_insn_idx);
368
for (frame = 0; frame <= curframe; frame++) {
369
mask = liveness->write_masks_acc[frame];
370
/* avoid allocating frames for zero masks */
371
if (mask == 0 && !instance->must_write_set[idx])
372
continue;
373
masks = alloc_frame_masks(env, instance, frame, liveness->write_insn_idx);
374
if (IS_ERR(masks))
375
return PTR_ERR(masks);
376
old_must_write = masks->must_write;
377
/*
378
* If instruction at this callchain is seen for a first time, set must_write equal
379
* to @mask. Otherwise take intersection with the previous value.
380
*/
381
if (instance->must_write_set[idx])
382
mask &= old_must_write;
383
if (old_must_write != mask) {
384
masks->must_write = mask;
385
instance->updated = true;
386
}
387
if (old_must_write & ~mask)
388
instance->must_write_dropped = true;
389
}
390
instance->must_write_set[idx] = true;
391
liveness->write_insn_idx = 0;
392
return 0;
393
}
394
395
/*
396
* Merge stack writes marks in @env->liveness->write_masks_acc
397
* with information already in @env->liveness->cur_instance.
398
*/
399
int bpf_commit_stack_write_marks(struct bpf_verifier_env *env)
400
{
401
return commit_stack_write_marks(env, env->liveness->cur_instance);
402
}
403
404
static char *fmt_callchain(struct bpf_verifier_env *env, struct callchain *callchain)
405
{
406
char *buf_end = env->tmp_str_buf + sizeof(env->tmp_str_buf);
407
char *buf = env->tmp_str_buf;
408
int i;
409
410
buf += snprintf(buf, buf_end - buf, "(");
411
for (i = 0; i <= callchain->curframe; i++)
412
buf += snprintf(buf, buf_end - buf, "%s%d", i ? "," : "", callchain->callsites[i]);
413
snprintf(buf, buf_end - buf, ")");
414
return env->tmp_str_buf;
415
}
416
417
static void log_mask_change(struct bpf_verifier_env *env, struct callchain *callchain,
418
char *pfx, u32 frame, u32 insn_idx, u64 old, u64 new)
419
{
420
u64 changed_bits = old ^ new;
421
u64 new_ones = new & changed_bits;
422
u64 new_zeros = ~new & changed_bits;
423
424
if (!changed_bits)
425
return;
426
bpf_log(&env->log, "%s frame %d insn %d ", fmt_callchain(env, callchain), frame, insn_idx);
427
if (new_ones) {
428
bpf_fmt_stack_mask(env->tmp_str_buf, sizeof(env->tmp_str_buf), new_ones);
429
bpf_log(&env->log, "+%s %s ", pfx, env->tmp_str_buf);
430
}
431
if (new_zeros) {
432
bpf_fmt_stack_mask(env->tmp_str_buf, sizeof(env->tmp_str_buf), new_zeros);
433
bpf_log(&env->log, "-%s %s", pfx, env->tmp_str_buf);
434
}
435
bpf_log(&env->log, "\n");
436
}
437
438
int bpf_jmp_offset(struct bpf_insn *insn)
439
{
440
u8 code = insn->code;
441
442
if (code == (BPF_JMP32 | BPF_JA))
443
return insn->imm;
444
return insn->off;
445
}
446
447
__diag_push();
448
__diag_ignore_all("-Woverride-init", "Allow field initialization overrides for opcode_info_tbl");
449
450
/*
451
* Returns an array of instructions succ, with succ->items[0], ...,
452
* succ->items[n-1] with successor instructions, where n=succ->cnt
453
*/
454
inline struct bpf_iarray *
455
bpf_insn_successors(struct bpf_verifier_env *env, u32 idx)
456
{
457
static const struct opcode_info {
458
bool can_jump;
459
bool can_fallthrough;
460
} opcode_info_tbl[256] = {
461
[0 ... 255] = {.can_jump = false, .can_fallthrough = true},
462
#define _J(code, ...) \
463
[BPF_JMP | code] = __VA_ARGS__, \
464
[BPF_JMP32 | code] = __VA_ARGS__
465
466
_J(BPF_EXIT, {.can_jump = false, .can_fallthrough = false}),
467
_J(BPF_JA, {.can_jump = true, .can_fallthrough = false}),
468
_J(BPF_JEQ, {.can_jump = true, .can_fallthrough = true}),
469
_J(BPF_JNE, {.can_jump = true, .can_fallthrough = true}),
470
_J(BPF_JLT, {.can_jump = true, .can_fallthrough = true}),
471
_J(BPF_JLE, {.can_jump = true, .can_fallthrough = true}),
472
_J(BPF_JGT, {.can_jump = true, .can_fallthrough = true}),
473
_J(BPF_JGE, {.can_jump = true, .can_fallthrough = true}),
474
_J(BPF_JSGT, {.can_jump = true, .can_fallthrough = true}),
475
_J(BPF_JSGE, {.can_jump = true, .can_fallthrough = true}),
476
_J(BPF_JSLT, {.can_jump = true, .can_fallthrough = true}),
477
_J(BPF_JSLE, {.can_jump = true, .can_fallthrough = true}),
478
_J(BPF_JCOND, {.can_jump = true, .can_fallthrough = true}),
479
_J(BPF_JSET, {.can_jump = true, .can_fallthrough = true}),
480
#undef _J
481
};
482
struct bpf_prog *prog = env->prog;
483
struct bpf_insn *insn = &prog->insnsi[idx];
484
const struct opcode_info *opcode_info;
485
struct bpf_iarray *succ, *jt;
486
int insn_sz;
487
488
jt = env->insn_aux_data[idx].jt;
489
if (unlikely(jt))
490
return jt;
491
492
/* pre-allocated array of size up to 2; reset cnt, as it may have been used already */
493
succ = env->succ;
494
succ->cnt = 0;
495
496
opcode_info = &opcode_info_tbl[BPF_CLASS(insn->code) | BPF_OP(insn->code)];
497
insn_sz = bpf_is_ldimm64(insn) ? 2 : 1;
498
if (opcode_info->can_fallthrough)
499
succ->items[succ->cnt++] = idx + insn_sz;
500
501
if (opcode_info->can_jump)
502
succ->items[succ->cnt++] = idx + bpf_jmp_offset(insn) + 1;
503
504
return succ;
505
}
506
507
__diag_pop();
508
509
static struct func_instance *get_outer_instance(struct bpf_verifier_env *env,
510
struct func_instance *instance)
511
{
512
struct callchain callchain = instance->callchain;
513
514
/* Adjust @callchain to represent callchain one frame up */
515
callchain.callsites[callchain.curframe] = 0;
516
callchain.sp_starts[callchain.curframe] = 0;
517
callchain.curframe--;
518
callchain.callsites[callchain.curframe] = callchain.sp_starts[callchain.curframe];
519
return __lookup_instance(env, &callchain);
520
}
521
522
static u32 callchain_subprog_start(struct callchain *callchain)
523
{
524
return callchain->sp_starts[callchain->curframe];
525
}
526
527
/*
528
* Transfer @may_read and @must_write_acc marks from the first instruction of @instance,
529
* to the call instruction in function instance calling @instance.
530
*/
531
static int propagate_to_outer_instance(struct bpf_verifier_env *env,
532
struct func_instance *instance)
533
{
534
struct callchain *callchain = &instance->callchain;
535
u32 this_subprog_start, callsite, frame;
536
struct func_instance *outer_instance;
537
struct per_frame_masks *insn;
538
int err;
539
540
this_subprog_start = callchain_subprog_start(callchain);
541
outer_instance = get_outer_instance(env, instance);
542
if (IS_ERR(outer_instance))
543
return PTR_ERR(outer_instance);
544
callsite = callchain->callsites[callchain->curframe - 1];
545
546
reset_stack_write_marks(env, outer_instance, callsite);
547
for (frame = 0; frame < callchain->curframe; frame++) {
548
insn = get_frame_masks(instance, frame, this_subprog_start);
549
if (!insn)
550
continue;
551
bpf_mark_stack_write(env, frame, insn->must_write_acc);
552
err = mark_stack_read(env, outer_instance, frame, callsite, insn->live_before);
553
if (err)
554
return err;
555
}
556
commit_stack_write_marks(env, outer_instance);
557
return 0;
558
}
559
560
static inline bool update_insn(struct bpf_verifier_env *env,
561
struct func_instance *instance, u32 frame, u32 insn_idx)
562
{
563
struct bpf_insn_aux_data *aux = env->insn_aux_data;
564
u64 new_before, new_after, must_write_acc;
565
struct per_frame_masks *insn, *succ_insn;
566
struct bpf_iarray *succ;
567
u32 s;
568
bool changed;
569
570
succ = bpf_insn_successors(env, insn_idx);
571
if (succ->cnt == 0)
572
return false;
573
574
changed = false;
575
insn = get_frame_masks(instance, frame, insn_idx);
576
new_before = 0;
577
new_after = 0;
578
/*
579
* New "must_write_acc" is an intersection of all "must_write_acc"
580
* of successors plus all "must_write" slots of instruction itself.
581
*/
582
must_write_acc = U64_MAX;
583
for (s = 0; s < succ->cnt; ++s) {
584
succ_insn = get_frame_masks(instance, frame, succ->items[s]);
585
new_after |= succ_insn->live_before;
586
must_write_acc &= succ_insn->must_write_acc;
587
}
588
must_write_acc |= insn->must_write;
589
/*
590
* New "live_before" is a union of all "live_before" of successors
591
* minus slots written by instruction plus slots read by instruction.
592
*/
593
new_before = (new_after & ~insn->must_write) | insn->may_read;
594
changed |= new_before != insn->live_before;
595
changed |= must_write_acc != insn->must_write_acc;
596
if (unlikely(env->log.level & BPF_LOG_LEVEL2) &&
597
(insn->may_read || insn->must_write ||
598
insn_idx == callchain_subprog_start(&instance->callchain) ||
599
aux[insn_idx].prune_point)) {
600
log_mask_change(env, &instance->callchain, "live",
601
frame, insn_idx, insn->live_before, new_before);
602
log_mask_change(env, &instance->callchain, "written",
603
frame, insn_idx, insn->must_write_acc, must_write_acc);
604
}
605
insn->live_before = new_before;
606
insn->must_write_acc = must_write_acc;
607
return changed;
608
}
609
610
/* Fixed-point computation of @live_before and @must_write_acc marks */
611
static int update_instance(struct bpf_verifier_env *env, struct func_instance *instance)
612
{
613
u32 i, frame, po_start, po_end, cnt, this_subprog_start;
614
struct callchain *callchain = &instance->callchain;
615
int *insn_postorder = env->cfg.insn_postorder;
616
struct bpf_subprog_info *subprog;
617
struct per_frame_masks *insn;
618
bool changed;
619
int err;
620
621
this_subprog_start = callchain_subprog_start(callchain);
622
/*
623
* If must_write marks were updated must_write_acc needs to be reset
624
* (to account for the case when new must_write sets became smaller).
625
*/
626
if (instance->must_write_dropped) {
627
for (frame = 0; frame <= callchain->curframe; frame++) {
628
if (!instance->frames[frame])
629
continue;
630
631
for (i = 0; i < instance->insn_cnt; i++) {
632
insn = get_frame_masks(instance, frame, this_subprog_start + i);
633
insn->must_write_acc = 0;
634
}
635
}
636
}
637
638
subprog = bpf_find_containing_subprog(env, this_subprog_start);
639
po_start = subprog->postorder_start;
640
po_end = (subprog + 1)->postorder_start;
641
cnt = 0;
642
/* repeat until fixed point is reached */
643
do {
644
cnt++;
645
changed = false;
646
for (frame = 0; frame <= instance->callchain.curframe; frame++) {
647
if (!instance->frames[frame])
648
continue;
649
650
for (i = po_start; i < po_end; i++)
651
changed |= update_insn(env, instance, frame, insn_postorder[i]);
652
}
653
} while (changed);
654
655
if (env->log.level & BPF_LOG_LEVEL2)
656
bpf_log(&env->log, "%s live stack update done in %d iterations\n",
657
fmt_callchain(env, callchain), cnt);
658
659
/* transfer marks accumulated for outer frames to outer func instance (caller) */
660
if (callchain->curframe > 0) {
661
err = propagate_to_outer_instance(env, instance);
662
if (err)
663
return err;
664
}
665
666
return 0;
667
}
668
669
/*
670
* Prepare all callchains within @env->cur_state for querying.
671
* This function should be called after each verifier.c:pop_stack()
672
* and whenever verifier.c:do_check_insn() processes subprogram exit.
673
* This would guarantee that visited verifier states with zero branches
674
* have their bpf_mark_stack_{read,write}() effects propagated in
675
* @env->liveness.
676
*/
677
int bpf_update_live_stack(struct bpf_verifier_env *env)
678
{
679
struct func_instance *instance;
680
int err, frame;
681
682
bpf_reset_live_stack_callchain(env);
683
for (frame = env->cur_state->curframe; frame >= 0; --frame) {
684
instance = lookup_instance(env, env->cur_state, frame);
685
if (IS_ERR(instance))
686
return PTR_ERR(instance);
687
688
if (instance->updated) {
689
err = update_instance(env, instance);
690
if (err)
691
return err;
692
instance->updated = false;
693
instance->must_write_dropped = false;
694
}
695
}
696
return 0;
697
}
698
699
static bool is_live_before(struct func_instance *instance, u32 insn_idx, u32 frameno, u32 spi)
700
{
701
struct per_frame_masks *masks;
702
703
masks = get_frame_masks(instance, frameno, insn_idx);
704
return masks && (masks->live_before & BIT(spi));
705
}
706
707
int bpf_live_stack_query_init(struct bpf_verifier_env *env, struct bpf_verifier_state *st)
708
{
709
struct live_stack_query *q = &env->liveness->live_stack_query;
710
struct func_instance *instance;
711
u32 frame;
712
713
memset(q, 0, sizeof(*q));
714
for (frame = 0; frame <= st->curframe; frame++) {
715
instance = lookup_instance(env, st, frame);
716
if (IS_ERR(instance))
717
return PTR_ERR(instance);
718
q->instances[frame] = instance;
719
}
720
q->curframe = st->curframe;
721
q->insn_idx = st->insn_idx;
722
return 0;
723
}
724
725
bool bpf_stack_slot_alive(struct bpf_verifier_env *env, u32 frameno, u32 spi)
726
{
727
/*
728
* Slot is alive if it is read before q->st->insn_idx in current func instance,
729
* or if for some outer func instance:
730
* - alive before callsite if callsite calls callback, otherwise
731
* - alive after callsite
732
*/
733
struct live_stack_query *q = &env->liveness->live_stack_query;
734
struct func_instance *instance, *curframe_instance;
735
u32 i, callsite;
736
bool alive;
737
738
curframe_instance = q->instances[q->curframe];
739
if (is_live_before(curframe_instance, q->insn_idx, frameno, spi))
740
return true;
741
742
for (i = frameno; i < q->curframe; i++) {
743
callsite = curframe_instance->callchain.callsites[i];
744
instance = q->instances[i];
745
alive = bpf_calls_callback(env, callsite)
746
? is_live_before(instance, callsite, frameno, spi)
747
: is_live_before(instance, callsite + 1, frameno, spi);
748
if (alive)
749
return true;
750
}
751
752
return false;
753
}
754
755