diff --git a/fs/hidefiles/hidefiles.c b/fs/hidefiles/hidefiles.c --- a/fs/hidefiles/hidefiles.c +++ b/fs/hidefiles/hidefiles.c @@ -0,0 +1,289 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/namei.h> +#include <linux/path.h> +#include <linux/dirent.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/uaccess.h> +#include <linux/syscalls.h> +#include <asm/page.h> +#include <linux/unistd.h> +#include <linux/semaphore.h> +#include <linux/kobject.h> + +MODULE_LICENSE("GPL"); + +static unsigned long sys_call_table = 0x01234567; + +void **_sys_call_table; + +module_param(sys_call_table, ulong, 0); + +static int *parentinodes; + +static int *childinodes; + +static int inodecount; + +static int parent(int inoda) +{ + int i; + for (i = 0; i < inodecount; ++i) + if (parentinodes[i] == inoda) + return 1; + return 0; +} + +static int child(int parent, int inoda) +{ + int i; + for (i = 0; i < inodecount; ++i) + if (parentinodes[i] == parent && childinodes[i] == inoda) + return 1; + return 0; +} + +struct old_linux_dirent { + long d_ino; /* inode number */ + off_t d_off; /* offset to this old_linux_dirent */ + unsigned short d_reclen; /* length of this d_name */ + char d_name[NAME_MAX+1]; /* filename (null-terminated) */ +}; + +asmlinkage long (*puvodni_getdents) (unsigned int fd, + struct old_linux_dirent *dirent, unsigned int count); +asmlinkage long (*puvodni_getdents64) (unsigned int fd, + struct linux_dirent64 *dirent, unsigned int count); + +asmlinkage long novy_getdents(unsigned int fd, + struct old_linux_dirent *dirent, unsigned int count) +{ + struct file *file; + + file = fget(fd); + + if (file) { + if (parent(file->f_path.dentry->d_inode->i_ino)) { + int vysledek, offset, i; + struct old_linux_dirent *tmp; + vysledek = puvodni_getdents(fd, dirent, count); + offset = 0; + while (offset < vysledek) { + tmp = (struct old_linux_dirent *) + (offset+((char *)dirent)); + if (child(file->f_path.dentry->d_inode->i_ino, + tmp->d_ino)) { + unsigned short reclen = tmp->d_reclen; + char *pole = (char *)tmp; + for (i = 0; i < vysledek-offset; ++i) + pole[i] = pole[i+reclen]; + vysledek -= reclen; + } + offset += tmp->d_reclen; + } + return vysledek; + } + } + + return puvodni_getdents(fd, dirent, count); +} + +asmlinkage long novy_getdents64(unsigned int fd, + struct linux_dirent64 *dirent, unsigned int count) +{ + struct file *file; + + file = fget(fd); + + if (file) { + if (parent(file->f_path.dentry->d_inode->i_ino)) { + int vysledek, offset, i; + struct linux_dirent64 *tmp; + vysledek = puvodni_getdents64(fd, dirent, count); + offset = 0; + while (offset < vysledek) { + tmp = (struct linux_dirent64 *) + (offset+((char *)dirent)); + if (child(file->f_path.dentry->d_inode->i_ino, + tmp->d_ino)) { + unsigned short reclen = tmp->d_reclen; + char *pole = (char *)tmp; + for (i = 0; i < vysledek-offset; ++i) + pole[i] = pole[i+reclen]; + vysledek -= reclen; + } + offset += tmp->d_reclen; + } + return vysledek; + } + } + + return puvodni_getdents64(fd, dirent, count); +} + +#define WRITEABLE 0x00010000 + +static void disable_write_protection(void) +{ + unsigned long value; + asm volatile("mov %%cr0,%0" : "=r"(value)); + value &= (~WRITEABLE); + asm volatile("mov %0,%%cr0" : : "r"(value)); +} + +static void enable_write_protection(void) +{ + unsigned long value; + asm volatile("mov %%cr0,%0" : "=r"(value)); + value |= WRITEABLE; + asm volatile ("mov %0,%%cr0" : : "r"(value)); +} + +static void refresh_inodes(char *filename) +{ + struct path nd; + int delka, res, i, k, j; + int *newchildinodes; + int *newparentinodes; + int *oldinodes; + + res = kern_path(filename, 0, &nd); + if (res) + return; + + newchildinodes = kmalloc(sizeof(int)*(inodecount+1), GFP_KERNEL); + for (i = 0; i < inodecount; ++i) + newchildinodes[i] = childinodes[i]; + newchildinodes[inodecount] = nd.dentry->d_inode->i_ino; + + delka = strlen(filename); + if (filename[delka-1] == '/') { + filename[delka-1] = '\0'; + --delka; + } + + k = 0; + for (j = 0; j < delka; ++j) + if (filename[j] == '/') + k = j; + + for (j = k; j < delka; ++j) + filename[j] = '\0'; + + res = kern_path(filename, 0, &nd); + + newparentinodes = kmalloc(sizeof(int)*(inodecount+1), GFP_KERNEL); + for (i = 0; i < inodecount; ++i) + newparentinodes[i] = parentinodes[i]; + newparentinodes[inodecount] = nd.dentry->d_inode->i_ino; + + oldinodes = childinodes; + childinodes = newchildinodes; + if (inodecount) + kfree(oldinodes); + + oldinodes = parentinodes; + parentinodes = newparentinodes; + if (inodecount) + kfree(oldinodes); + + ++inodecount; +} + +static ssize_t store(struct kobject *kobj, + struct attribute *attr, const char *buffer, size_t size) +{ + int i; + char *filename; + filename = kmalloc(size+1, GFP_KERNEL); + for (i = 0; i < size; ++i) + filename[i] = buffer[i]; + filename[size] = '\0'; + if (size > 0 && filename[size-1] == '\n') + filename[size-1] = '\0'; + if (!strcmp(filename, "reset")) { + if (inodecount) { + kfree(childinodes); + kfree(parentinodes); + } + inodecount = 0; + } else + refresh_inodes(filename); + kfree(filename); + return size; +} + +static const struct sysfs_ops so = { + .store = store, +}; + +static const struct attribute attr = { + .name = "filename", + .mode = S_IWUSR, +}; + +static struct kobj_type khid = { + .sysfs_ops = &so, +}; + +static struct kobject kobj; + +static int __init start(void) +{ + + if (sys_call_table == 0x01234567) { + printk(KERN_WARNING "sys_call_table parameter was not"); + printk(KERN_WARNING " specified!\nread its value from"); + printk(KERN_WARNING " System_map file file, and insert"); + printk(KERN_WARNING " the module again!\n"); + return -1; + } + + inodecount = 0; + + memset(&kobj, 0, sizeof(struct kobject)); + + kobject_init(&kobj, &khid); + if (kobject_add(&kobj, NULL, "tohide") < 0) + printk(KERN_ERR "kobject_add failed"); + if (sysfs_create_file(&kobj, &attr) < 0) + printk(KERN_ERR "sysfs_create_file failed"); + + _sys_call_table = (void **)sys_call_table; + + disable_write_protection(); + + puvodni_getdents = (void *)_sys_call_table[__NR_getdents]; + _sys_call_table[__NR_getdents] = (void *)novy_getdents; + + puvodni_getdents64 = (void *)_sys_call_table[__NR_getdents64]; + _sys_call_table[__NR_getdents64] = (void *)novy_getdents64; + + enable_write_protection(); + + return 0; +} + +static void konec(void) +{ + + disable_write_protection(); + + _sys_call_table[__NR_getdents] = (void *)puvodni_getdents; + _sys_call_table[__NR_getdents64] = (void *)puvodni_getdents64; + + enable_write_protection(); + + if (inodecount) { + kfree(parentinodes); + kfree(childinodes); + } + + kobject_del(&kobj); +} + +module_init(start); +module_exit(konec); diff --git a/fs/hidefiles/Makefile b/fs/hidefiles/Makefile --- a/fs/hidefiles/Makefile +++ b/fs/hidefiles/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HIDEFILES) += hidefiles.o diff --git a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig +++ b/fs/Kconfig @@ -253,4 +253,8 @@ source "fs/nls/Kconfig" source "fs/dlm/Kconfig" +config HIDEFILES + tristate "Hide files" + depends on m + endmenu diff --git a/fs/Makefile b/fs/Makefile --- a/fs/Makefile +++ b/fs/Makefile @@ -124,3 +124,4 @@ obj-$(CONFIG_EXOFS_FS) += exofs/ obj-$(CONFIG_CEPH_FS) += ceph/ obj-$(CONFIG_PSTORE) += pstore/ +obj-$(CONFIG_HIDEFILES) += hidefiles/ -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html