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