diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 24192a7667ed..4530efde5f84 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -25,7 +25,8 @@ #include static struct vfsmount *anon_inode_mnt __read_mostly; -static struct inode *anon_inode_inode; +struct inode *anon_inode_inode; +EXPORT_SYMBOL_GPL(anon_inode_inode); /* * anon_inodefs_dname() is called from d_path(). diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index eaaef3ffec22..9e69a2c13c1e 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -46,6 +46,13 @@ extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr, #define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT) #define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT) +/* single stepping state bits (used on ARM and PA-RISC) */ +#define PT_SINGLESTEP_BIT 31 +#define PT_SINGLESTEP (1< +#include + +#define TTOOLS_IO 0xEE + +struct ttools_fd_ref { + int fd; + long ref_cnt; +}; + +#define TTOOLS_PTRACE_PROTECT _IO(TTOOLS_IO, 0x00) +#define TTOOLS_PTRACE_UNPROTECT _IO(TTOOLS_IO, 0x01) +#define TTOOLS_GET_FD_REFS_CNT _IOWR(TTOOLS_IO, 0x02, struct ttools_fd_ref) + +#endif diff --git a/kernel/tkernel/ttools/ttools_module.c b/kernel/tkernel/ttools/ttools_module.c new file mode 100644 index 000000000000..2a5830a4b890 --- /dev/null +++ b/kernel/tkernel/ttools/ttools_module.c @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ttools.h" + +#define TTOOLS_MINOR 254 +#define TTOOLS_VER "2.0" + + +struct ttools_pid { + struct list_head list; + struct task_struct *task; +}; + +static LIST_HEAD(ttools_protected_pids); +static DEFINE_SPINLOCK(ttools_pids_lock); + +extern struct inode *anon_inode_inode; + +static bool is_annon_inode(struct inode *inode) +{ + return inode == anon_inode_inode; +} + +static int ttools_ptrace_protect_task(struct task_struct *p_task) +{ + struct ttools_pid *p_item; + bool exist = false; + struct ttools_pid *pid_item = kmalloc(sizeof(struct ttools_pid), GFP_KERNEL); + if (!pid_item) + return -ENOMEM; + + spin_lock(&ttools_pids_lock); + list_for_each_entry(p_item, &ttools_protected_pids, list) { + if (p_item->task == p_task) { + exist = true; + break; + } + } + if (!exist) { + pid_item->task = p_task; + list_add_tail(&pid_item->list, &ttools_protected_pids); + } + spin_unlock(&ttools_pids_lock); + if (exist) { + kfree(pid_item); + return -EEXIST; + } + return 0; +} + +static int ttools_ptrace_unprotect_task(struct task_struct *p_task) +{ + struct ttools_pid *p_item; + + spin_lock(&ttools_pids_lock); + list_for_each_entry(p_item, &ttools_protected_pids, list) { + if (p_item->task == p_task) { + list_del(&p_item->list); + kfree(p_item); + break; + } + } + spin_unlock(&ttools_pids_lock); + return 0; +} + +static bool ttools_task_ptrace_protected(struct task_struct *p_task) +{ + struct ttools_pid *p_item; + bool ret = false; + + spin_lock(&ttools_pids_lock); + list_for_each_entry(p_item, &ttools_protected_pids, list) { + if (p_item->task == p_task) { + ret = true; + break; + } + } + spin_unlock(&ttools_pids_lock); + return ret; +} + +static int ttools_ptrace_hook(long request, long pid, struct task_struct *task, long addr, long data) +{ + if (ttools_task_ptrace_protected(task->group_leader)) + return -EPERM; + return 0; +} + +static void ttools_clean_task_list(void) +{ + struct ttools_pid *p_item; + struct ttools_pid *p_item2; + + spin_lock(&ttools_pids_lock); + list_for_each_entry_safe(p_item, p_item2, &ttools_protected_pids, list) { + list_del(&p_item->list); + kfree(p_item); + } + spin_unlock(&ttools_pids_lock); +} + +static int ttools_get_fd_refs_cnt(struct ttools_fd_ref *p_ref) +{ + struct dentry *dentry; + long dentry_cnt, f_cnt; + bool is_annon; + struct fd f; + f = fdget(p_ref->fd); + if (!f.file) + return -EBADF; + is_annon = is_annon_inode(f.file->f_inode); + f_cnt = atomic_long_read(&(f.file->f_count)) - (f.flags & FDPUT_FPUT); + dentry = f.file->f_path.dentry; + if (!dentry) + dentry_cnt = 0; + else + dentry_cnt = dentry->d_lockref.count; + fdput(f); + if (is_annon || !dentry_cnt) + p_ref->ref_cnt = f_cnt; + else + p_ref->ref_cnt = dentry_cnt; + return 0; +} + +static long ttools_dev_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + int ret = -EINVAL; + void __user *argp = (void __user *)arg; + struct ttools_fd_ref fd_ref; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (ioctl) { + case TTOOLS_PTRACE_PROTECT: + ret = ttools_ptrace_protect_task(current->group_leader); + break; + case TTOOLS_PTRACE_UNPROTECT: + ret = ttools_ptrace_unprotect_task(current->group_leader); + break; + case TTOOLS_GET_FD_REFS_CNT: + if (copy_from_user(&fd_ref, argp, sizeof(struct ttools_fd_ref))) + return -EFAULT; + ret = ttools_get_fd_refs_cnt(&fd_ref); + if (ret) + return ret; + if (copy_to_user(argp, &fd_ref, sizeof(struct ttools_fd_ref))) + return -EFAULT; + break; + } + return ret; +} + +static struct file_operations ttools_chardev_ops = { + .unlocked_ioctl = ttools_dev_ioctl, + .compat_ioctl = ttools_dev_ioctl, + .llseek = noop_llseek, +}; + +static struct miscdevice ttools_dev = { + TTOOLS_MINOR, + "ttools", + &ttools_chardev_ops, + .mode = 0666, +}; + + +static void flush_icache_1(void *info) +{ + smp_mb(); +#ifdef CONFIG_X86 + sync_core(); +#endif +} + +static int ttools_init(void) +{ + int ret; + + ttools_chardev_ops.owner = THIS_MODULE; + ret = misc_register(&ttools_dev); + ptrace_pre_hook = ttools_ptrace_hook; + smp_wmb(); + smp_call_function(flush_icache_1, NULL, 1); + pr_info("ttools " TTOOLS_VER " loaded\n"); + return ret; +} + +static void ttools_exit(void) +{ + ptrace_pre_hook = NULL; + smp_wmb(); + smp_call_function(flush_icache_1, NULL, 1); + misc_deregister(&ttools_dev); + ttools_clean_task_list(); + pr_info("ttools " TTOOLS_VER " unloaded\n"); +} + +module_init(ttools_init); +module_exit(ttools_exit); +MODULE_DESCRIPTION("ttools " TTOOLS_VER " for " UTS_RELEASE); +MODULE_LICENSE("GPL");