[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:
parent
141ba6644b
commit
62b6061f57
|
@ -1974,3 +1974,6 @@ CONFIG_ATOMIC64_SELFTEST=y
|
|||
CONFIG_ASYNC_RAID6_TEST=m
|
||||
CONFIG_TEST_KSTRTOX=y
|
||||
CONFIG_TEST_BPF=m
|
||||
CONFIG_TKERNEL=y
|
||||
CONFIG_TKERNEL_SECURITY_MONITOR=y
|
||||
CONFIG_TKERNEL_AEGIS_MODULE=m
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include "internal.h"
|
||||
|
||||
#include <trace/events/sched.h>
|
||||
#include <linux/hook_frame.h>
|
||||
|
||||
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;
|
||||
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);
|
||||
out_free:
|
||||
|
|
29
fs/fcntl.c
29
fs/fcntl.c
|
@ -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,
|
||||
unsigned long arg)
|
||||
{
|
||||
|
@ -417,6 +442,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
|||
case F_SET_RW_HINT:
|
||||
err = fcntl_rw_hint(filp, cmd, arg);
|
||||
break;
|
||||
case F_SET_FILE_HOOK_FLAG:
|
||||
case F_GET_FILE_HOOK_FLAG:
|
||||
err = fcntl_rw_hook(filp, cmd, arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1040,6 +1040,7 @@ struct file {
|
|||
struct address_space *f_mapping;
|
||||
errseq_t f_wb_err;
|
||||
errseq_t f_sb_err; /* for syncfs */
|
||||
unsigned long hook_flags;
|
||||
} __randomize_layout
|
||||
__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
|
||||
|
||||
|
|
|
@ -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
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/syscall_user_dispatch.h>
|
||||
#include <linux/mm_types_task.h>
|
||||
#include <linux/task_io_accounting.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/posix-timers.h>
|
||||
#include <linux/rseq.h>
|
||||
#include <linux/seqlock.h>
|
||||
|
@ -768,6 +769,14 @@ struct kmap_ctrl {
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TKERNEL_SECURITY_MONITOR
|
||||
struct security_moni_info {
|
||||
struct kref refcount;
|
||||
long size;
|
||||
char buffer[];
|
||||
};
|
||||
#endif
|
||||
|
||||
struct task_struct {
|
||||
#ifdef CONFIG_THREAD_INFO_IN_TASK
|
||||
/*
|
||||
|
@ -811,6 +820,10 @@ struct task_struct {
|
|||
*/
|
||||
int recent_used_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
|
||||
int on_rq;
|
||||
|
||||
|
|
|
@ -546,6 +546,7 @@ struct sock {
|
|||
struct rcu_head sk_rcu;
|
||||
netns_tracker ns_tracker;
|
||||
struct hlist_node sk_bind2_node;
|
||||
pid_t pid;
|
||||
|
||||
KABI_RESERVE(1);
|
||||
KABI_RESERVE(2);
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
#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_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
|
||||
* used to clear any hints previously set.
|
||||
|
|
|
@ -76,6 +76,9 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <asm/unistd.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
|
||||
|
@ -868,6 +871,14 @@ void __noreturn do_exit(long code)
|
|||
acct_process();
|
||||
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_shm(tsk);
|
||||
exit_files(tsk);
|
||||
|
|
|
@ -112,6 +112,8 @@
|
|||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/task.h>
|
||||
|
||||
#include <linux/hook_frame.h>
|
||||
|
||||
/*
|
||||
* 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))
|
||||
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
|
||||
* might get invalid after that point, if the thread exits quickly.
|
||||
|
|
106
kernel/sysctl.c
106
kernel/sysctl.c
|
@ -159,6 +159,17 @@ extern int sysctl_vm_ramdisk_swaptune;
|
|||
extern int sysctl_vm_swapcache_fastfree;
|
||||
#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 */
|
||||
|
||||
/*
|
||||
|
@ -1716,6 +1727,27 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
|
|||
#endif /* CONFIG_PROC_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,
|
||||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
|
@ -1751,6 +1783,80 @@ DECLARE_STATIC_KEY_TRUE(rps_using_pvipi);
|
|||
#endif
|
||||
|
||||
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",
|
||||
.data = &panic_timeout,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
menuconfig TKERNEL
|
||||
bool "Tencent Kernel Features"
|
||||
default n
|
||||
default y
|
||||
|
||||
if TKERNEL
|
||||
|
||||
|
@ -27,4 +27,16 @@ config TKERNEL_SHIELD_MOUNTS
|
|||
bool 'Shield mount'
|
||||
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
|
||||
|
|
|
@ -3,3 +3,5 @@ obj-$(CONFIG_TKERNEL_NONPRIV_NETBIND) += netbind.o
|
|||
obj-$(CONFIG_TKERNEL_TTOOLS) += ttools/
|
||||
obj-$(CONFIG_TKERNEL_NETATOP) += netatop/
|
||||
obj-$(CONFIG_TKERNEL_SHIELD_MOUNTS) += shield_mounts.o
|
||||
obj-$(CONFIG_TKERNEL_SECURITY_MONITOR) += onionhook/
|
||||
obj-$(CONFIG_TKERNEL_AEGIS_MODULE) += aegis/
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
obj-$(CONFIG_TKERNEL_AEGIS_MODULE) += aegis.o
|
||||
aegis-objs := module.o list.o hook_info.o
|
||||
|
|
@ -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(¤t->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(¤t->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(¤t->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);
|
||||
}
|
|
@ -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_
|
|
@ -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();
|
||||
}
|
|
@ -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_
|
|
@ -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");
|
||||
|
|
@ -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_
|
|
@ -0,0 +1 @@
|
|||
obj-y := hook_frame.o
|
|
@ -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
|
|
@ -123,6 +123,7 @@
|
|||
|
||||
#include <trace/events/sock.h>
|
||||
#include <linux/tkernel.h>
|
||||
#include <linux/hook_frame.h>
|
||||
|
||||
/* The inetsw table contains everything that inet_create needs to
|
||||
* 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);
|
||||
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,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <net/route.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <net/sock_reuseport.h>
|
||||
#include <linux/hook_frame.h>
|
||||
|
||||
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);
|
||||
err = 0;
|
||||
#ifdef CONFIG_SECURITY_MONITOR
|
||||
sock_hook_check(sk);
|
||||
#endif
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/hook_frame.h>
|
||||
|
||||
struct raw_frag_vec {
|
||||
struct msghdr *msg;
|
||||
|
@ -101,6 +102,10 @@ int raw_hash_sk(struct sock *sk)
|
|||
spin_unlock(&h->lock);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
||||
|
||||
#ifdef CONFIG_SECURITY_MONITOR
|
||||
sock_hook_check(sk);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(raw_hash_sk);
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
#include <net/addrconf.h>
|
||||
#include <net/udp_tunnel.h>
|
||||
#include <net/gro.h>
|
||||
#include <linux/hook_frame.h>
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
#include <net/ipv6_stubs.h>
|
||||
#endif
|
||||
|
@ -344,6 +345,11 @@ found:
|
|||
}
|
||||
sock_set_flag(sk, SOCK_RCU_FREE);
|
||||
error = 0;
|
||||
|
||||
#ifdef CONFIG_SECURITY_MONITOR
|
||||
sock_hook_check(sk);
|
||||
#endif
|
||||
|
||||
fail_unlock:
|
||||
spin_unlock_bh(&hslot->lock);
|
||||
fail:
|
||||
|
|
25
net/socket.c
25
net/socket.c
|
@ -109,6 +109,7 @@
|
|||
#include <linux/errqueue.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <trace/events/sock.h>
|
||||
#include <linux/hook_frame.h>
|
||||
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
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)
|
||||
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
|
||||
* 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)
|
||||
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) {
|
||||
len = ops->getname(newsock, (struct sockaddr *)&address, 2);
|
||||
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,
|
||||
addrlen, sock->file->f_flags | file_flags);
|
||||
|
||||
#ifdef CONFIG_SECURITY_MONITOR
|
||||
connect_hook_check(sock, file, address, err);
|
||||
#endif
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
@ -2195,6 +2212,10 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
|
|||
msg.msg_flags = flags;
|
||||
err = __sock_sendmsg(sock, &msg);
|
||||
|
||||
#ifdef CONFIG_SECURITY_MONITOR
|
||||
sendto_hook_check(sock, fd, &address, err);
|
||||
#endif
|
||||
|
||||
out_put:
|
||||
fput_light(sock->file, fput_needed);
|
||||
out:
|
||||
|
@ -2254,6 +2275,10 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
|
|||
err = err2;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURITY_MONITOR
|
||||
recvfrom_hook_check(sock, fd, &address, err);
|
||||
#endif
|
||||
|
||||
fput_light(sock->file, fput_needed);
|
||||
out:
|
||||
return err;
|
||||
|
|
Loading…
Reference in New Issue