[PATCH] security: add security hook point

Adapted to tkernel5  and fixed some bugs.

Signed-off-by: Zhiping Du <zhipingdu@tencent.com>
Signed-off-by: zhiguang peng <zgpeng@tencent.com>
Signed-off-by: Haiquan zhang  <huntazhang@tencent.com>
Signed-off-by: jit xie  <jitxie@tencent.com>
This commit is contained in:
huntazhang 2024-06-24 20:02:36 +08:00
parent 141ba6644b
commit 62b6061f57
27 changed files with 1913 additions and 1 deletions

View File

@ -1974,3 +1974,6 @@ CONFIG_ATOMIC64_SELFTEST=y
CONFIG_ASYNC_RAID6_TEST=m CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_KSTRTOX=y CONFIG_TEST_KSTRTOX=y
CONFIG_TEST_BPF=m CONFIG_TEST_BPF=m
CONFIG_TKERNEL=y
CONFIG_TKERNEL_SECURITY_MONITOR=y
CONFIG_TKERNEL_AEGIS_MODULE=m

View File

@ -75,6 +75,7 @@
#include "internal.h" #include "internal.h"
#include <trace/events/sched.h> #include <trace/events/sched.h>
#include <linux/hook_frame.h>
static int bprm_creds_from_file(struct linux_binprm *bprm); static int bprm_creds_from_file(struct linux_binprm *bprm);
@ -1964,6 +1965,10 @@ static int do_execveat_common(int fd, struct filename *filename,
goto out_free; goto out_free;
bprm->argc = 1; bprm->argc = 1;
} }
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
if (filename)
execve_hook_check(bprm->argc, (void *)&argv, bprm->envc, (void *)&envp, filename->name);
#endif
retval = bprm_execve(bprm, fd, filename, flags); retval = bprm_execve(bprm, fd, filename, flags);
out_free: out_free:

View File

@ -283,6 +283,31 @@ static bool rw_hint_valid(u64 hint)
} }
} }
static long fcntl_rw_hook(struct file *file, unsigned int cmd,
unsigned long arg)
{
u64 *argp = (u64 __user *)arg;
u64 flags;
switch (cmd) {
case F_GET_FILE_HOOK_FLAG:
flags = file->hook_flags;
if (copy_to_user(argp, &flags, sizeof(*argp)))
return -EFAULT;
return 0;
case F_SET_FILE_HOOK_FLAG:
if (copy_from_user(&flags, argp, sizeof(flags)))
return -EFAULT;
spin_lock(&file->f_lock);
file->hook_flags = flags;
spin_unlock(&file->f_lock);
return 0;
default:
return -EINVAL;
}
}
static long fcntl_rw_hint(struct file *file, unsigned int cmd, static long fcntl_rw_hint(struct file *file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
@ -417,6 +442,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
case F_SET_RW_HINT: case F_SET_RW_HINT:
err = fcntl_rw_hint(filp, cmd, arg); err = fcntl_rw_hint(filp, cmd, arg);
break; break;
case F_SET_FILE_HOOK_FLAG:
case F_GET_FILE_HOOK_FLAG:
err = fcntl_rw_hook(filp, cmd, arg);
break;
default: default:
break; break;
} }

View File

@ -1040,6 +1040,7 @@ struct file {
struct address_space *f_mapping; struct address_space *f_mapping;
errseq_t f_wb_err; errseq_t f_wb_err;
errseq_t f_sb_err; /* for syncfs */ errseq_t f_sb_err; /* for syncfs */
unsigned long hook_flags;
} __randomize_layout } __randomize_layout
__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */

View File

@ -0,0 +1,56 @@
#ifndef __HOOK_FRAME_H__
#define __HOOK_FRAME_H__
#include<linux/net.h>
#include<linux/socket.h>
#include<linux/fs.h>
#define SYSCTL_SET_MAGIC (0x5a5a5a5aUL << 32)
/* attention!!!
* this emum value must be equal hook_info_array index
*/
enum {
EXECVE_INFO,
SOCK_INFO,
CONNECT_INFO,
ACCEPT_INFO,
SENDTO_INFO,
RECVFROM_INFO,
FORK_INFO,
EXIT_INFO,
INFO_MAX
};
extern unsigned long hook_func_array[INFO_MAX];
extern int hook_info_flag;
extern unsigned long execve_info_flag;
extern unsigned long connect_info_flag;
extern unsigned long accept_info_flag;
extern unsigned long sendto_info_flag;
extern unsigned long recvfrom_info_flag;
extern unsigned long sock_info_flag;
extern unsigned long fork_info_flag;
extern unsigned long exit_info_flag;
extern void (*get_execve_info_func)(int argc, void *argv, int envc, void *envp, const char *filename);
extern void (*get_connect_info_func)(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err);
extern void (*get_accept_info_func)(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err);
extern void (*get_sendto_info_func)(struct socket *sock, int fd, struct sockaddr_storage *address, int err);
extern void (*get_recvfrom_info_func)(struct socket *sock, int fd, struct sockaddr_storage *address, int err);
extern void (*get_sock_info_func)(struct sock *sk);
extern void (*get_fork_info_func)(struct task_struct *p, unsigned long clone_flags);
extern void (*get_exit_info_func)(struct task_struct *tsk, long code);
extern long hookinfo_nr(void);
extern void sock_hook_check(void *sk);
extern void recvfrom_hook_check(struct socket *sock, int fd, struct sockaddr_storage *address, int err);
extern void sendto_hook_check(struct socket *sock, int fd, struct sockaddr_storage *address, int err);
extern void connect_hook_check(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err);
extern void accept_hook_check(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err);
extern void execve_hook_check(int argc, void *argv, int envc, void *envp, const char *filename);
extern void fork_hook_check(struct task_struct *p, unsigned long clone_flags);
extern void exit_hook_check(struct task_struct *tsk, long code);
#endif

View File

@ -31,6 +31,7 @@
#include <linux/syscall_user_dispatch.h> #include <linux/syscall_user_dispatch.h>
#include <linux/mm_types_task.h> #include <linux/mm_types_task.h>
#include <linux/task_io_accounting.h> #include <linux/task_io_accounting.h>
#include <linux/kref.h>
#include <linux/posix-timers.h> #include <linux/posix-timers.h>
#include <linux/rseq.h> #include <linux/rseq.h>
#include <linux/seqlock.h> #include <linux/seqlock.h>
@ -768,6 +769,14 @@ struct kmap_ctrl {
#endif #endif
}; };
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
struct security_moni_info {
struct kref refcount;
long size;
char buffer[];
};
#endif
struct task_struct { struct task_struct {
#ifdef CONFIG_THREAD_INFO_IN_TASK #ifdef CONFIG_THREAD_INFO_IN_TASK
/* /*
@ -811,6 +820,10 @@ struct task_struct {
*/ */
int recent_used_cpu; int recent_used_cpu;
int wake_cpu; int wake_cpu;
#endif
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
struct security_moni_info *par_moni_info;
struct security_moni_info *my_moni_info;
#endif #endif
int on_rq; int on_rq;

View File

@ -546,6 +546,7 @@ struct sock {
struct rcu_head sk_rcu; struct rcu_head sk_rcu;
netns_tracker ns_tracker; netns_tracker ns_tracker;
struct hlist_node sk_bind2_node; struct hlist_node sk_bind2_node;
pid_t pid;
KABI_RESERVE(1); KABI_RESERVE(1);
KABI_RESERVE(2); KABI_RESERVE(2);

View File

@ -56,6 +56,9 @@
#define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13) #define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13)
#define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14) #define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14)
#define F_SET_FILE_HOOK_FLAG (F_LINUX_SPECIFIC_BASE + 1024)
#define F_GET_FILE_HOOK_FLAG (F_LINUX_SPECIFIC_BASE + 1025)
/* /*
* Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be
* used to clear any hints previously set. * used to clear any hints previously set.

View File

@ -76,6 +76,9 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <linux/hook_frame.h>
extern void data_release(struct kref *ref);
/* /*
* The default value should be high enough to not crash a system that randomly * The default value should be high enough to not crash a system that randomly
@ -868,6 +871,14 @@ void __noreturn do_exit(long code)
acct_process(); acct_process();
trace_sched_process_exit(tsk); trace_sched_process_exit(tsk);
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
if (tsk->par_moni_info)
kref_put(&tsk->par_moni_info->refcount, data_release);
if (tsk->my_moni_info)
kref_put(&tsk->my_moni_info->refcount, data_release);
exit_hook_check(tsk, code);
#endif
exit_sem(tsk); exit_sem(tsk);
exit_shm(tsk); exit_shm(tsk);
exit_files(tsk); exit_files(tsk);

View File

@ -112,6 +112,8 @@
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/task.h> #include <trace/events/task.h>
#include <linux/hook_frame.h>
/* /*
* Minimum number of threads to boot the kernel * Minimum number of threads to boot the kernel
*/ */
@ -2931,6 +2933,21 @@ pid_t kernel_clone(struct kernel_clone_args *args)
if (IS_ERR(p)) if (IS_ERR(p))
return PTR_ERR(p); return PTR_ERR(p);
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
p->par_moni_info = 0;
p->my_moni_info = 0;
if (hook_info_flag) {
p->par_moni_info = current->my_moni_info;
p->my_moni_info = current->my_moni_info;
if (p->par_moni_info)
kref_get(&p->par_moni_info->refcount);
if (p->my_moni_info)
kref_get(&p->my_moni_info->refcount);
}
fork_hook_check(p, clone_flags);
#endif
/* /*
* Do this prior waking up the new thread - the thread pointer * Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly. * might get invalid after that point, if the thread exits quickly.

View File

@ -159,6 +159,17 @@ extern int sysctl_vm_ramdisk_swaptune;
extern int sysctl_vm_swapcache_fastfree; extern int sysctl_vm_swapcache_fastfree;
#endif #endif
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
unsigned long connect_info_flag;
unsigned long accept_info_flag;
unsigned long sendto_info_flag;
unsigned long recvfrom_info_flag;
unsigned long execve_info_flag;
unsigned long sock_info_flag;
unsigned long fork_info_flag;
unsigned long exit_info_flag;
#endif
#endif /* CONFIG_SYSCTL */ #endif /* CONFIG_SYSCTL */
/* /*
@ -1716,6 +1727,27 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
#endif /* CONFIG_PROC_SYSCTL */ #endif /* CONFIG_PROC_SYSCTL */
#if defined(CONFIG_SYSCTL) #if defined(CONFIG_SYSCTL)
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
#include <linux/hook_frame.h>
unsigned long security_switch_min = 0x0 | SYSCTL_SET_MAGIC;
unsigned long security_switch_max = 0xffffffff | SYSCTL_SET_MAGIC;
int security_switch_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
int ret;
ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
if (ret)
return ret;
if (write)
*(unsigned long *)(table->data) = (*(unsigned long *)(table->data)) & 0xffffffff;
return ret;
}
#endif
int proc_do_static_key(struct ctl_table *table, int write, int proc_do_static_key(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos) void *buffer, size_t *lenp, loff_t *ppos)
{ {
@ -1751,6 +1783,80 @@ DECLARE_STATIC_KEY_TRUE(rps_using_pvipi);
#endif #endif
static struct ctl_table kern_table[] = { static struct ctl_table kern_table[] = {
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
{
.procname = "connect_info_switch",
.data = &connect_info_flag,
.maxlen = sizeof(connect_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
{
.procname = "accept_info_switch",
.data = &accept_info_flag,
.maxlen = sizeof(accept_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
{
.procname = "sendto_info_switch",
.data = &sendto_info_flag,
.maxlen = sizeof(sendto_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
{
.procname = "recvfrom_info_switch",
.data = &recvfrom_info_flag,
.maxlen = sizeof(recvfrom_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
{
.procname = "execve_info_switch",
.data = &execve_info_flag,
.maxlen = sizeof(execve_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
{
.procname = "sock_info_switch",
.data = &sock_info_flag,
.maxlen = sizeof(sock_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
{
.procname = "fork_info_switch",
.data = &fork_info_flag,
.maxlen = sizeof(fork_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
{
.procname = "exit_info_switch",
.data = &exit_info_flag,
.maxlen = sizeof(exit_info_flag),
.mode = 0644,
.proc_handler = &security_switch_handler,
.extra1 = &security_switch_min,
.extra2 = &security_switch_max,
},
#endif
{ {
.procname = "panic", .procname = "panic",
.data = &panic_timeout, .data = &panic_timeout,

View File

@ -4,7 +4,7 @@
# #
menuconfig TKERNEL menuconfig TKERNEL
bool "Tencent Kernel Features" bool "Tencent Kernel Features"
default n default y
if TKERNEL if TKERNEL
@ -27,4 +27,16 @@ config TKERNEL_SHIELD_MOUNTS
bool 'Shield mount' bool 'Shield mount'
default n default n
config TKERNEL_SECURITY_MONITOR
bool "security monitor"
default y
help
Allow user to add security monitor
config TKERNEL_AEGIS_MODULE
tristate "ONION aegis module"
default m
help
ONION aegis module
endif endif

View File

@ -3,3 +3,5 @@ obj-$(CONFIG_TKERNEL_NONPRIV_NETBIND) += netbind.o
obj-$(CONFIG_TKERNEL_TTOOLS) += ttools/ obj-$(CONFIG_TKERNEL_TTOOLS) += ttools/
obj-$(CONFIG_TKERNEL_NETATOP) += netatop/ obj-$(CONFIG_TKERNEL_NETATOP) += netatop/
obj-$(CONFIG_TKERNEL_SHIELD_MOUNTS) += shield_mounts.o obj-$(CONFIG_TKERNEL_SHIELD_MOUNTS) += shield_mounts.o
obj-$(CONFIG_TKERNEL_SECURITY_MONITOR) += onionhook/
obj-$(CONFIG_TKERNEL_AEGIS_MODULE) += aegis/

View File

@ -0,0 +1,3 @@
obj-$(CONFIG_TKERNEL_AEGIS_MODULE) += aegis.o
aegis-objs := module.o list.o hook_info.o

View File

@ -0,0 +1,732 @@
#include <linux/file.h>
#include <net/sock.h>
#include <uapi/linux/binfmts.h>
#include <linux/un.h>
#include <linux/kref.h>
#include <net/sock.h>
#include <linux/cpu.h>
#include <net/inet_sock.h>
#include <linux/pid_namespace.h>
#include <linux/cred.h>
#include <linux/uidgid.h>
#include <linux/fs_struct.h>
#include <linux/hook_frame.h>
#include "hook_info.h"
#include "list.h"
#include "module.h"
char ssh_info_head[SSH_INFO_LEN] = "SSH_GLOBAL_ONION_INFOMATION";
char ssh_tty_head[SSH_TTY_LEN] = "SSH_TTY";
enum PWD_FLAG_TYPE {
PWD_INIT,
PWD_CORR,
PWD_TOOLARGE,
PWD_GETERR
};
struct hook_info hook_info_array[] = {
{ "execve_info", EXECVE_INFO, (unsigned long)get_execve_info, execinfo_to_user, extra_execinfo_free},
{ "sock_info", SOCK_INFO, (unsigned long)get_sock_info, sockinfo_to_user, NULL},
{}
};
unsigned int para_len_current = PARA_LEN_DEFAULT;
unsigned int para_sum_current = PARA_SUM_DEFAULT;
unsigned long min_para_len = 2 | SYSCTL_SET_MAGIC;
unsigned long max_para_len = 4096 | SYSCTL_SET_MAGIC;
unsigned long sysctl_para_len = PARA_LEN_DEFAULT;
unsigned long sysctl_para_sum = PARA_SUM_DEFAULT;
unsigned long sysctl_info_num = INFO_NUM_DEFAULT;
unsigned long sysctl_poll_wakeup_length = WAKEUP_LENGTH_DEFAULT;
unsigned long sysctl_set_min = 0x0 | SYSCTL_SET_MAGIC;
unsigned long sysctl_set_max = 0xffffffff | SYSCTL_SET_MAGIC;
static struct ctl_table_header *sysctl_header;
static struct ctl_table_header *sysctl_tbl;
#if IS_MODULE(CONFIG_TKERNEL_AEGIS_MODULE)
u64 nsec_to_clock_t(u64 x)
{
#if (NSEC_PER_SEC % USER_HZ) == 0
return div_u64(x, NSEC_PER_SEC / USER_HZ);
#elif (USER_HZ % 512) == 0
return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512);
#else
return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
#endif
}
#endif
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
{
const char __user *native;
#ifdef CONFIG_COMPAT
if (unlikely(argv.is_compat)) {
compat_uptr_t compat;
if (get_user(compat, argv.ptr.compat + nr))
return ERR_PTR(-EFAULT);
return compat_ptr(compat);
}
#endif
if (get_user(native, argv.ptr.native + nr))
return ERR_PTR(-EFAULT);
return native;
}
void hookinfo_total_numb(int type)
{
this_cpu_inc(*hook_info_array[type].total_numb);
}
void hookinfo_drop_stats(int type)
{
this_cpu_inc(*hook_info_array[type].drop_stats);
}
void clear_task_environ(struct exec_info *exec_info)
{
if (exec_info->env_info) {
kfree(exec_info->env_info);
exec_info->env_info = NULL;
exec_info->size -= exec_info->inf_size;
exec_info->inf_size = 0;
}
if (exec_info->env_tty) {
kfree(exec_info->env_tty);
exec_info->env_tty = NULL;
exec_info->size -= exec_info->tty_size;
exec_info->tty_size = 0;
}
}
int get_task_environ(struct exec_info *exec_info,
int envc, struct user_arg_ptr *envp)
{
int i = 0, ret = 0;
long len, max_len = SSH_INFO_LEN;
const char __user *str;
char src_envhead[SSH_INFO_LEN] = "";
while (i < envc) {
cond_resched();
str = get_user_arg_ptr(*envp, i);
if (IS_ERR(str)) {
ret = -EFAULT;
goto err;
}
len = strnlen_user(str, MAX_ARG_STRLEN);
if (!len) {
ret = -EFAULT;
goto err;
}
if (copy_from_user(src_envhead, str, min(max_len, len))) {
ret = -EFAULT;
goto err;
}
src_envhead[SSH_INFO_LEN - 1] = '\0';
if (!exec_info->env_info &&
strcmp(ssh_info_head, src_envhead) == 0) {
exec_info->env_info = kzalloc(len, GFP_KERNEL);
if (!exec_info->env_info) {
ret = -ENOMEM;
goto err;
}
if (copy_from_user(exec_info->env_info, str, len)) {
ret = -EFAULT;
goto err;
}
exec_info->inf_size = len;
exec_info->size += len;
goto check;
}
src_envhead[SSH_TTY_LEN - 1] = '\0';
if (!exec_info->env_tty &&
strcmp(ssh_tty_head, src_envhead) == 0) {
exec_info->env_tty = kzalloc(len, GFP_KERNEL);
if (!exec_info->env_tty) {
ret = -ENOMEM;
goto err;
}
if (copy_from_user(exec_info->env_tty, str, len)) {
ret = -EFAULT;
goto err;
}
exec_info->tty_size = len;
exec_info->size += len;
}
check:
if (exec_info->env_info && exec_info->env_tty)
goto out;
i++;
}
return 0;
err:
if (exec_info->env_info) {
kfree(exec_info->env_info);
exec_info->env_info = NULL;
exec_info->size -= exec_info->inf_size;
exec_info->inf_size = 0;
}
if (exec_info->env_tty) {
kfree(exec_info->env_tty);
exec_info->env_tty = NULL;
exec_info->size -= exec_info->tty_size;
exec_info->tty_size = 0;
}
out:
return ret;
}
int get_task_para(int argc, struct user_arg_ptr *argv)
{
int i = 0, ret = 0;
long len, sum = 0, point = 0;
const char __user *str;
unsigned int para_len = para_len_current;
unsigned int para_sum = para_sum_current;
para_sum = para_sum > para_len ? para_sum : para_len;
while (i < argc) {
str = get_user_arg_ptr(*argv, i);
if (IS_ERR(str)) {
ret = -EFAULT;
goto out;
}
len = strnlen_user(str, MAX_ARG_STRLEN);
if (!len) {
ret = -EFAULT;
goto out;
}
if (len > para_len)
len = para_len;
sum += len;
if (sum > para_sum) {
sum = para_sum;
break;
}
i++;
}
if (current->my_moni_info)
kref_put(&current->my_moni_info->refcount, data_release);
current->my_moni_info = kzalloc(sizeof(struct security_moni_info)
+ sum, GFP_KERNEL);
if (!current->my_moni_info) {
ret = -ENOMEM;
goto out;
}
kref_init(&current->my_moni_info->refcount);
current->my_moni_info->size = sum;
para_sum = sum;
i = 0;
sum = 0;
while (i < argc) {
str = get_user_arg_ptr(*argv, i);
if (IS_ERR(str)) {
ret = -EFAULT;
goto error;
}
len = strnlen_user(str, MAX_ARG_STRLEN);
if (!len) {
ret = -EFAULT;
goto error;
}
if (len > para_len)
len = para_len;
if (sum + len > para_sum)
len = para_sum - sum;
if (copy_from_user(current->my_moni_info->buffer + point,
str, len)) {
ret = -EFAULT;
goto error;
}
point += len;
current->my_moni_info->buffer[point - 1] = '\0';
sum += len;
if (sum >= para_sum)
goto out;
i++;
}
return 0;
error:
kref_put(&current->my_moni_info->refcount, data_release);
current->my_moni_info = NULL;
out:
return ret;
}
void get_pidns_inum(struct exec_info *exec_info)
{
struct pid_namespace *ns = NULL;
rcu_read_lock();
ns = task_active_pid_ns(current);
if (ns) {
get_pid_ns(ns);
exec_info->inum = ns->ns.inum;
put_pid_ns(ns);
}
rcu_read_unlock();
}
void get_task_ids(struct exec_info *exec_info)
{
exec_info->init_pid = task_pid_nr_ns(current, &init_pid_ns);
exec_info->acti_pid = task_pid_nr_ns(current, NULL);
exec_info->init_ppid = task_ppid_nr_ns(current, &init_pid_ns);
exec_info->acti_ppid = task_ppid_nr_ns(current, NULL);
exec_info->acti_uid = from_kuid_munged(current_user_ns(), current_uid());
exec_info->acti_gid = from_kgid_munged(current_user_ns(), current_gid());
exec_info->acti_euid = from_kuid_munged(current_user_ns(), current_euid());
exec_info->acti_egid = from_kgid_munged(current_user_ns(), current_egid());
}
void get_task_pwd(struct exec_info *exec_info)
{
struct path pwdpath;
char path[PWD_LEN] = "\0";
char *ppath = path;
if (current->fs) {
get_fs_pwd(current->fs, &pwdpath);
ppath = d_path(&pwdpath, path, PWD_LEN);
if (!IS_ERR(ppath)) {
exec_info->pwd_flag = PWD_CORR;
memcpy(exec_info->pwd, ppath, path + PWD_LEN - ppath);
} else {
exec_info->pwd_flag = PWD_GETERR;
if (PTR_ERR(ppath) == -ENAMETOOLONG) {
exec_info->pwd_flag = PWD_TOOLARGE;
memcpy(exec_info->pwd, path, PWD_LEN);
}
}
path_put(&pwdpath);
}
}
void get_task_start_time(struct exec_info *exec_info)
{
exec_info->start_time = nsec_to_clock_t(current->start_boottime);
}
void info_ptr_hold_ref(struct exec_info *exec_info)
{
exec_info->parent = current->par_moni_info;
if (exec_info->parent) {
kref_get(&exec_info->parent->refcount);
exec_info->size += exec_info->parent->size;
exec_info->pa_size = exec_info->parent->size;
}
exec_info->my = current->my_moni_info;
if (exec_info->my) {
kref_get(&exec_info->my->refcount);
exec_info->size += exec_info->my->size;
exec_info->my_size = exec_info->my->size;
}
}
void get_execve_info(int argc, struct user_arg_ptr *argv, int envc, struct user_arg_ptr *envp, const char *filename)
{
struct exec_info *exec_info;
hookinfo_total_numb(EXECVE_INFO);
if (atomic64_read(this_cpu_ptr(hook_info_array[EXECVE_INFO].info_num)) > (sysctl_info_num & SYSCTL_VALID_MASK))
goto drop;
exec_info = kzalloc(sizeof(struct exec_info), GFP_KERNEL);
if (!exec_info)
goto drop;
exec_info->size += sizeof(struct exec_info) - 4 * sizeof(void *) - sizeof(struct list_head);
exec_info->type = EXECVE_INFO;
exec_info->magic = INFO_MAGIC;
if (get_task_environ(exec_info, envc, envp))
goto err;
if (get_task_para(argc, argv))
goto para_err;
get_pidns_inum(exec_info);
get_task_ids(exec_info);
get_task_pwd(exec_info);
get_task_start_time(exec_info);
info_ptr_hold_ref(exec_info);
hookinfo_list_in(&exec_info->head, (int)EXECVE_INFO);
return;
para_err:
clear_task_environ(exec_info);
err:
kfree(exec_info);
drop:
hookinfo_drop_stats(EXECVE_INFO);
}
void extra_execinfo_free(struct list_head *info_head)
{
struct exec_info *exec_info = (struct exec_info *)info_head;
if (exec_info->parent) {
kref_put(&exec_info->parent->refcount, data_release);
exec_info->parent = 0;
}
if (exec_info->my) {
kref_put(&exec_info->my->refcount, data_release);
exec_info->my = 0;
}
if (exec_info->env_info) {
kfree(exec_info->env_info);
exec_info->env_info = 0;
}
if (exec_info->env_tty) {
kfree(exec_info->env_tty);
exec_info->env_tty = 0;
}
}
int execinfo_to_user(struct list_head *info_head, char __user **buf, size_t count, int cpu)
{
int readsize = 0, ret, headlen;
struct exec_info *exec_info = (struct exec_info *)info_head;
int size = exec_info->size;
if (size > count) {
ret = -EFBIG;
goto out;
}
headlen = sizeof(struct exec_info) - 4 * sizeof(void *) - sizeof(struct list_head);
if (copy_to_user(*buf, (void *)&exec_info->magic, headlen)) {
return -EFAULT;
goto out;
}
*buf += headlen;
readsize += headlen;
if (exec_info->parent) {
if (copy_to_user(*buf, exec_info->parent->buffer, exec_info->parent->size)) {
ret = -EFAULT;
goto par_err;
}
*buf += exec_info->parent->size;
readsize += exec_info->parent->size;
}
if (exec_info->my) {
if (copy_to_user(*buf, exec_info->my->buffer, exec_info->my->size)) {
ret = -EFAULT;
goto my_err;
}
*buf += exec_info->my->size;
readsize += exec_info->my->size;
}
if (exec_info->env_info) {
if (copy_to_user(*buf, exec_info->env_info, exec_info->inf_size)) {
ret = -EFAULT;
goto info_err;
}
*buf += exec_info->inf_size;
readsize += exec_info->inf_size;
}
if (exec_info->env_tty) {
if (copy_to_user(*buf, exec_info->env_tty, exec_info->tty_size)) {
ret = -EFAULT;
goto tty_err;
}
*buf += exec_info->tty_size;
readsize += exec_info->tty_size;
}
extra_execinfo_free(info_head);
return readsize;
tty_err:
*buf -= exec_info->inf_size;
readsize -= exec_info->inf_size;
info_err:
*buf -= exec_info->my->size;
readsize -= exec_info->my->size;
my_err:
*buf -= exec_info->parent->size;
readsize -= exec_info->parent->size;
par_err:
*buf -= headlen;
readsize -= headlen;
out:
return ret;
}
ssize_t hook_info_read(struct hook_info *info,
struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
int cpu;
bool try;
struct list_head *list, *info_head, *tmp;
int len = 0, ret;
raw_spinlock_t *plock;
get_online_cpus();
for_each_cpu((cpu), hook_cpu_mask) {
try = true;
retry:
list = &info->list;
list_for_each_safe(info_head, tmp, list) {
ret = info->to_user_func(info_head, &buf, count, cpu);
if (ret < 0) {
put_online_cpus();
return len;
}
count -= ret;
len += ret;
list_del(info_head);
kfree(info_head);
atomic64_dec(per_cpu_ptr(hook_info_array[info->type].info_num,
hook_info_array[info->type].last_cpu));
}
plock = per_cpu_ptr(info->lock, cpu);
hook_info_array[info->type].last_cpu = cpu;
raw_spin_lock_bh(plock);
list_replace_init(per_cpu_ptr(info->lists, cpu), &info->list);
raw_spin_unlock_bh(plock);
if (try) {
try = false;
goto retry;
}
}
put_online_cpus();
return len;
}
int sockinfo_to_user(struct list_head *info_head, char __user **buf, size_t count, int cpu)
{
struct sock_info *node = (struct sock_info *)info_head;
unsigned int hookinfo_len = node->size;
if (hookinfo_len > count)
return -EFBIG;
if (copy_to_user(*buf, (void *)&node->magic, hookinfo_len))
return -EFAULT;
*buf += hookinfo_len;
return hookinfo_len;
}
void get_sock_info(struct sock *sk)
{
struct sock_info *node;
const struct inet_sock *inet;
hookinfo_total_numb(SOCK_INFO);
if (atomic64_read(this_cpu_ptr(hook_info_array[SOCK_INFO].info_num)) > (sysctl_info_num & SYSCTL_VALID_MASK))
goto drop;
node = kzalloc(sizeof(struct sock_info), GFP_NOWAIT);
if (!node)
goto drop;
node->magic = INFO_MAGIC;
node->info_type = SOCK_INFO;
node->size = sizeof(struct sock_info) - sizeof(node->head);
inet = inet_sk(sk);
node->dest = inet->inet_daddr;
node->src = inet->inet_rcv_saddr;
node->destp = ntohs(inet->inet_dport);
node->srcp = ntohs(inet->inet_sport);
node->state = sk->sk_state;
node->type = sk->sk_type;
node->family = sk->sk_family;
node->pid = sk->pid;
#if IS_ENABLED(CONFIG_IPV6)
node->daddr6 = sk->sk_v6_daddr;
node->saddr6 = sk->sk_v6_rcv_saddr;
#endif
hookinfo_list_in(&node->head, (int)SOCK_INFO);
return;
drop:
hookinfo_drop_stats(SOCK_INFO);
}
int para_len_sum_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
int ret;
unsigned int old_len, old_sum;
static DEFINE_MUTEX(mutex);
mutex_lock(&mutex);
old_len = sysctl_para_len;
old_sum = sysctl_para_sum;
ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
if (ret)
goto err;
if (write) {
*(unsigned long *)(table->data) = (*(unsigned long *)(table->data)) & 0xffffffff;
if (sysctl_para_len > sysctl_para_sum) {
sysctl_para_len = old_len;
sysctl_para_sum = old_sum;
ret = -EINVAL;
goto err;
}
para_len_current = (unsigned int)sysctl_para_len;
para_sum_current = (unsigned int)sysctl_para_sum;
}
err:
mutex_unlock(&mutex);
return ret;
}
int secur_sysctl_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
int ret;
static DEFINE_MUTEX(info_num_mutex);
mutex_lock(&info_num_mutex);
ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
if (ret)
goto err;
if (write)
*(unsigned long *)(table->data) = (*(unsigned long *)(table->data)) & 0xffffffff;
err:
mutex_unlock(&info_num_mutex);
return ret;
}
static struct ctl_table security_control_table[] = {
{
.procname = "secur_para_len",
.data = &sysctl_para_len,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = para_len_sum_handler,
.extra1 = &min_para_len,
.extra2 = &max_para_len,
},
{
.procname = "secur_para_sum",
.data = &sysctl_para_sum,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = para_len_sum_handler,
.extra1 = &min_para_len,
.extra2 = &max_para_len,
},
{
.procname = "secur_info_num",
.data = &sysctl_info_num,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = secur_sysctl_handler,
.extra1 = &sysctl_set_min,
.extra2 = &sysctl_set_max,
},
{
.procname = "secur_poll_wakeup_length",
.data = &sysctl_poll_wakeup_length,
.maxlen = sizeof(unsigned long),
.mode = 0644,
.proc_handler = secur_sysctl_handler,
.extra1 = &sysctl_set_min,
.extra2 = &sysctl_set_max,
},
{ }
};
static struct ctl_table security_table[] = {
{
//.procname = "security_sysctl",
.procname = NULL,
.maxlen = 0,
.mode = 0555,
},
{ }
};
int mod_sysctl_add(void)
{
sysctl_header = register_sysctl("security_sysctl", security_table);
if (!sysctl_header)
return -ENOMEM;
sysctl_tbl = register_sysctl("security_sysctl", security_control_table);
if (!sysctl_tbl) {
unregister_sysctl_table(sysctl_header);
return -ENOMEM;
}
return 0;
}
void mod_sysctl_del(void)
{
if (sysctl_tbl)
unregister_sysctl_table(sysctl_tbl);
if (sysctl_header)
unregister_sysctl_table(sysctl_header);
}

View File

@ -0,0 +1,135 @@
#ifndef AEGIS_MODULE_HOOK_INFO_H_
#define AEGIS_MODULE_HOOK_INFO_H_
#include <linux/compat.h>
#include <linux/in6.h>
#define SYSCTL_SET_MAGIC (0x5a5a5a5aUL << 32)
#define SYSCTL_VALID_MASK (0xffffffffUL)
#define PARA_LEN_DEFAULT 100
#define PARA_SUM_DEFAULT 1024
#define INFO_NUM_DEFAULT 2048
#define WAKEUP_LENGTH_DEFAULT 1
/* The last byte indicates the version of the captured information. */
#define INFO_MAGIC 0x12345601
#define SSH_INFO_LEN 28
#define SSH_TTY_LEN 8
#define PWD_LEN 64
#define STATISTIC_NUM 2
#define STATISTIC_VERSION 10001
/* Wrappers which go away once all code is converted */
static inline void cpu_hotplug_begin(void) { cpus_write_lock(); }
static inline void cpu_hotplug_done(void) { cpus_write_unlock(); }
static inline void get_online_cpus(void) { cpus_read_lock(); }
static inline void put_online_cpus(void) { cpus_read_unlock(); }
struct exec_info {
struct list_head head;
unsigned long magic;
int type;
int size;
int pa_size;
int my_size;
int inf_size;
int tty_size;
pid_t init_pid;
pid_t acti_pid;
pid_t init_ppid;
pid_t acti_ppid;
uid_t acti_uid;
gid_t acti_gid;
uid_t acti_euid;
gid_t acti_egid;
int pwd_flag;
unsigned int inum;
unsigned long long start_time;
char pwd[64];
struct security_moni_info *parent;
struct security_moni_info *my;
char *env_info;
char *env_tty;
};
struct sock_info {
struct list_head head;
unsigned long magic;
int info_type;
int size;
__be32 dest;
__be32 src;
__u16 destp;
__u16 srcp;
int state;
__u16 type;
__u16 family;
pid_t pid;
struct in6_addr daddr6;
struct in6_addr saddr6;
};
typedef void (*extra_free_func_t)(struct list_head *info_head);
typedef int (*to_user_func_t)(struct list_head *info_head, char __user **buf, size_t count, int cpu);
struct hook_info {
const char *dir;
int type;
unsigned long hook_func_addr;
to_user_func_t to_user_func;
extra_free_func_t extra_free_func;
struct list_head list;
struct list_head __percpu *lists;
raw_spinlock_t __percpu *lock;
atomic64_t __percpu *info_num;
wait_queue_head_t wait_queue;
struct mutex readlock;
unsigned long __percpu *drop_stats;
unsigned long __percpu *total_numb;
int last_cpu;
};
struct info_entry {
int type;
char padding[4];
unsigned long long total;
unsigned long long discard;
};
struct statistics_info {
int version;
char padding[4];
struct info_entry info_entry[STATISTIC_NUM];
};
struct user_arg_ptr {
#ifdef CONFIG_COMPAT
bool is_compat;
#endif
union {
const char __user *const __user *native;
#ifdef CONFIG_COMPAT
const compat_uptr_t __user *compat;
#endif
} ptr;
};
extern struct hook_info hook_info_array[];
extern unsigned long sysctl_poll_wakeup_length;
extern ssize_t hook_info_read(struct hook_info *info, struct file *file,
char __user *buf, size_t count, loff_t *ppos);
extern void get_execve_info(int argc, struct user_arg_ptr *argv, int envc,
struct user_arg_ptr *envp, const char *filename);
extern void get_sock_info(struct sock *sk);
extern int execinfo_to_user(struct list_head *info_head, char __user **buf,
size_t count, int cpu);
extern int sockinfo_to_user(struct list_head *info_head, char __user **buf,
size_t count, int cpu);
extern void extra_execinfo_free(struct list_head *exec_info);
#endif // AEGIS_MODULE_HOOK_INFO_H_

344
kernel/tkernel/aegis/list.c Normal file
View File

@ -0,0 +1,344 @@
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <linux/cpu.h>
#include <linux/hook_frame.h>
#include <linux/slab.h>
#include "list.h"
#include "hook_info.h"
#include "module.h"
#define HOOKINFO_WAKEUP_LENGTH 1
static struct proc_dir_entry *hook_dir_entry;
unsigned long percpu_total_num(long __percpu *num)
{
int cpu;
unsigned long total = 0;
get_online_cpus();
for_each_cpu((cpu), hook_cpu_mask)
total += *per_cpu_ptr(num, cpu);
put_online_cpus();
return total;
}
unsigned long percpu_total_num_atomic64(atomic64_t __percpu *num)
{
int cpu;
unsigned long total = 0;
get_online_cpus();
for_each_cpu((cpu), hook_cpu_mask)
total += atomic64_read(per_cpu_ptr(num, cpu));
put_online_cpus();
return total;
}
int clear_hookinfo_list(struct hook_info *info)
{
struct list_head *info_head, *tmp;
int cpu;
bool try = true;
get_online_cpus();
for_each_possible_cpu(cpu) {
struct list_head *list = per_cpu_ptr(info->lists, cpu);
retry:
list_for_each_safe(info_head, tmp, list) {
if (info->extra_free_func)
info->extra_free_func(info_head);
list_del(info_head);
kfree(info_head);
}
if (try) {
list = &info->list;
try = false;
goto retry;
}
}
put_online_cpus();
return 0;
}
void clear_cpu_list(void)
{
int i = 0;
struct hook_info *info;
for (i = 0; hook_info_array[i].dir; i++) {
info = &hook_info_array[i];
clear_hookinfo_list(info);
}
}
void hookinfo_list_in(struct list_head *new, int type)
{
struct list_head *list = this_cpu_ptr(hook_info_array[type].lists);
raw_spinlock_t *plock = this_cpu_ptr(hook_info_array[type].lock);
raw_spin_lock_bh(plock);
list_add_tail(new, list);
raw_spin_unlock_bh(plock);
atomic64_inc(this_cpu_ptr(hook_info_array[type].info_num));
if (wq_has_sleeper(&hook_info_array[type].wait_queue))
wake_up_interruptible_poll(&hook_info_array[type].wait_queue, POLLIN);
}
static ssize_t fops_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
ssize_t len = 0;
struct hook_info *info = pde_data(file_inode(file));
if (file->hook_flags != HOOK_INFO_READ_FLAG)
return 0;
mutex_lock(&info->readlock);
len = hook_info_read(info, file, buf, count, ppos);
mutex_unlock(&info->readlock);
return len;
}
static int fops_open(struct inode *inode, struct file *file)
{
return try_module_get(THIS_MODULE) ? 0 : -ENOENT;
}
static unsigned int fops_poll(struct file *file, poll_table *wait)
{
struct hook_info *info = pde_data(file_inode(file));
unsigned int mask = 0;
if (file->hook_flags != HOOK_INFO_READ_FLAG)
return POLLERR;
poll_wait(file, &info->wait_queue, wait);
if (percpu_total_num_atomic64(info->info_num) > (sysctl_poll_wakeup_length & SYSCTL_VALID_MASK))
mask = POLLIN;
return mask;
}
static int fops_release(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
return 0;
}
static const struct proc_ops hook_info_fops = {
.proc_open = fops_open,
.proc_release = fops_release,
.proc_read = fops_read,
.proc_poll = fops_poll,
.proc_lseek = noop_llseek,
};
static ssize_t fops_statistics_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
int ret, i;
struct statistics_info statistics_information = {};
unsigned int copied = sizeof(struct statistics_info);
if (count < copied)
return 0;
for (i = 0; hook_info_array[i].dir; i++) {
statistics_information.info_entry[i].type = hook_info_array[i].type;
statistics_information.info_entry[i].discard =
percpu_total_num(hook_info_array[i].drop_stats);
statistics_information.info_entry[i].total =
percpu_total_num(hook_info_array[i].total_numb);
}
statistics_information.version = STATISTIC_VERSION;
ret = copy_to_user(buf, &statistics_information, copied);
return copied - ret;
}
static const struct proc_ops stats_info_fops = {
.proc_open = fops_open,
.proc_release = fops_release,
.proc_read = fops_statistics_read,
.proc_lseek = noop_llseek,
};
int hook_info_proc_create(void)
{
int i, ret;
hook_dir_entry = proc_mkdir("aegis", NULL);
if (!hook_dir_entry) {
ret = -ENOMEM;
goto out;
}
for (i = 0; hook_info_array[i].dir; i++) {
if (!proc_create_data(hook_info_array[i].dir, 0400, hook_dir_entry, &hook_info_fops, (void *)&hook_info_array[i])) {
ret = -ENOMEM;
goto err;
}
mutex_init(&hook_info_array[i].readlock);
}
if (!proc_create("statistics_info", 0400, hook_dir_entry, &stats_info_fops)) {
ret = -ENOMEM;
goto err;
}
return 0;
err:
proc_remove(hook_dir_entry);
out:
return ret;
}
void hook_info_proc_delete(void)
{
proc_remove(hook_dir_entry);
}
int hook_info_percpu_create(void)
{
int i, cpu, ret;
for (i = 0; hook_info_array[i].dir; i++) {
hook_info_array[i].lists = alloc_percpu(struct list_head);
hook_info_array[i].lock = alloc_percpu(raw_spinlock_t);
hook_info_array[i].info_num = alloc_percpu(atomic64_t);
hook_info_array[i].drop_stats = alloc_percpu(unsigned long);
hook_info_array[i].total_numb = alloc_percpu(unsigned long);
if (!hook_info_array[i].lists || !hook_info_array[i].info_num || !hook_info_array[i].total_numb
|| !hook_info_array[i].drop_stats || !hook_info_array[i].lock) {
printk(KERN_ERR "security: failed to allocate percpu data\n");
ret = -ENOMEM;
goto err;
}
get_online_cpus();
for_each_possible_cpu(cpu) {
struct list_head *list = per_cpu_ptr(hook_info_array[i].lists, cpu);
raw_spinlock_t *plock = per_cpu_ptr(hook_info_array[i].lock, cpu);
INIT_LIST_HEAD(list);
raw_spin_lock_init(plock);
atomic64_set(per_cpu_ptr(hook_info_array[i].info_num, cpu), 0);
*per_cpu_ptr(hook_info_array[i].drop_stats, cpu) = 0;
*per_cpu_ptr(hook_info_array[i].total_numb, cpu) = 0;
}
put_online_cpus();
INIT_LIST_HEAD(&hook_info_array[i].list);
}
return 0;
err:
for (; i >= 0; i--) {
free_percpu(hook_info_array[i].lists);
free_percpu(hook_info_array[i].lock);
free_percpu(hook_info_array[i].info_num);
free_percpu(hook_info_array[i].drop_stats);
free_percpu(hook_info_array[i].total_numb);
}
return ret;
}
int hook_info_percpu_delete(void)
{
int i;
clear_cpu_list();
for (i = 0; hook_info_array[i].dir; i++) {
free_percpu(hook_info_array[i].lists);
free_percpu(hook_info_array[i].lock);
free_percpu(hook_info_array[i].info_num);
free_percpu(hook_info_array[i].drop_stats);
free_percpu(hook_info_array[i].total_numb);
}
return 0;
}
int hook_info_func_register(void)
{
int i, type, ret;
for (i = 0; hook_info_array[i].dir; i++) {
type = hook_info_array[i].type;
if (!hook_func_array[type])
hook_func_array[type] = hook_info_array[i].hook_func_addr;
else {
ret = -EBUSY;
goto err;
}
}
return 0;
err:
for (i = i - 1; i >= 0; i++) {
type = hook_info_array[i].type;
hook_func_array[type] = 0;
}
return ret;
}
void hook_info_func_unregister(void)
{
int i, type;
for (i = 0; hook_info_array[i].dir; i++) {
type = hook_info_array[i].type;
hook_func_array[type] = 0;
}
}
void init_wait_queue(void)
{
int i;
for (i = 0; hook_info_array[i].dir; i++)
init_waitqueue_head(&hook_info_array[i].wait_queue);
}
int list_module_init(void)
{
int ret;
ret = hook_info_percpu_create();
if (ret)
goto list_err;
ret = hook_info_proc_create();
if (ret)
goto proc_err;
ret = hook_info_func_register();
if (ret)
goto func_err;
init_wait_queue();
return 0;
func_err:
hook_info_proc_delete();
proc_err:
hook_info_percpu_delete();
list_err:
return ret;
}
void list_module_exit(void)
{
hook_info_func_unregister();
hook_info_proc_delete();
hook_info_percpu_delete();
}

View File

@ -0,0 +1,11 @@
#ifndef AEGIS_MODULE_LIST_H_
#define AEGIS_MODULE_LIST_H_
#define HOOK_INFO_READ_FLAG 0x5a5a5a5a
extern void hookinfo_list_in(struct list_head *new, int type);
extern int list_module_init(void);
extern void list_module_exit(void);
extern void data_release(struct kref *ref);
extern void hook_info_func_unregister(void);
#endif // AEGIS_MODULE_LIST_H_

View File

@ -0,0 +1,162 @@
#include <linux/module.h>
#include <net/sock.h>
#include <linux/cpu.h>
#include <linux/hook_frame.h>
#include "module.h"
#include "list.h"
#include "hook_info.h"
static bool module_putted;
static struct mutex hook_lock;
static struct kset *hook_sysfs_kset;
static enum cpuhp_state cpu_online_enum;
const struct cpumask *hook_cpu_mask = cpu_online_mask;
void hook_disable(void)
{
mutex_lock(&hook_lock);
hook_info_flag = 0;
smp_wmb();
hook_info_func_unregister();
if (!module_putted && !hookinfo_nr()) {
module_put(THIS_MODULE);
module_putted = true;
}
mutex_unlock(&hook_lock);
}
static ssize_t disable_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\t%s\t%ld\n",
hook_info_flag ? "enabled" : "disabled",
module_putted ? "unused" : "inuse", hookinfo_nr());
}
static ssize_t disable_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
unsigned long v;
if (kstrtoul(buf, 0, &v))
return -EINVAL;
if ((v & 0xffffffff00000000) != SYSCTL_SET_MAGIC)
return -EINVAL;
if (v & 0x00000000ffffffff)
hook_disable();
return count;
}
KERNEL_ATTR_RW(disable);
static struct attribute *security_moni_attrs[] = {
&disable_attr.attr,
NULL
};
static struct attribute_group hook_attrs_group = {
.attrs = security_moni_attrs,
};
int hook_sysfs_init(void)
{
int ret;
hook_sysfs_kset = kset_create_and_add("aegis", NULL, kernel_kobj);
if (!hook_sysfs_kset)
return -ENOMEM;
ret = sysfs_create_group(&hook_sysfs_kset->kobj, &hook_attrs_group);
if (ret)
kset_unregister(hook_sysfs_kset);
return ret;
}
void hook_sysfs_exit(void)
{
sysfs_remove_group(&hook_sysfs_kset->kobj, &hook_attrs_group);
kset_unregister(hook_sysfs_kset);
}
static int cpu_online_func(unsigned int cpu)
{
return 0;
}
static int cpu_offline_func(unsigned int cpu)
{
hook_cpu_mask = cpu_possible_mask;
return 0;
}
static __init int security_moni_init(void)
{
int ret;
if (hook_info_flag || hookinfo_nr()) {
ret = -EBUSY;
goto err_out;
}
if (!try_module_get(THIS_MODULE)) {
ret = -EFAULT;
goto err_out;
}
mutex_init(&hook_lock);
ret = list_module_init();
if (ret)
goto list_err;
ret = hook_sysfs_init();
if (ret)
goto sysfs_err;
ret = mod_sysctl_add();
if (ret)
goto sysctl_err;
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "security/module:online",
cpu_online_func, cpu_offline_func);
if (ret < 0)
goto cpuhp_err;
cpu_online_enum = ret;
hook_info_flag = 1;
return 0;
cpuhp_err:
mod_sysctl_del();
sysctl_err:
hook_sysfs_exit();
sysfs_err:
list_module_exit();
list_err:
module_put(THIS_MODULE);
err_out:
return ret;
}
static __exit void security_moni_exit(void)
{
list_module_exit();
hook_sysfs_exit();
mod_sysctl_del();
cpuhp_remove_state(cpu_online_enum);
}
module_init(security_moni_init);
module_exit(security_moni_exit);
MODULE_AUTHOR("zhipingdu/zgpeng/huntazhang");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,17 @@
#ifndef AEGIS_MODULE_MODULE_H_
#include <linux/cpumask.h>
#define AEGIS_MODULE_MODULE_H_
#define KERNEL_ATTR_RW(_name) \
static struct kobj_attribute _name##_attr = \
__ATTR(_name, 0644, _name##_show, _name##_store)
extern int hook_info_flag;
extern long nr_hook_count(int flag);
extern long nr_execve_count(void);
extern int mod_sysctl_add(void);
extern void mod_sysctl_del(void);
extern const struct cpumask *hook_cpu_mask;
#endif // AEGIS_MODULE_MODULE_H_

View File

@ -0,0 +1 @@
obj-y := hook_frame.o

View File

@ -0,0 +1,196 @@
#include<net/sock.h>
#include<linux/hook_frame.h>
#include<linux/fs.h>
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
int hook_info_flag;
EXPORT_SYMBOL(hook_info_flag);
unsigned long hook_func_array[INFO_MAX];
EXPORT_SYMBOL(hook_func_array);
void (*get_execve_info_func)(int argc, void *argv, int envc, void *envp, const char *filename);
EXPORT_SYMBOL(get_execve_info_func);
void (*get_connect_info_func)(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err);
EXPORT_SYMBOL(get_connect_info_func);
void (*get_accept_info_func)(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err);
EXPORT_SYMBOL(get_accept_info_func);
void (*get_sendto_info_func)(struct socket *sock, int fd, struct sockaddr_storage *address, int err);
EXPORT_SYMBOL(get_sendto_info_func);
void (*get_recvfrom_info_func)(struct socket *sock, int fd, struct sockaddr_storage *address, int err);
EXPORT_SYMBOL(get_recvfrom_info_func);
void (*get_sock_info_func)(struct sock *sk);
EXPORT_SYMBOL(get_sock_info_func);
void (*get_fork_info_func)(struct task_struct *p, unsigned long clone_flags);
EXPORT_SYMBOL(get_fork_info_func);
void (*get_exit_info_func)(struct task_struct *tsk, long code);
EXPORT_SYMBOL(get_exit_info_func);
static DEFINE_PER_CPU(long, hook_info_count) __aligned(64);
long hookinfo_nr(void)
{
int cpu;
long total = 0;
for_each_possible_cpu(cpu) {
total += per_cpu(hook_info_count, cpu);
}
return total;
}
EXPORT_SYMBOL(hookinfo_nr);
void data_release(struct kref *ref)
{
struct security_moni_info *data = container_of(ref, struct security_moni_info, refcount);
kfree(data);
}
EXPORT_SYMBOL(data_release);
void execve_hook_check(int argc, void *argv, int envc, void *envp, const char *filename)
{
if (execve_info_flag && hook_info_flag) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_execve_info_func = (typeof(get_execve_info_func))hook_func_array[EXECVE_INFO];
if (get_execve_info_func) {
get_execve_info_func(argc, argv, envc, envp, filename);
}
__this_cpu_dec(hook_info_count);
}
}
void accept_hook_check(struct socket *newsock, struct file *newfile, struct sockaddr_storage *address, int err)
{
if (accept_info_flag && hook_info_flag) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_accept_info_func = (typeof(get_accept_info_func))hook_func_array[ACCEPT_INFO];
if (get_accept_info_func) {
get_accept_info_func(newsock, newfile, NULL, err);
}
__this_cpu_dec(hook_info_count);
}
}
void connect_hook_check(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err)
{
if (connect_info_flag && hook_info_flag) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_connect_info_func = (typeof(get_connect_info_func))hook_func_array[CONNECT_INFO];
if (get_connect_info_func) {
get_connect_info_func(sock, newfile, address, err);
}
__this_cpu_dec(hook_info_count);
}
}
void sendto_hook_check(struct socket *sock, int fd, struct sockaddr_storage *address, int err)
{
if (sendto_info_flag && hook_info_flag && err >= 0) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_sendto_info_func = (typeof(get_sendto_info_func))hook_func_array[SENDTO_INFO];
if (get_sendto_info_func) {
get_sendto_info_func(sock, fd, address, err);
}
__this_cpu_dec(hook_info_count);
}
}
void recvfrom_hook_check(struct socket *sock, int fd, struct sockaddr_storage *address, int err)
{
if (recvfrom_info_flag && hook_info_flag && err >= 0) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_recvfrom_info_func = (typeof(get_recvfrom_info_func))hook_func_array[RECVFROM_INFO];
if (get_recvfrom_info_func) {
get_recvfrom_info_func(sock, fd, address, err);
}
__this_cpu_dec(hook_info_count);
}
}
void sock_hook_check(void *sock)
{
struct sock *sk = sock;
if (sock_info_flag && hook_info_flag) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_sock_info_func = (typeof(get_sock_info_func))hook_func_array[SOCK_INFO];
if (get_sock_info_func) {
get_sock_info_func(sk);
}
__this_cpu_dec(hook_info_count);
}
}
EXPORT_SYMBOL(sock_hook_check);
void fork_hook_check(struct task_struct *p, unsigned long clone_flags)
{
if (fork_info_flag && hook_info_flag) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_fork_info_func = (typeof(get_fork_info_func))hook_func_array[FORK_INFO];
if (get_fork_info_func) {
get_fork_info_func(p, clone_flags);
}
__this_cpu_dec(hook_info_count);
}
}
void exit_hook_check(struct task_struct *tsk, long code)
{
if (exit_info_flag && hook_info_flag) {
__this_cpu_inc(hook_info_count);
smp_rmb();
get_exit_info_func = (typeof(get_exit_info_func))hook_func_array[EXIT_INFO];
if (get_exit_info_func) {
get_exit_info_func(tsk, code);
}
__this_cpu_dec(hook_info_count);
}
}
#else
void sock_hook_check(void *sock)
{
}
void recvfrom_hook_check(struct socket *sock, int fd, struct sockaddr_storage *address, int err)
{
}
void sendto_hook_check(struct socket *sock, int fd, struct sockaddr_storage *address, int err)
{
}
void connect_hook_check(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err)
{
}
void accept_hook_check(struct socket *sock, struct file *newfile, struct sockaddr_storage *address, int err)
{
}
void execve_hook_check(int argc, void *argv, int envc, void *envp, const char *filename)
{
}
void fork_hook_check(struct task_struct *p, unsigned long clone_flags)
{
}
void exit_hook_check(struct task_struct *tsk, long code)
{
}
#endif

View File

@ -123,6 +123,7 @@
#include <trace/events/sock.h> #include <trace/events/sock.h>
#include <linux/tkernel.h> #include <linux/tkernel.h>
#include <linux/hook_frame.h>
/* The inetsw table contains everything that inet_create needs to /* The inetsw table contains everything that inet_create needs to
* build a new socket. * build a new socket.
@ -1366,6 +1367,16 @@ void inet_sk_state_store(struct sock *sk, int newstate)
{ {
trace_inet_sock_set_state(sk, sk->sk_state, newstate); trace_inet_sock_set_state(sk, sk->sk_state, newstate);
smp_store_release(&sk->sk_state, newstate); smp_store_release(&sk->sk_state, newstate);
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
switch (sk->sk_state) {
case TCP_ESTABLISHED:
case TCP_LISTEN:
sock_hook_check(sk);
break;
default:
break;
}
#endif
} }
struct sk_buff *inet_gso_segment(struct sk_buff *skb, struct sk_buff *inet_gso_segment(struct sk_buff *skb,

View File

@ -15,6 +15,7 @@
#include <net/route.h> #include <net/route.h>
#include <net/tcp_states.h> #include <net/tcp_states.h>
#include <net/sock_reuseport.h> #include <net/sock_reuseport.h>
#include <linux/hook_frame.h>
int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{ {
@ -77,6 +78,10 @@ int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
sk_dst_set(sk, &rt->dst); sk_dst_set(sk, &rt->dst);
err = 0; err = 0;
#ifdef CONFIG_SECURITY_MONITOR
sock_hook_check(sk);
#endif
out: out:
return err; return err;
} }

View File

@ -75,6 +75,7 @@
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/hook_frame.h>
struct raw_frag_vec { struct raw_frag_vec {
struct msghdr *msg; struct msghdr *msg;
@ -101,6 +102,10 @@ int raw_hash_sk(struct sock *sk)
spin_unlock(&h->lock); spin_unlock(&h->lock);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
#ifdef CONFIG_SECURITY_MONITOR
sock_hook_check(sk);
#endif
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(raw_hash_sk); EXPORT_SYMBOL_GPL(raw_hash_sk);

View File

@ -115,6 +115,7 @@
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/udp_tunnel.h> #include <net/udp_tunnel.h>
#include <net/gro.h> #include <net/gro.h>
#include <linux/hook_frame.h>
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6_stubs.h> #include <net/ipv6_stubs.h>
#endif #endif
@ -344,6 +345,11 @@ found:
} }
sock_set_flag(sk, SOCK_RCU_FREE); sock_set_flag(sk, SOCK_RCU_FREE);
error = 0; error = 0;
#ifdef CONFIG_SECURITY_MONITOR
sock_hook_check(sk);
#endif
fail_unlock: fail_unlock:
spin_unlock_bh(&hslot->lock); spin_unlock_bh(&hslot->lock);
fail: fail:

View File

@ -109,6 +109,7 @@
#include <linux/errqueue.h> #include <linux/errqueue.h>
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
#include <trace/events/sock.h> #include <trace/events/sock.h>
#include <linux/hook_frame.h>
#ifdef CONFIG_NET_RX_BUSY_POLL #ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int sysctl_net_busy_read __read_mostly; unsigned int sysctl_net_busy_read __read_mostly;
@ -1572,6 +1573,11 @@ int __sock_create(struct net *net, int family, int type, int protocol,
if (err < 0) if (err < 0)
goto out_module_put; goto out_module_put;
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
if (sock->sk)
sock->sk->pid = task_tgid_nr(current);
#endif
/* /*
* Now to bump the refcnt of the [loadable] module that owns this * Now to bump the refcnt of the [loadable] module that owns this
* socket at sock_release time we decrement its refcnt. * socket at sock_release time we decrement its refcnt.
@ -1935,6 +1941,12 @@ struct file *do_accept(struct file *file, unsigned file_flags,
if (err < 0) if (err < 0)
goto out_fd; goto out_fd;
#ifdef CONFIG_SECURITY_MONITOR
if (newsock->sk)
newsock->sk->pid = task_tgid_nr(current);
accept_hook_check(newsock, newfile, &address, err);
#endif
if (upeer_sockaddr) { if (upeer_sockaddr) {
len = ops->getname(newsock, (struct sockaddr *)&address, 2); len = ops->getname(newsock, (struct sockaddr *)&address, 2);
if (len < 0) { if (len < 0) {
@ -2051,6 +2063,11 @@ int __sys_connect_file(struct file *file, struct sockaddr_storage *address,
err = READ_ONCE(sock->ops)->connect(sock, (struct sockaddr *)address, err = READ_ONCE(sock->ops)->connect(sock, (struct sockaddr *)address,
addrlen, sock->file->f_flags | file_flags); addrlen, sock->file->f_flags | file_flags);
#ifdef CONFIG_SECURITY_MONITOR
connect_hook_check(sock, file, address, err);
#endif
out: out:
return err; return err;
} }
@ -2195,6 +2212,10 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
msg.msg_flags = flags; msg.msg_flags = flags;
err = __sock_sendmsg(sock, &msg); err = __sock_sendmsg(sock, &msg);
#ifdef CONFIG_SECURITY_MONITOR
sendto_hook_check(sock, fd, &address, err);
#endif
out_put: out_put:
fput_light(sock->file, fput_needed); fput_light(sock->file, fput_needed);
out: out:
@ -2254,6 +2275,10 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
err = err2; err = err2;
} }
#ifdef CONFIG_SECURITY_MONITOR
recvfrom_hook_check(sock, fd, &address, err);
#endif
fput_light(sock->file, fput_needed); fput_light(sock->file, fput_needed);
out: out:
return err; return err;