@@ -1333,10 +1333,16 @@ static int validate_code(struct jit_ctx *ctx)
13331333
13341334 for (i = 0 ; i < ctx -> idx ; i ++ ) {
13351335 u32 a64_insn = le32_to_cpu (ctx -> image [i ]);
1336-
13371336 if (a64_insn == AARCH64_BREAK_FAULT )
13381337 return -1 ;
13391338 }
1339+ return 0 ;
1340+ }
1341+
1342+ static int validate_ctx (struct jit_ctx * ctx )
1343+ {
1344+ if (validate_code (ctx ))
1345+ return -1 ;
13401346
13411347 if (WARN_ON_ONCE (ctx -> exentry_idx != ctx -> prog -> aux -> num_exentries ))
13421348 return -1 ;
@@ -1461,7 +1467,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
14611467 build_epilogue (& ctx );
14621468
14631469 /* 3. Extra pass to validate JITed code. */
1464- if (validate_code (& ctx )) {
1470+ if (validate_ctx (& ctx )) {
14651471 bpf_jit_binary_free (header );
14661472 prog = orig_prog ;
14671473 goto out_off ;
@@ -1532,6 +1538,334 @@ void bpf_jit_free_exec(void *addr)
15321538 return vfree (addr );
15331539}
15341540
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+
15351869static int gen_branch_or_nop (enum aarch64_insn_branch_type type , void * ip ,
15361870 void * addr , u32 * insn )
15371871{
0 commit comments