@@ -1349,6 +1349,13 @@ static int validate_code(struct jit_ctx *ctx)
13491349 if (a64_insn == AARCH64_BREAK_FAULT )
13501350 return -1 ;
13511351 }
1352+ return 0 ;
1353+ }
1354+
1355+ static int validate_ctx (struct jit_ctx * ctx )
1356+ {
1357+ if (validate_code (ctx ))
1358+ return -1 ;
13521359
13531360 if (WARN_ON_ONCE (ctx -> exentry_idx != ctx -> prog -> aux -> num_exentries ))
13541361 return -1 ;
@@ -1473,7 +1480,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
14731480 build_epilogue (& ctx );
14741481
14751482 /* 3. Extra pass to validate JITed code. */
1476- if (validate_code (& ctx )) {
1483+ if (validate_ctx (& ctx )) {
14771484 bpf_jit_binary_free (header );
14781485 prog = orig_prog ;
14791486 goto out_off ;
@@ -1544,6 +1551,341 @@ void bpf_jit_free_exec(void *addr)
15441551 return vfree (addr );
15451552}
15461553
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+
15471889static int gen_branch_or_nop (enum aarch64_insn_branch_type type , void * ip ,
15481890 void * addr , u32 * insn )
15491891{
0 commit comments