8
8
#include <linux/netdevice.h>
9
9
#include <linux/filter.h>
10
10
#include <linux/if_vlan.h>
11
+ #include <linux/bitfield.h>
11
12
#include <linux/bpf.h>
12
13
#include <linux/memory.h>
13
14
#include <linux/sort.h>
@@ -1388,16 +1389,67 @@ static int emit_atomic_ld_st_index(u8 **pprog, u32 atomic_op, u32 size,
1388
1389
return 0 ;
1389
1390
}
1390
1391
1392
+ /*
1393
+ * Metadata encoding for exception handling in JITed code.
1394
+ *
1395
+ * Format of `fixup` and `data` fields in `struct exception_table_entry`:
1396
+ *
1397
+ * Bit layout of `fixup` (32-bit):
1398
+ *
1399
+ * +-----------+--------+-----------+---------+----------+
1400
+ * | 31 | 30-24 | 23-16 | 15-8 | 7-0 |
1401
+ * | | | | | |
1402
+ * | ARENA_ACC | Unused | ARENA_REG | DST_REG | INSN_LEN |
1403
+ * +-----------+--------+-----------+---------+----------+
1404
+ *
1405
+ * - INSN_LEN (8 bits): Length of faulting insn (max x86 insn = 15 bytes (fits in 8 bits)).
1406
+ * - DST_REG (8 bits): Offset of dst_reg from reg2pt_regs[] (max offset = 112 (fits in 8 bits)).
1407
+ * This is set to DONT_CLEAR if the insn is a store.
1408
+ * - ARENA_REG (8 bits): Offset of the register that is used to calculate the
1409
+ * address for load/store when accessing the arena region.
1410
+ * - ARENA_ACCESS (1 bit): This bit is set when the faulting instruction accessed the arena region.
1411
+ *
1412
+ * Bit layout of `data` (32-bit):
1413
+ *
1414
+ * +--------------+--------+--------------+
1415
+ * | 31-16 | 15-8 | 7-0 |
1416
+ * | | | |
1417
+ * | ARENA_OFFSET | Unused | EX_TYPE_BPF |
1418
+ * +--------------+--------+--------------+
1419
+ *
1420
+ * - ARENA_OFFSET (16 bits): Offset used to calculate the address for load/store when
1421
+ * accessing the arena region.
1422
+ */
1423
+
1391
1424
#define DONT_CLEAR 1
1425
+ #define FIXUP_INSN_LEN_MASK GENMASK(7, 0)
1426
+ #define FIXUP_REG_MASK GENMASK(15, 8)
1427
+ #define FIXUP_ARENA_REG_MASK GENMASK(23, 16)
1428
+ #define FIXUP_ARENA_ACCESS BIT(31)
1429
+ #define DATA_ARENA_OFFSET_MASK GENMASK(31, 16)
1392
1430
1393
1431
bool ex_handler_bpf (const struct exception_table_entry * x , struct pt_regs * regs )
1394
1432
{
1395
- u32 reg = x -> fixup >> 8 ;
1433
+ u32 reg = FIELD_GET (FIXUP_REG_MASK , x -> fixup );
1434
+ u32 insn_len = FIELD_GET (FIXUP_INSN_LEN_MASK , x -> fixup );
1435
+ bool is_arena = !!(x -> fixup & FIXUP_ARENA_ACCESS );
1436
+ bool is_write = (reg == DONT_CLEAR );
1437
+ unsigned long addr ;
1438
+ s16 off ;
1439
+ u32 arena_reg ;
1396
1440
1397
1441
/* jump over faulting load and clear dest register */
1398
1442
if (reg != DONT_CLEAR )
1399
1443
* (unsigned long * )((void * )regs + reg ) = 0 ;
1400
- regs -> ip += x -> fixup & 0xff ;
1444
+ regs -> ip += insn_len ;
1445
+
1446
+ if (is_arena ) {
1447
+ arena_reg = FIELD_GET (FIXUP_ARENA_REG_MASK , x -> data );
1448
+ off = FIELD_GET (DATA_ARENA_OFFSET_MASK , x -> data );
1449
+ addr = * (unsigned long * )((void * )regs + arena_reg ) + off ;
1450
+ bpf_prog_report_arena_violation (is_write , addr );
1451
+ }
1452
+
1401
1453
return true;
1402
1454
}
1403
1455
@@ -2070,6 +2122,8 @@ st: if (is_imm8(insn->off))
2070
2122
{
2071
2123
struct exception_table_entry * ex ;
2072
2124
u8 * _insn = image + proglen + (start_of_ldx - temp );
2125
+ u32 arena_reg , fixup_reg ;
2126
+ bool is_arena ;
2073
2127
s64 delta ;
2074
2128
2075
2129
if (!bpf_prog -> aux -> extable )
@@ -2089,8 +2143,25 @@ st: if (is_imm8(insn->off))
2089
2143
2090
2144
ex -> data = EX_TYPE_BPF ;
2091
2145
2092
- ex -> fixup = (prog - start_of_ldx ) |
2093
- ((BPF_CLASS (insn -> code ) == BPF_LDX ? reg2pt_regs [dst_reg ] : DONT_CLEAR ) << 8 );
2146
+ is_arena = (BPF_MODE (insn -> code ) == BPF_PROBE_MEM32 ) ||
2147
+ (BPF_MODE (insn -> code ) == BPF_PROBE_ATOMIC );
2148
+
2149
+ fixup_reg = (BPF_CLASS (insn -> code ) == BPF_LDX ) ?
2150
+ reg2pt_regs [dst_reg ] : DONT_CLEAR ;
2151
+
2152
+ ex -> fixup = FIELD_PREP (FIXUP_OFFSET_MASK , prog - start_of_ldx ) |
2153
+ FIELD_PREP (FIXUP_REG_MASK , fixup_reg );
2154
+
2155
+ if (is_arena ) {
2156
+ ex -> fixup |= FIXUP_ARENA_ACCESS ;
2157
+ if (BPF_CLASS (insn -> code ) == BPF_LDX )
2158
+ arena_reg = reg2pt_regs [src_reg ];
2159
+ else
2160
+ arena_reg = reg2pt_regs [dst_reg ];
2161
+
2162
+ ex -> fixup |= FIELD_PREP (FIXUP_ARENA_REG_MASK , arena_reg );
2163
+ ex -> data |= FIELD_PREP (DATA_ARENA_OFFSET_MASK , insn -> off );
2164
+ }
2094
2165
}
2095
2166
break ;
2096
2167
0 commit comments