cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

var_off.c (11491B)


      1{
      2	"variable-offset ctx access",
      3	.insns = {
      4	/* Get an unknown value */
      5	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
      6	/* Make it small and 4-byte aligned */
      7	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
      8	/* add it to skb.  We now have either &skb->len or
      9	 * &skb->pkt_type, but we don't know which
     10	 */
     11	BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
     12	/* dereference it */
     13	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
     14	BPF_EXIT_INSN(),
     15	},
     16	.errstr = "variable ctx access var_off=(0x0; 0x4)",
     17	.result = REJECT,
     18	.prog_type = BPF_PROG_TYPE_LWT_IN,
     19},
     20{
     21	"variable-offset stack read, priv vs unpriv",
     22	.insns = {
     23	/* Fill the top 8 bytes of the stack */
     24	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
     25	/* Get an unknown value */
     26	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
     27	/* Make it small and 4-byte aligned */
     28	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
     29	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
     30	/* add it to fp.  We now have either fp-4 or fp-8, but
     31	 * we don't know which
     32	 */
     33	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
     34	/* dereference it for a stack read */
     35	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
     36	BPF_MOV64_IMM(BPF_REG_0, 0),
     37	BPF_EXIT_INSN(),
     38	},
     39	.result = ACCEPT,
     40	.result_unpriv = REJECT,
     41	.errstr_unpriv = "R2 variable stack access prohibited for !root",
     42	.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
     43},
     44{
     45	"variable-offset stack read, uninitialized",
     46	.insns = {
     47	/* Get an unknown value */
     48	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
     49	/* Make it small and 4-byte aligned */
     50	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
     51	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
     52	/* add it to fp.  We now have either fp-4 or fp-8, but
     53	 * we don't know which
     54	 */
     55	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
     56	/* dereference it for a stack read */
     57	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
     58	BPF_MOV64_IMM(BPF_REG_0, 0),
     59	BPF_EXIT_INSN(),
     60	},
     61	.result = REJECT,
     62	.errstr = "invalid variable-offset read from stack R2",
     63	.prog_type = BPF_PROG_TYPE_LWT_IN,
     64},
     65{
     66	"variable-offset stack write, priv vs unpriv",
     67	.insns = {
     68	/* Get an unknown value */
     69	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
     70	/* Make it small and 8-byte aligned */
     71	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
     72	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
     73	/* Add it to fp.  We now have either fp-8 or fp-16, but
     74	 * we don't know which
     75	 */
     76	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
     77	/* Dereference it for a stack write */
     78	BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
     79	/* Now read from the address we just wrote. This shows
     80	 * that, after a variable-offset write, a priviledged
     81	 * program can read the slots that were in the range of
     82	 * that write (even if the verifier doesn't actually know
     83	 * if the slot being read was really written to or not.
     84	 */
     85	BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, 0),
     86	BPF_MOV64_IMM(BPF_REG_0, 0),
     87	BPF_EXIT_INSN(),
     88	},
     89	/* Variable stack access is rejected for unprivileged.
     90	 */
     91	.errstr_unpriv = "R2 variable stack access prohibited for !root",
     92	.result_unpriv = REJECT,
     93	.result = ACCEPT,
     94},
     95{
     96	"variable-offset stack write clobbers spilled regs",
     97	.insns = {
     98	/* Dummy instruction; needed because we need to patch the next one
     99	 * and we can't patch the first instruction.
    100	 */
    101	BPF_MOV64_IMM(BPF_REG_6, 0),
    102	/* Make R0 a map ptr */
    103	BPF_LD_MAP_FD(BPF_REG_0, 0),
    104	/* Get an unknown value */
    105	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
    106	/* Make it small and 8-byte aligned */
    107	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
    108	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
    109	/* Add it to fp. We now have either fp-8 or fp-16, but
    110	 * we don't know which.
    111	 */
    112	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
    113	/* Spill R0(map ptr) into stack */
    114	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
    115	/* Dereference the unknown value for a stack write */
    116	BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
    117	/* Fill the register back into R2 */
    118	BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8),
    119	/* Try to dereference R2 for a memory load */
    120	BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8),
    121	BPF_EXIT_INSN(),
    122	},
    123	.fixup_map_hash_8b = { 1 },
    124	/* The unpriviledged case is not too interesting; variable
    125	 * stack access is rejected.
    126	 */
    127	.errstr_unpriv = "R2 variable stack access prohibited for !root",
    128	.result_unpriv = REJECT,
    129	/* In the priviledged case, dereferencing a spilled-and-then-filled
    130	 * register is rejected because the previous variable offset stack
    131	 * write might have overwritten the spilled pointer (i.e. we lose track
    132	 * of the spilled register when we analyze the write).
    133	 */
    134	.errstr = "R2 invalid mem access 'scalar'",
    135	.result = REJECT,
    136},
    137{
    138	"indirect variable-offset stack access, unbounded",
    139	.insns = {
    140	BPF_MOV64_IMM(BPF_REG_2, 6),
    141	BPF_MOV64_IMM(BPF_REG_3, 28),
    142	/* Fill the top 16 bytes of the stack. */
    143	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
    144	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    145	/* Get an unknown value. */
    146	BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_sock_ops,
    147							   bytes_received)),
    148	/* Check the lower bound but don't check the upper one. */
    149	BPF_JMP_IMM(BPF_JSLT, BPF_REG_4, 0, 4),
    150	/* Point the lower bound to initialized stack. Offset is now in range
    151	 * from fp-16 to fp+0x7fffffffffffffef, i.e. max value is unbounded.
    152	 */
    153	BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
    154	BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
    155	BPF_MOV64_IMM(BPF_REG_5, 8),
    156	/* Dereference it indirectly. */
    157	BPF_EMIT_CALL(BPF_FUNC_getsockopt),
    158	BPF_MOV64_IMM(BPF_REG_0, 0),
    159	BPF_EXIT_INSN(),
    160	},
    161	.errstr = "invalid unbounded variable-offset indirect access to stack R4",
    162	.result = REJECT,
    163	.prog_type = BPF_PROG_TYPE_SOCK_OPS,
    164},
    165{
    166	"indirect variable-offset stack access, max out of bound",
    167	.insns = {
    168	/* Fill the top 8 bytes of the stack */
    169	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    170	/* Get an unknown value */
    171	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
    172	/* Make it small and 4-byte aligned */
    173	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
    174	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
    175	/* add it to fp.  We now have either fp-4 or fp-8, but
    176	 * we don't know which
    177	 */
    178	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
    179	/* dereference it indirectly */
    180	BPF_LD_MAP_FD(BPF_REG_1, 0),
    181	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    182	BPF_MOV64_IMM(BPF_REG_0, 0),
    183	BPF_EXIT_INSN(),
    184	},
    185	.fixup_map_hash_8b = { 5 },
    186	.errstr = "invalid variable-offset indirect access to stack R2",
    187	.result = REJECT,
    188	.prog_type = BPF_PROG_TYPE_LWT_IN,
    189},
    190{
    191	"indirect variable-offset stack access, min out of bound",
    192	.insns = {
    193	/* Fill the top 8 bytes of the stack */
    194	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    195	/* Get an unknown value */
    196	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
    197	/* Make it small and 4-byte aligned */
    198	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
    199	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 516),
    200	/* add it to fp.  We now have either fp-516 or fp-512, but
    201	 * we don't know which
    202	 */
    203	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
    204	/* dereference it indirectly */
    205	BPF_LD_MAP_FD(BPF_REG_1, 0),
    206	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    207	BPF_MOV64_IMM(BPF_REG_0, 0),
    208	BPF_EXIT_INSN(),
    209	},
    210	.fixup_map_hash_8b = { 5 },
    211	.errstr = "invalid variable-offset indirect access to stack R2",
    212	.result = REJECT,
    213	.prog_type = BPF_PROG_TYPE_LWT_IN,
    214},
    215{
    216	"indirect variable-offset stack access, max_off+size > max_initialized",
    217	.insns = {
    218	/* Fill only the second from top 8 bytes of the stack. */
    219	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
    220	/* Get an unknown value. */
    221	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
    222	/* Make it small and 4-byte aligned. */
    223	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
    224	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
    225	/* Add it to fp.  We now have either fp-12 or fp-16, but we don't know
    226	 * which. fp-12 size 8 is partially uninitialized stack.
    227	 */
    228	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
    229	/* Dereference it indirectly. */
    230	BPF_LD_MAP_FD(BPF_REG_1, 0),
    231	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
    232	BPF_MOV64_IMM(BPF_REG_0, 0),
    233	BPF_EXIT_INSN(),
    234	},
    235	.fixup_map_hash_8b = { 5 },
    236	.errstr = "invalid indirect read from stack R2 var_off",
    237	.result = REJECT,
    238	.prog_type = BPF_PROG_TYPE_LWT_IN,
    239},
    240{
    241	"indirect variable-offset stack access, min_off < min_initialized",
    242	.insns = {
    243	/* Fill only the top 8 bytes of the stack. */
    244	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    245	/* Get an unknown value */
    246	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
    247	/* Make it small and 4-byte aligned. */
    248	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
    249	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
    250	/* Add it to fp.  We now have either fp-12 or fp-16, but we don't know
    251	 * which. fp-16 size 8 is partially uninitialized stack.
    252	 */
    253	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
    254	/* Dereference it indirectly. */
    255	BPF_LD_MAP_FD(BPF_REG_1, 0),
    256	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
    257	BPF_MOV64_IMM(BPF_REG_0, 0),
    258	BPF_EXIT_INSN(),
    259	},
    260	.fixup_map_hash_8b = { 5 },
    261	.errstr = "invalid indirect read from stack R2 var_off",
    262	.result = REJECT,
    263	.prog_type = BPF_PROG_TYPE_LWT_IN,
    264},
    265{
    266	"indirect variable-offset stack access, priv vs unpriv",
    267	.insns = {
    268	/* Fill the top 16 bytes of the stack. */
    269	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
    270	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    271	/* Get an unknown value. */
    272	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
    273	/* Make it small and 4-byte aligned. */
    274	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
    275	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
    276	/* Add it to fp.  We now have either fp-12 or fp-16, we don't know
    277	 * which, but either way it points to initialized stack.
    278	 */
    279	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
    280	/* Dereference it indirectly. */
    281	BPF_LD_MAP_FD(BPF_REG_1, 0),
    282	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
    283	BPF_MOV64_IMM(BPF_REG_0, 0),
    284	BPF_EXIT_INSN(),
    285	},
    286	.fixup_map_hash_8b = { 6 },
    287	.errstr_unpriv = "R2 variable stack access prohibited for !root",
    288	.result_unpriv = REJECT,
    289	.result = ACCEPT,
    290	.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
    291},
    292{
    293	"indirect variable-offset stack access, uninitialized",
    294	.insns = {
    295	BPF_MOV64_IMM(BPF_REG_2, 6),
    296	BPF_MOV64_IMM(BPF_REG_3, 28),
    297	/* Fill the top 16 bytes of the stack. */
    298	BPF_ST_MEM(BPF_W, BPF_REG_10, -16, 0),
    299	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    300	/* Get an unknown value. */
    301	BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, 0),
    302	/* Make it small and 4-byte aligned. */
    303	BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 4),
    304	BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
    305	/* Add it to fp.  We now have either fp-12 or fp-16, we don't know
    306	 * which, but either way it points to initialized stack.
    307	 */
    308	BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
    309	BPF_MOV64_IMM(BPF_REG_5, 8),
    310	/* Dereference it indirectly. */
    311	BPF_EMIT_CALL(BPF_FUNC_getsockopt),
    312	BPF_MOV64_IMM(BPF_REG_0, 0),
    313	BPF_EXIT_INSN(),
    314	},
    315	.errstr = "invalid indirect read from stack R4 var_off",
    316	.result = REJECT,
    317	.prog_type = BPF_PROG_TYPE_SOCK_OPS,
    318},
    319{
    320	"indirect variable-offset stack access, ok",
    321	.insns = {
    322	/* Fill the top 16 bytes of the stack. */
    323	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
    324	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    325	/* Get an unknown value. */
    326	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
    327	/* Make it small and 4-byte aligned. */
    328	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
    329	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
    330	/* Add it to fp.  We now have either fp-12 or fp-16, we don't know
    331	 * which, but either way it points to initialized stack.
    332	 */
    333	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
    334	/* Dereference it indirectly. */
    335	BPF_LD_MAP_FD(BPF_REG_1, 0),
    336	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
    337	BPF_MOV64_IMM(BPF_REG_0, 0),
    338	BPF_EXIT_INSN(),
    339	},
    340	.fixup_map_hash_8b = { 6 },
    341	.result = ACCEPT,
    342	.prog_type = BPF_PROG_TYPE_LWT_IN,
    343},