tkernel: ttools: add ttools module to support ptrace protect
Upstream: no Add ttools module to support ptrace protect and get file refcounts by fd. Signed-off-by: Xiaoming Gao <newtongao@tencent.com> Signed-off-by: katrinzhou <katrinzhou@tencent.com> Signed-off-by: Kairui Song <kasong@tencent.com>
This commit is contained in:
parent
0585394287
commit
c9c30816bb
|
@ -25,7 +25,8 @@
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
static struct vfsmount *anon_inode_mnt __read_mostly;
|
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().
|
* anon_inodefs_dname() is called from d_path().
|
||||||
|
|
|
@ -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_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT)
|
||||||
#define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << 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<<PT_SINGLESTEP_BIT)
|
||||||
|
#define PT_BLOCKSTEP_BIT 30
|
||||||
|
#define PT_BLOCKSTEP (1<<PT_BLOCKSTEP_BIT)
|
||||||
|
|
||||||
|
extern int (*ptrace_pre_hook)(long request, long pid, struct task_struct *task, long addr, long data);
|
||||||
extern long arch_ptrace(struct task_struct *child, long request,
|
extern long arch_ptrace(struct task_struct *child, long request,
|
||||||
unsigned long addr, unsigned long data);
|
unsigned long addr, unsigned long data);
|
||||||
extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
|
extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
|
||||||
|
|
|
@ -1275,6 +1275,9 @@ int ptrace_request(struct task_struct *child, long request,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int (*ptrace_pre_hook)(long request, long pid, struct task_struct *task, long addr, long data);
|
||||||
|
EXPORT_SYMBOL(ptrace_pre_hook);
|
||||||
|
|
||||||
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
|
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
|
||||||
unsigned long, data)
|
unsigned long, data)
|
||||||
{
|
{
|
||||||
|
@ -1292,6 +1295,12 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ptrace_pre_hook) {
|
||||||
|
ret = ptrace_pre_hook(request, pid, child, addr, data);
|
||||||
|
if (ret)
|
||||||
|
goto out_put_task_struct;
|
||||||
|
}
|
||||||
|
|
||||||
if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
|
if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
|
||||||
ret = ptrace_attach(child, request, addr, data);
|
ret = ptrace_attach(child, request, addr, data);
|
||||||
goto out_put_task_struct;
|
goto out_put_task_struct;
|
||||||
|
|
|
@ -9,4 +9,8 @@ config TKERNEL_NONPRIV_NETBIND
|
||||||
bool "Allow non-privileged user to bind specific low ports"
|
bool "Allow non-privileged user to bind specific low ports"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config TKERNEL_TTOOLS
|
||||||
|
tristate "Tencent Kernel TTools"
|
||||||
|
default n
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
obj-$(CONFIG_TKERNEL) += base.o
|
obj-$(CONFIG_TKERNEL) += base.o
|
||||||
obj-$(CONFIG_TKERNEL_NONPRIV_NETBIND) += netbind.o
|
obj-$(CONFIG_TKERNEL_NONPRIV_NETBIND) += netbind.o
|
||||||
|
obj-$(CONFIG_TKERNEL_TTOOLS) += ttools/
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
obj-m := ttools.o
|
||||||
|
ttools-y := ttools_module.o
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef __TTOOLS_H__
|
||||||
|
#define __TTOOLS_H__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -0,0 +1,220 @@
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/fs_struct.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <generated/utsrelease.h>
|
||||||
|
#include <linux/kallsyms.h>
|
||||||
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/sync_core.h>
|
||||||
|
#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");
|
Loading…
Reference in New Issue