@@ -1333,10 +1333,16 @@ static int validate_code(struct jit_ctx *ctx)
1333
1333
1334
1334
for (i = 0 ; i < ctx -> idx ; i ++ ) {
1335
1335
u32 a64_insn = le32_to_cpu (ctx -> image [i ]);
1336
-
1337
1336
if (a64_insn == AARCH64_BREAK_FAULT )
1338
1337
return -1 ;
1339
1338
}
1339
+ return 0 ;
1340
+ }
1341
+
1342
+ static int validate_ctx (struct jit_ctx * ctx )
1343
+ {
1344
+ if (validate_code (ctx ))
1345
+ return -1 ;
1340
1346
1341
1347
if (WARN_ON_ONCE (ctx -> exentry_idx != ctx -> prog -> aux -> num_exentries ))
1342
1348
return -1 ;
@@ -1461,7 +1467,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
1461
1467
build_epilogue (& ctx );
1462
1468
1463
1469
/* 3. Extra pass to validate JITed code. */
1464
- if (validate_code (& ctx )) {
1470
+ if (validate_ctx (& ctx )) {
1465
1471
bpf_jit_binary_free (header );
1466
1472
prog = orig_prog ;
1467
1473
goto out_off ;
@@ -1532,6 +1538,334 @@ void bpf_jit_free_exec(void *addr)
1532
1538
return vfree (addr );
1533
1539
}
1534
1540
1541
+ static void invoke_bpf_prog (struct jit_ctx * ctx , struct bpf_prog * p ,
1542
+ int args_off , int retval_off , bool save_ret )
1543
+ {
1544
+ u32 * branch ;
1545
+ u64 enter_prog ;
1546
+ u64 exit_prog ;
1547
+ u8 tmp = bpf2a64 [TMP_REG_1 ];
1548
+ u8 r0 = bpf2a64 [BPF_REG_0 ];
1549
+
1550
+ if (p -> aux -> sleepable ) {
1551
+ enter_prog = (u64 )__bpf_prog_enter_sleepable ;
1552
+ exit_prog = (u64 )__bpf_prog_exit_sleepable ;
1553
+ } else {
1554
+ enter_prog = (u64 )__bpf_prog_enter ;
1555
+ exit_prog = (u64 )__bpf_prog_exit ;
1556
+ }
1557
+
1558
+ /* bl __bpf_prog_enter */
1559
+ emit_addr_mov_i64 (A64_R (0 ), (const u64 )p , ctx );
1560
+ emit_addr_mov_i64 (tmp , enter_prog , ctx );
1561
+ emit (A64_BLR (tmp ), ctx );
1562
+
1563
+ /*
1564
+ * if (__bpf_prog_enter(prog) == 0)
1565
+ * goto skip_exec_of_prog;
1566
+ */
1567
+ branch = ctx -> image + ctx -> idx ;
1568
+ emit (A64_NOP , ctx );
1569
+
1570
+ /* move return value to x19 */
1571
+ emit (A64_MOV (1 , A64_R (19 ), r0 ), ctx );
1572
+
1573
+ /* bl bpf_prog */
1574
+ emit (A64_ADD_I (1 , A64_R (0 ), A64_SP , args_off ), ctx );
1575
+ if (!p -> jited )
1576
+ emit_addr_mov_i64 (A64_R (1 ), (const u64 )p -> insnsi , ctx );
1577
+ emit_addr_mov_i64 (tmp , (const u64 )p -> bpf_func , ctx );
1578
+ emit (A64_BLR (tmp ), ctx );
1579
+
1580
+ /* store return value */
1581
+ if (save_ret )
1582
+ emit (A64_STR64I (r0 , A64_SP , retval_off ), ctx );
1583
+
1584
+ if (ctx -> image ) {
1585
+ int offset = & ctx -> image [ctx -> idx ] - branch ;
1586
+ * branch = A64_CBZ (1 , A64_R (0 ), offset );
1587
+ }
1588
+
1589
+ /* bl __bpf_prog_exit */
1590
+ emit_addr_mov_i64 (A64_R (0 ), (const u64 )p , ctx );
1591
+ emit (A64_MOV (1 , A64_R (1 ), A64_R (19 )), ctx );
1592
+ emit_addr_mov_i64 (tmp , exit_prog , ctx );
1593
+ emit (A64_BLR (tmp ), ctx );
1594
+ }
1595
+
1596
+ static void invoke_bpf_mod_ret (struct jit_ctx * ctx , struct bpf_tramp_progs * tp ,
1597
+ int args_off , int retval_off , u32 * * branches )
1598
+ {
1599
+ int i ;
1600
+
1601
+ /* The first fmod_ret program will receive a garbage return value.
1602
+ * Set this to 0 to avoid confusing the program.
1603
+ */
1604
+ emit (A64_STR64I (A64_ZR , A64_SP , retval_off ), ctx );
1605
+ for (i = 0 ; i < tp -> nr_progs ; i ++ ) {
1606
+ invoke_bpf_prog (ctx , tp -> progs [i ], args_off , retval_off , true);
1607
+ /*
1608
+ * if (*(u64 *)(sp + retval_off) != 0)
1609
+ * goto do_fexit;
1610
+ */
1611
+ emit (A64_LDR64I (A64_R (10 ), A64_SP , retval_off ), ctx );
1612
+ /* Save the location of branch, and generate a nop.
1613
+ * This nop will be replaced with a cbnz later.
1614
+ */
1615
+ branches [i ] = ctx -> image + ctx -> idx ;
1616
+ emit (A64_NOP , ctx );
1617
+ }
1618
+ }
1619
+
1620
+ static void save_args (struct jit_ctx * ctx , int args_off , int nargs )
1621
+ {
1622
+ int i ;
1623
+
1624
+ for (i = 0 ; i < nargs ; i ++ ) {
1625
+ emit (A64_STR64I (i , A64_SP , args_off ), ctx );
1626
+ args_off += 8 ;
1627
+ }
1628
+ }
1629
+
1630
+ static void restore_args (struct jit_ctx * ctx , int args_off , int nargs )
1631
+ {
1632
+ int i ;
1633
+
1634
+ for (i = 0 ; i < nargs ; i ++ ) {
1635
+ emit (A64_LDR64I (i , A64_SP , args_off ), ctx );
1636
+ args_off += 8 ;
1637
+ }
1638
+ }
1639
+
1640
+ /*
1641
+ * Based on the x86's implementation of arch_prepare_bpf_trampoline().
1642
+ *
1643
+ * We dpend on DYNAMIC_FTRACE_WITH_REGS to set return address and nop.
1644
+ *
1645
+ * fentry before bpf trampoline hooked:
1646
+ * mov x9, x30
1647
+ * nop
1648
+ *
1649
+ * fentry after bpf trampoline hooked:
1650
+ * mov x9, x30
1651
+ * bl <bpf_trampoline>
1652
+ *
1653
+ */
1654
+ static int prepare_trampoline (struct jit_ctx * ctx , struct bpf_tramp_image * im ,
1655
+ struct bpf_tramp_progs * tprogs , void * orig_call ,
1656
+ int nargs , u32 flags )
1657
+ {
1658
+ int i ;
1659
+ int stack_size ;
1660
+ int retaddr_off ;
1661
+ int regs_off ;
1662
+ int retval_off ;
1663
+ int args_off ;
1664
+ int nargs_off ;
1665
+ struct bpf_tramp_progs * fentry = & tprogs [BPF_TRAMP_FENTRY ];
1666
+ struct bpf_tramp_progs * fexit = & tprogs [BPF_TRAMP_FEXIT ];
1667
+ struct bpf_tramp_progs * fmod_ret = & tprogs [BPF_TRAMP_MODIFY_RETURN ];
1668
+ bool save_ret ;
1669
+ u32 * * branches = NULL ;
1670
+
1671
+ /*
1672
+ * trampoline stack layout:
1673
+ * [ parent ip ]
1674
+ * [ FP ]
1675
+ * SP + retaddr_off [ self ip ]
1676
+ * FP [ FP ]
1677
+ *
1678
+ * sp + regs_off [ x19 ] callee-saved regs, currently
1679
+ * only x19 is used
1680
+ *
1681
+ * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
1682
+ * BPF_TRAMP_F_RET_FENTRY_RET flags
1683
+ *
1684
+ * [ argN ]
1685
+ * [ ... ]
1686
+ * sp + args_off [ arg1 ]
1687
+ *
1688
+ * SP + nargs_off [ args count ]
1689
+ *
1690
+ * SP + 0 [ traced function ] BPF_TRAMP_F_IP_ARG flag
1691
+ */
1692
+
1693
+ stack_size = 0 ;
1694
+ /* room for IP address argument */
1695
+ if (flags & BPF_TRAMP_F_IP_ARG )
1696
+ stack_size += 8 ;
1697
+
1698
+ nargs_off = stack_size ;
1699
+ /* room for args count */
1700
+ stack_size += 8 ;
1701
+
1702
+ args_off = stack_size ;
1703
+ /* room for args */
1704
+ stack_size += nargs * 8 ;
1705
+
1706
+ /* room for return value */
1707
+ retval_off = stack_size ;
1708
+ save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET );
1709
+ if (save_ret )
1710
+ stack_size += 8 ;
1711
+
1712
+ /* room for callee-saved registers, currently only x19 is used */
1713
+ regs_off = stack_size ;
1714
+ stack_size += 8 ;
1715
+
1716
+ retaddr_off = stack_size + 8 ;
1717
+
1718
+ if (IS_ENABLED (CONFIG_ARM64_BTI_KERNEL ))
1719
+ emit (A64_BTI_C , ctx );
1720
+
1721
+ /* frame for parent function */
1722
+ emit (A64_PUSH (A64_FP , A64_R (9 ), A64_SP ), ctx );
1723
+ emit (A64_MOV (1 , A64_FP , A64_SP ), ctx );
1724
+
1725
+ /* frame for patched function */
1726
+ emit (A64_PUSH (A64_FP , A64_LR , A64_SP ), ctx );
1727
+ emit (A64_MOV (1 , A64_FP , A64_SP ), ctx );
1728
+
1729
+ /* allocate stack space */
1730
+ emit (A64_SUB_I (1 , A64_SP , A64_SP , stack_size ), ctx );
1731
+
1732
+ if (flags & BPF_TRAMP_F_IP_ARG ) {
1733
+ /* save ip address of the traced function */
1734
+ emit_addr_mov_i64 (A64_R (10 ), (const u64 )orig_call , ctx );
1735
+ emit (A64_STR64I (A64_R (10 ), A64_SP , 0 ), ctx );
1736
+ }
1737
+
1738
+ /* save args count*/
1739
+ emit (A64_MOVZ (1 , A64_R (10 ), nargs , 0 ), ctx );
1740
+ emit (A64_STR64I (A64_R (10 ), A64_SP , nargs_off ), ctx );
1741
+
1742
+ /* save args */
1743
+ save_args (ctx , args_off , nargs );
1744
+
1745
+ /* save callee saved registers */
1746
+ emit (A64_STR64I (A64_R (19 ), A64_SP , regs_off ), ctx );
1747
+
1748
+ if (flags & BPF_TRAMP_F_CALL_ORIG ) {
1749
+ emit_addr_mov_i64 (A64_R (0 ), (const u64 )im , ctx );
1750
+ emit_addr_mov_i64 (A64_R (10 ), (const u64 )__bpf_tramp_enter , ctx );
1751
+ emit (A64_BLR (A64_R (10 )), ctx );
1752
+ }
1753
+
1754
+ for (i = 0 ; i < fentry -> nr_progs ; i ++ )
1755
+ invoke_bpf_prog (ctx , fentry -> progs [i ], args_off , retval_off ,
1756
+ flags & BPF_TRAMP_F_RET_FENTRY_RET );
1757
+
1758
+ if (fmod_ret -> nr_progs ) {
1759
+ branches = kcalloc (fmod_ret -> nr_progs , sizeof (u32 * ),
1760
+ GFP_KERNEL );
1761
+ if (!branches )
1762
+ return - ENOMEM ;
1763
+
1764
+ invoke_bpf_mod_ret (ctx , fmod_ret , args_off , retval_off ,
1765
+ branches );
1766
+ }
1767
+
1768
+ if (flags & BPF_TRAMP_F_CALL_ORIG ) {
1769
+ restore_args (ctx , args_off , nargs );
1770
+ emit (A64_LDR64I (A64_R (10 ), A64_SP , retaddr_off ), ctx );
1771
+ emit (A64_BLR (A64_R (10 )), ctx );
1772
+ emit (A64_STR64I (A64_R (0 ), A64_SP , retval_off ), ctx );
1773
+ im -> ip_after_call = ctx -> image + ctx -> idx ;
1774
+ emit (A64_NOP , ctx );
1775
+ }
1776
+
1777
+ /* update the branches saved in invoke_bpf_mod_ret with cbnz */
1778
+ for (i = 0 ; i < fmod_ret -> nr_progs && ctx -> image != NULL ; i ++ ) {
1779
+ int offset = & ctx -> image [ctx -> idx ] - branches [i ];
1780
+ * branches [i ] = A64_CBNZ (1 , A64_R (10 ), offset );
1781
+ }
1782
+
1783
+ for (i = 0 ; i < fexit -> nr_progs ; i ++ )
1784
+ invoke_bpf_prog (ctx , fexit -> progs [i ], args_off , retval_off ,
1785
+ false);
1786
+
1787
+ if (flags & BPF_TRAMP_F_RESTORE_REGS )
1788
+ restore_args (ctx , args_off , nargs );
1789
+
1790
+ if (flags & BPF_TRAMP_F_CALL_ORIG ) {
1791
+ im -> ip_epilogue = ctx -> image + ctx -> idx ;
1792
+ emit_addr_mov_i64 (A64_R (0 ), (const u64 )im , ctx );
1793
+ emit_addr_mov_i64 (A64_R (10 ), (const u64 )__bpf_tramp_exit , ctx );
1794
+ emit (A64_BLR (A64_R (10 )), ctx );
1795
+ }
1796
+
1797
+ /* restore x19 */
1798
+ emit (A64_LDR64I (A64_R (19 ), A64_SP , regs_off ), ctx );
1799
+
1800
+ if (save_ret )
1801
+ emit (A64_LDR64I (A64_R (0 ), A64_SP , retval_off ), ctx );
1802
+
1803
+ /* reset SP */
1804
+ emit (A64_MOV (1 , A64_SP , A64_FP ), ctx );
1805
+
1806
+ /* pop frames */
1807
+ emit (A64_POP (A64_FP , A64_LR , A64_SP ), ctx );
1808
+ emit (A64_POP (A64_FP , A64_R (9 ), A64_SP ), ctx );
1809
+
1810
+ if (flags & BPF_TRAMP_F_SKIP_FRAME ) {
1811
+ /* skip patched function, return to parent */
1812
+ emit (A64_MOV (1 , A64_LR , A64_R (9 )), ctx );
1813
+ emit (A64_RET (A64_R (9 )), ctx );
1814
+ } else {
1815
+ /* return to patched function */
1816
+ emit (A64_MOV (1 , A64_R (10 ), A64_LR ), ctx );
1817
+ emit (A64_MOV (1 , A64_LR , A64_R (9 )), ctx );
1818
+ emit (A64_RET (A64_R (10 )), ctx );
1819
+ }
1820
+
1821
+ if (ctx -> image )
1822
+ bpf_flush_icache (ctx -> image , ctx -> image + ctx -> idx );
1823
+
1824
+ kfree (branches );
1825
+
1826
+ return ctx -> idx ;
1827
+ }
1828
+
1829
+ int arch_prepare_bpf_trampoline (struct bpf_tramp_image * im , void * image ,
1830
+ void * image_end , const struct btf_func_model * m ,
1831
+ u32 flags , struct bpf_tramp_progs * tprogs ,
1832
+ void * orig_call )
1833
+ {
1834
+ int ret ;
1835
+ int nargs = m -> nr_args ;
1836
+ int max_insns = ((long )image_end - (long )image ) / AARCH64_INSN_SIZE ;
1837
+ struct jit_ctx ctx = {
1838
+ .image = NULL ,
1839
+ .idx = 0
1840
+ };
1841
+
1842
+ /* we depends on ftrace to set return address and place nop */
1843
+ if (!IS_ENABLED (CONFIG_DYNAMIC_FTRACE_WITH_REGS ))
1844
+ return - ENOTSUPP ;
1845
+
1846
+ /* the first 8 arguments are passed by registers */
1847
+ if (nargs > 8 )
1848
+ return - ENOTSUPP ;
1849
+
1850
+ ret = prepare_trampoline (& ctx , im , tprogs , orig_call , nargs , flags );
1851
+ if (ret < 0 )
1852
+ return ret ;
1853
+
1854
+ if (ret > max_insns )
1855
+ return - EFBIG ;
1856
+
1857
+ ctx .image = image ;
1858
+ ctx .idx = 0 ;
1859
+
1860
+ jit_fill_hole (image , (unsigned int )(image_end - image ));
1861
+ ret = prepare_trampoline (& ctx , im , tprogs , orig_call , nargs , flags );
1862
+
1863
+ if (ret > 0 && validate_code (& ctx ) < 0 )
1864
+ ret = - EINVAL ;
1865
+
1866
+ return ret ;
1867
+ }
1868
+
1535
1869
static int gen_branch_or_nop (enum aarch64_insn_branch_type type , void * ip ,
1536
1870
void * addr , u32 * insn )
1537
1871
{
0 commit comments