@@ -1428,6 +1428,8 @@ static int copy_reference_state(struct bpf_verifier_state *dst, const struct bpf
1428
1428
dst->active_preempt_locks = src->active_preempt_locks;
1429
1429
dst->active_rcu_lock = src->active_rcu_lock;
1430
1430
dst->active_irq_id = src->active_irq_id;
1431
+ dst->active_lock_id = src->active_lock_id;
1432
+ dst->active_lock_ptr = src->active_lock_ptr;
1431
1433
return 0;
1432
1434
}
1433
1435
@@ -1527,6 +1529,8 @@ static int acquire_lock_state(struct bpf_verifier_env *env, int insn_idx, enum r
1527
1529
s->ptr = ptr;
1528
1530
1529
1531
state->active_locks++;
1532
+ state->active_lock_id = id;
1533
+ state->active_lock_ptr = ptr;
1530
1534
return 0;
1531
1535
}
1532
1536
@@ -1577,16 +1581,24 @@ static bool find_reference_state(struct bpf_verifier_state *state, int ptr_id)
1577
1581
1578
1582
static int release_lock_state(struct bpf_verifier_state *state, int type, int id, void *ptr)
1579
1583
{
1584
+ void *prev_ptr = NULL;
1585
+ u32 prev_id = 0;
1580
1586
int i;
1581
1587
1582
1588
for (i = 0; i < state->acquired_refs; i++) {
1583
- if (state->refs[i].type != type)
1584
- continue;
1585
- if (state->refs[i].id == id && state->refs[i].ptr == ptr) {
1589
+ if (state->refs[i].type == type && state->refs[i].id == id &&
1590
+ state->refs[i].ptr == ptr) {
1586
1591
release_reference_state(state, i);
1587
1592
state->active_locks--;
1593
+ /* Reassign active lock (id, ptr). */
1594
+ state->active_lock_id = prev_id;
1595
+ state->active_lock_ptr = prev_ptr;
1588
1596
return 0;
1589
1597
}
1598
+ if (state->refs[i].type & REF_TYPE_LOCK_MASK) {
1599
+ prev_id = state->refs[i].id;
1600
+ prev_ptr = state->refs[i].ptr;
1601
+ }
1590
1602
}
1591
1603
return -EINVAL;
1592
1604
}
@@ -8342,6 +8354,14 @@ static int process_spin_lock(struct bpf_verifier_env *env, int regno, int flags)
8342
8354
type = REF_TYPE_RES_LOCK;
8343
8355
else
8344
8356
type = REF_TYPE_LOCK;
8357
+ if (!find_lock_state(cur, type, reg->id, ptr)) {
8358
+ verbose(env, "%s_unlock of different lock\n", lock_str);
8359
+ return -EINVAL;
8360
+ }
8361
+ if (reg->id != cur->active_lock_id || ptr != cur->active_lock_ptr) {
8362
+ verbose(env, "%s_unlock cannot be out of order\n", lock_str);
8363
+ return -EINVAL;
8364
+ }
8345
8365
if (release_lock_state(cur, type, reg->id, ptr)) {
8346
8366
verbose(env, "%s_unlock of different lock\n", lock_str);
8347
8367
return -EINVAL;
@@ -12534,8 +12554,7 @@ static int check_reg_allocation_locked(struct bpf_verifier_env *env, struct bpf_
12534
12554
12535
12555
if (!env->cur_state->active_locks)
12536
12556
return -EINVAL;
12537
- s = find_lock_state(env->cur_state, REF_TYPE_LOCK | REF_TYPE_RES_LOCK | REF_TYPE_RES_LOCK_IRQ,
12538
- id, ptr);
12557
+ s = find_lock_state(env->cur_state, REF_TYPE_LOCK_MASK, id, ptr);
12539
12558
if (!s) {
12540
12559
verbose(env, "held lock and object are not in the same allocation\n");
12541
12560
return -EINVAL;
@@ -18591,6 +18610,10 @@ static bool refsafe(struct bpf_verifier_state *old, struct bpf_verifier_state *c
18591
18610
if (!check_ids(old->active_irq_id, cur->active_irq_id, idmap))
18592
18611
return false;
18593
18612
18613
+ if (!check_ids(old->active_lock_id, cur->active_lock_id, idmap) ||
18614
+ old->active_lock_ptr != cur->active_lock_ptr)
18615
+ return false;
18616
+
18594
18617
for (i = 0; i < old->acquired_refs; i++) {
18595
18618
if (!check_ids(old->refs[i].id, cur->refs[i].id, idmap) ||
18596
18619
old->refs[i].type != cur->refs[i].type)
0 commit comments