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

array_access.c (12358B)


      1{
      2	"valid map access into an array with a constant",
      3	.insns = {
      4	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
      5	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
      6	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
      7	BPF_LD_MAP_FD(BPF_REG_1, 0),
      8	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
      9	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
     10	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
     11	BPF_EXIT_INSN(),
     12	},
     13	.fixup_map_hash_48b = { 3 },
     14	.errstr_unpriv = "R0 leaks addr",
     15	.result_unpriv = REJECT,
     16	.result = ACCEPT,
     17},
     18{
     19	"valid map access into an array with a register",
     20	.insns = {
     21	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
     22	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
     23	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
     24	BPF_LD_MAP_FD(BPF_REG_1, 0),
     25	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
     26	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
     27	BPF_MOV64_IMM(BPF_REG_1, 4),
     28	BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
     29	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
     30	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
     31	BPF_EXIT_INSN(),
     32	},
     33	.fixup_map_hash_48b = { 3 },
     34	.errstr_unpriv = "R0 leaks addr",
     35	.result_unpriv = REJECT,
     36	.result = ACCEPT,
     37	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
     38},
     39{
     40	"valid map access into an array with a variable",
     41	.insns = {
     42	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
     43	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
     44	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
     45	BPF_LD_MAP_FD(BPF_REG_1, 0),
     46	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
     47	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
     48	BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
     49	BPF_JMP_IMM(BPF_JGE, BPF_REG_1, MAX_ENTRIES, 3),
     50	BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
     51	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
     52	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
     53	BPF_EXIT_INSN(),
     54	},
     55	.fixup_map_hash_48b = { 3 },
     56	.errstr_unpriv = "R0 leaks addr",
     57	.result_unpriv = REJECT,
     58	.result = ACCEPT,
     59	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
     60},
     61{
     62	"valid map access into an array with a signed variable",
     63	.insns = {
     64	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
     65	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
     66	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
     67	BPF_LD_MAP_FD(BPF_REG_1, 0),
     68	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
     69	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 9),
     70	BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
     71	BPF_JMP32_IMM(BPF_JSGT, BPF_REG_1, 0xffffffff, 1),
     72	BPF_MOV32_IMM(BPF_REG_1, 0),
     73	BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES),
     74	BPF_JMP_REG(BPF_JSGT, BPF_REG_2, BPF_REG_1, 1),
     75	BPF_MOV32_IMM(BPF_REG_1, 0),
     76	BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 2),
     77	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
     78	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
     79	BPF_EXIT_INSN(),
     80	},
     81	.fixup_map_hash_48b = { 3 },
     82	.errstr_unpriv = "R0 leaks addr",
     83	.result_unpriv = REJECT,
     84	.result = ACCEPT,
     85	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
     86},
     87{
     88	"invalid map access into an array with a constant",
     89	.insns = {
     90	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
     91	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
     92	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
     93	BPF_LD_MAP_FD(BPF_REG_1, 0),
     94	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
     95	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
     96	BPF_ST_MEM(BPF_DW, BPF_REG_0, (MAX_ENTRIES + 1) << 2,
     97		   offsetof(struct test_val, foo)),
     98	BPF_EXIT_INSN(),
     99	},
    100	.fixup_map_hash_48b = { 3 },
    101	.errstr = "invalid access to map value, value_size=48 off=48 size=8",
    102	.result = REJECT,
    103},
    104{
    105	"invalid map access into an array with a register",
    106	.insns = {
    107	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    108	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    109	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    110	BPF_LD_MAP_FD(BPF_REG_1, 0),
    111	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    112	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
    113	BPF_MOV64_IMM(BPF_REG_1, MAX_ENTRIES + 1),
    114	BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
    115	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
    116	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
    117	BPF_EXIT_INSN(),
    118	},
    119	.fixup_map_hash_48b = { 3 },
    120	.errstr = "R0 min value is outside of the allowed memory range",
    121	.result = REJECT,
    122	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
    123},
    124{
    125	"invalid map access into an array with a variable",
    126	.insns = {
    127	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    128	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    129	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    130	BPF_LD_MAP_FD(BPF_REG_1, 0),
    131	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    132	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
    133	BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
    134	BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2),
    135	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
    136	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
    137	BPF_EXIT_INSN(),
    138	},
    139	.fixup_map_hash_48b = { 3 },
    140	.errstr = "R0 unbounded memory access, make sure to bounds check any such access",
    141	.result = REJECT,
    142	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
    143},
    144{
    145	"invalid map access into an array with no floor check",
    146	.insns = {
    147	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    148	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    149	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    150	BPF_LD_MAP_FD(BPF_REG_1, 0),
    151	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    152	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
    153	BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
    154	BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES),
    155	BPF_JMP_REG(BPF_JSGT, BPF_REG_2, BPF_REG_1, 1),
    156	BPF_MOV32_IMM(BPF_REG_1, 0),
    157	BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 2),
    158	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
    159	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
    160	BPF_EXIT_INSN(),
    161	},
    162	.fixup_map_hash_48b = { 3 },
    163	.errstr_unpriv = "R0 leaks addr",
    164	.errstr = "R0 unbounded memory access",
    165	.result_unpriv = REJECT,
    166	.result = REJECT,
    167	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
    168},
    169{
    170	"invalid map access into an array with a invalid max check",
    171	.insns = {
    172	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    173	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    174	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    175	BPF_LD_MAP_FD(BPF_REG_1, 0),
    176	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    177	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
    178	BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
    179	BPF_MOV32_IMM(BPF_REG_2, MAX_ENTRIES + 1),
    180	BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_1, 1),
    181	BPF_MOV32_IMM(BPF_REG_1, 0),
    182	BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 2),
    183	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
    184	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)),
    185	BPF_EXIT_INSN(),
    186	},
    187	.fixup_map_hash_48b = { 3 },
    188	.errstr_unpriv = "R0 leaks addr",
    189	.errstr = "invalid access to map value, value_size=48 off=44 size=8",
    190	.result_unpriv = REJECT,
    191	.result = REJECT,
    192	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
    193},
    194{
    195	"invalid map access into an array with a invalid max check",
    196	.insns = {
    197	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    198	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    199	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    200	BPF_LD_MAP_FD(BPF_REG_1, 0),
    201	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    202	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 10),
    203	BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
    204	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    205	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    206	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    207	BPF_LD_MAP_FD(BPF_REG_1, 0),
    208	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    209	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
    210	BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_8),
    211	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0,
    212		    offsetof(struct test_val, foo)),
    213	BPF_EXIT_INSN(),
    214	},
    215	.fixup_map_hash_48b = { 3, 11 },
    216	.errstr = "R0 pointer += pointer",
    217	.result = REJECT,
    218	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
    219},
    220{
    221	"valid read map access into a read-only array 1",
    222	.insns = {
    223	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    224	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    225	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    226	BPF_LD_MAP_FD(BPF_REG_1, 0),
    227	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    228	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
    229	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0),
    230	BPF_EXIT_INSN(),
    231	},
    232	.fixup_map_array_ro = { 3 },
    233	.result = ACCEPT,
    234	.retval = 28,
    235},
    236{
    237	"valid read map access into a read-only array 2",
    238	.insns = {
    239	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    240	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    241	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    242	BPF_LD_MAP_FD(BPF_REG_1, 0),
    243	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    244	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
    245
    246	BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
    247	BPF_MOV64_IMM(BPF_REG_2, 4),
    248	BPF_MOV64_IMM(BPF_REG_3, 0),
    249	BPF_MOV64_IMM(BPF_REG_4, 0),
    250	BPF_MOV64_IMM(BPF_REG_5, 0),
    251	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
    252		     BPF_FUNC_csum_diff),
    253	BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffff),
    254	BPF_EXIT_INSN(),
    255	},
    256	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
    257	.fixup_map_array_ro = { 3 },
    258	.result = ACCEPT,
    259	.retval = 65507,
    260},
    261{
    262	"invalid write map access into a read-only array 1",
    263	.insns = {
    264	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    265	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    266	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    267	BPF_LD_MAP_FD(BPF_REG_1, 0),
    268	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    269	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
    270	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42),
    271	BPF_EXIT_INSN(),
    272	},
    273	.fixup_map_array_ro = { 3 },
    274	.result = REJECT,
    275	.errstr = "write into map forbidden",
    276},
    277{
    278	"invalid write map access into a read-only array 2",
    279	.insns = {
    280	BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
    281	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    282	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    283	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    284	BPF_LD_MAP_FD(BPF_REG_1, 0),
    285	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    286	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
    287	BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
    288	BPF_MOV64_IMM(BPF_REG_2, 0),
    289	BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
    290	BPF_MOV64_IMM(BPF_REG_4, 8),
    291	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
    292		     BPF_FUNC_skb_load_bytes),
    293	BPF_EXIT_INSN(),
    294	},
    295	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
    296	.fixup_map_array_ro = { 4 },
    297	.result = REJECT,
    298	.errstr = "write into map forbidden",
    299},
    300{
    301	"valid write map access into a write-only array 1",
    302	.insns = {
    303	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    304	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    305	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    306	BPF_LD_MAP_FD(BPF_REG_1, 0),
    307	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    308	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
    309	BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42),
    310	BPF_MOV64_IMM(BPF_REG_0, 1),
    311	BPF_EXIT_INSN(),
    312	},
    313	.fixup_map_array_wo = { 3 },
    314	.result = ACCEPT,
    315	.retval = 1,
    316},
    317{
    318	"valid write map access into a write-only array 2",
    319	.insns = {
    320	BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
    321	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    322	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    323	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    324	BPF_LD_MAP_FD(BPF_REG_1, 0),
    325	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    326	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
    327	BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
    328	BPF_MOV64_IMM(BPF_REG_2, 0),
    329	BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
    330	BPF_MOV64_IMM(BPF_REG_4, 8),
    331	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
    332		     BPF_FUNC_skb_load_bytes),
    333	BPF_EXIT_INSN(),
    334	},
    335	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
    336	.fixup_map_array_wo = { 4 },
    337	.result = ACCEPT,
    338	.retval = 0,
    339},
    340{
    341	"invalid read map access into a write-only array 1",
    342	.insns = {
    343	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    344	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    345	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    346	BPF_LD_MAP_FD(BPF_REG_1, 0),
    347	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    348	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
    349	BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0),
    350	BPF_EXIT_INSN(),
    351	},
    352	.fixup_map_array_wo = { 3 },
    353	.result = REJECT,
    354	.errstr = "read from map forbidden",
    355},
    356{
    357	"invalid read map access into a write-only array 2",
    358	.insns = {
    359	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
    360	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
    361	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
    362	BPF_LD_MAP_FD(BPF_REG_1, 0),
    363	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
    364	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
    365
    366	BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
    367	BPF_MOV64_IMM(BPF_REG_2, 4),
    368	BPF_MOV64_IMM(BPF_REG_3, 0),
    369	BPF_MOV64_IMM(BPF_REG_4, 0),
    370	BPF_MOV64_IMM(BPF_REG_5, 0),
    371	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
    372		     BPF_FUNC_csum_diff),
    373	BPF_EXIT_INSN(),
    374	},
    375	.prog_type = BPF_PROG_TYPE_SCHED_CLS,
    376	.fixup_map_array_wo = { 3 },
    377	.result = REJECT,
    378	.errstr = "read from map forbidden",
    379},