diff -Nur a/src/Makefile b/src/Makefile --- a/src/Makefile 2022-07-26 16:03:59.605586984 +0800 +++ b/src/Makefile 2022-08-03 17:32:16.825278169 +0800 @@ -12,7 +12,7 @@ debug: make CONFIG_TOA=m -C /lib/modules/${kerver}/build M=`pwd` modules EXTRA_CFLAGS="-DTOA_DBG_MSG" clean: - rm -f .*.cmd *.o *.ko *.mod.c modules.order Module.symvers + rm -f .*.cmd *.o *.ko *.mod.c modules.order Module.symvers *.mod rm -rf .tmp_versions install: test -d "$(DESTDIR)/lib/modules/${kerver}/extra/net/toa" \ diff -Nur a/src/toa.c b/src/toa.c --- a/src/toa.c 2022-07-26 16:03:59.605586984 +0800 +++ b/src/toa.c 2022-08-03 17:29:42.024204449 +0800 @@ -45,21 +45,11 @@ } #if defined(CONFIG_ARM64) -/* - * ARM64 interface - * Lookup the page table entry for a virtual address. Return a pointer - * to the entry and the level of the mapping. - * - * Note: We return pud and pmd either when the entry is marked large - * or when the present bit is not set. Otherwise we would return a - * pointer to a nonexisting mapping. - */ -static pte_t *lookup_address(unsigned long address, unsigned int *level) +static pmd_t *toa_get_pmd(unsigned long address) { pgd_t *pgdp; pud_t *pudp, pud; - pmd_t *pmdp, pmd; - pte_t *ptep; + pmd_t *pmdp; unsigned long addr = address; unsigned long init_mm = kallsyms_lookup_name_fun("init_mm"); @@ -79,12 +69,62 @@ return NULL; pmdp = pmd_offset(pudp, addr); + + return pmdp; +} + +static int toa_mkwrite(unsigned long vma) +{ + pmd_t *pmdp, pmd; + pte_t *ptep, pte; + + pmdp = toa_get_pmd(vma); + if (NULL == pmdp) + return 1; + pmd = READ_ONCE(*pmdp); if (pmd_none(pmd)) - return NULL; + return 1; + + if (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT)) { + set_pmd(pmdp, __pmd(pmd_val(pmd) & ~PMD_SECT_RDONLY)); + } else { + ptep = pte_offset_kernel(pmdp, vma); + pte = READ_ONCE(*ptep); + if (pte_none(pte)) { + return 1; + } + set_pte(ptep, pte_mkwrite(pte)); + } + + return 0; +} + +static void toa_wrprotect(unsigned long vma) +{ + pmd_t *pmdp, pmd; + pte_t *ptep, pte; + + pmdp = toa_get_pmd(vma); + if (NULL == pmdp) + return; + + pmd = READ_ONCE(*pmdp); + if (pmd_none(pmd)) + return; + + if (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT)) { + set_pmd(pmdp, __pmd(pmd_val(pmd) | PMD_SECT_RDONLY)); + } else { + ptep = pte_offset_kernel(pmdp, vma); + pte = READ_ONCE(*ptep); + if (pte_none(pte)) { + return; + } + set_pte(ptep, pte_wrprotect(pte)); + } - ptep = pte_offset_kernel(pmdp, addr); - return ptep; + return; } #endif @@ -360,8 +400,12 @@ static inline int hook_toa_functions(void) { +#if defined(CONFIG_ARM64) + int err = 0; +#else unsigned int level; pte_t *pte; +#endif /* hook inet_getname for ipv4 */ struct proto_ops *inet_stream_ops_p = @@ -379,15 +423,22 @@ (struct inet_connection_sock_af_ops *)&ipv6_specific; #endif +#if defined(CONFIG_ARM64) + err |= toa_mkwrite((unsigned long)&inet_stream_ops_p->getname); + err |= toa_mkwrite((unsigned long)&ipv4_specific_p->syn_recv_sock); +#ifdef CONFIG_IP_VS_TOA_IPV6 + err |= toa_mkwrite((unsigned long)&inet6_stream_ops_p->getname); + err |= toa_mkwrite((unsigned long)&ipv6_specific_p->syn_recv_sock); +#endif + if (0 == err) { + flush_tlb_all(); + } else { + return 1; + } +#else pte = lookup_address((unsigned long )inet_stream_ops_p, &level); if (pte == NULL) return 1; - -#if defined(CONFIG_ARM64) - *pte = pte_mkwrite(*pte); - __sync_icache_dcache(*pte); - flush_tlb_all(); -#else if (pte->pte & ~_PAGE_RW) { pte->pte |= _PAGE_RW; } @@ -396,8 +447,8 @@ smp_processor_id(), inet_getname, inet_getname_toa);*/ inet_stream_ops_p->getname = inet_getname_toa; - TOA_INFO("CPU [%u] hooked inet_getname <%p> --> <%p>\n", - smp_processor_id(), inet_getname, inet_stream_ops_p->getname); + TOA_INFO("CPU [%u] hooked inet_getname <%p> --> <%p>, <%p>\n", + smp_processor_id(), inet_getname, inet_stream_ops_p->getname, inet_getname_toa); #ifdef CONFIG_IP_VS_TOA_IPV6 inet6_stream_ops_p->getname = inet6_getname_toa; @@ -406,9 +457,10 @@ #endif ipv4_specific_p->syn_recv_sock = tcp_v4_syn_recv_sock_toa; - TOA_INFO("CPU [%u] hooked tcp_v4_syn_recv_sock <%p> --> <%p>\n", + TOA_INFO("CPU [%u] hooked tcp_v4_syn_recv_sock <%p> --> <%p>, <%p>\n", smp_processor_id(), tcp_v4_syn_recv_sock, - ipv4_specific_p->syn_recv_sock); + ipv4_specific_p->syn_recv_sock, + tcp_v4_syn_recv_sock_toa); #ifdef CONFIG_IP_VS_TOA_IPV6 ipv6_specific_p->syn_recv_sock = tcp_v6_syn_recv_sock_toa; @@ -417,15 +469,18 @@ ipv6_specific_p->syn_recv_sock); #endif - pte = lookup_address((unsigned long )inet_stream_ops_p, &level); - if (pte == NULL) - return 1; - #if defined(CONFIG_ARM64) - *pte = pte_wrprotect(*pte); - __sync_icache_dcache(*pte); + toa_wrprotect((unsigned long)&inet_stream_ops_p->getname); + toa_wrprotect((unsigned long)&ipv4_specific_p->syn_recv_sock); +#ifdef CONFIG_IP_VS_TOA_IPV6 + toa_wrprotect((unsigned long)&inet6_stream_ops_p->getname); + toa_wrprotect((unsigned long)&ipv6_specific_p->syn_recv_sock); +#endif flush_tlb_all(); #else + pte = lookup_address((unsigned long )inet_stream_ops_p, &level); + if (pte == NULL) + return 1; pte->pte |= pte->pte &~_PAGE_RW; #endif @@ -436,8 +491,12 @@ static int unhook_toa_functions(void) { +#if defined(CONFIG_ARM64) + int err = 0; +#else unsigned int level; pte_t *pte; +#endif /* unhook inet_getname for ipv4 */ struct proto_ops *inet_stream_ops_p = @@ -455,15 +514,22 @@ (struct inet_connection_sock_af_ops *)&ipv6_specific; #endif +#if defined(CONFIG_ARM64) + err |= toa_mkwrite((unsigned long)&inet_stream_ops_p->getname); + err |= toa_mkwrite((unsigned long)&ipv4_specific_p->syn_recv_sock); +#ifdef CONFIG_IP_VS_TOA_IPV6 + err |= toa_mkwrite((unsigned long)&inet6_stream_ops_p->getname); + err |= toa_mkwrite((unsigned long)&ipv6_specific_p->syn_recv_sock); +#endif + if (0 == err) { + flush_tlb_all(); + } else { + return 1; + } +#else pte = lookup_address((unsigned long )inet_stream_ops_p, &level); if (pte == NULL) return 1; - -#if defined(CONFIG_ARM64) - *pte = pte_mkwrite(*pte); - __sync_icache_dcache(*pte); - flush_tlb_all(); -#else if (pte->pte & ~_PAGE_RW) { pte->pte |= _PAGE_RW; } @@ -491,15 +557,18 @@ smp_processor_id()); #endif - pte = lookup_address((unsigned long )inet_stream_ops_p, &level); - if (pte == NULL) - return 1; - #if defined(CONFIG_ARM64) - *pte = pte_wrprotect(*pte); - __sync_icache_dcache(*pte); + toa_wrprotect((unsigned long)&inet_stream_ops_p->getname); + toa_wrprotect((unsigned long)&ipv4_specific_p->syn_recv_sock); +#ifdef CONFIG_IP_VS_TOA_IPV6 + toa_wrprotect((unsigned long)&inet6_stream_ops_p->getname); + toa_wrprotect((unsigned long)&ipv6_specific_p->syn_recv_sock); +#endif flush_tlb_all(); #else + pte = lookup_address((unsigned long )inet_stream_ops_p, &level); + if (pte == NULL) + return 1; pte->pte |= pte->pte &~_PAGE_RW; #endif