From e109c5a0426d1bb5d0af1c322534dd87ff39b9ae Mon Sep 17 00:00:00 2001 From: zcfsite Date: Sat, 21 Oct 2023 18:00:05 +0800 Subject: [PATCH] secdetector inclusion category: feature bugzilla: https://gitee.comm/openeuler/kernel/issues/I89J93?from=project-issue ------------------------- support secDetector Add tracepoint secdetector_chkfsevent to monitor file creation, deletion, etc. Add tracepoint secdetector_chknetevent to monitor port access and network connections. Add tracepoint secdetector_chktaskevent to monitor process event. Add tracepoint secdetector_chkapievent to monitor sensitive calls Signed-off-by: chenjingwen Signed-off-by: zcfsite --- fs/exec.c | 40 +++++++++- fs/namei.c | 95 +++++++++++++++++++++- fs/open.c | 51 +++++++++++- fs/pipe.c | 16 ++++ fs/proc/array.c | 30 +++++++ fs/read_write.c | 49 +++++++++++- fs/utimes.c | 27 +++++++ fs/xattr.c | 71 ++++++++++++++++- include/linux/sched/signal.h | 14 +++- include/linux/secdetector.h | 147 +++++++++++++++++++++++++++++++++++ kernel/Makefile | 4 + kernel/cred.c | 14 ++++ kernel/fork.c | 60 ++++++++++++++ kernel/ptrace.c | 17 ++++ kernel/sched/core.c | 5 ++ kernel/secdetector.c | 35 +++++++++ mm/memfd.c | 16 ++++ net/socket.c | 142 +++++++++++++++++++++++++++++++-- security/Kconfig | 8 ++ 19 files changed, 825 insertions(+), 16 deletions(-) create mode 100644 include/linux/secdetector.h create mode 100644 kernel/secdetector.c diff --git a/fs/exec.c b/fs/exec.c index 981b3ac90c44..e44e1eeb7474 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -73,7 +73,9 @@ #include "internal.h" #include - +#ifdef CONFIG_SECDETECTOR +#include +#endif static int bprm_creds_from_file(struct linux_binprm *bprm); int suid_dumpable = 0; @@ -1689,6 +1691,18 @@ static int search_binary_handler(struct linux_binprm *bprm) if (retval) return retval; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chktaskevent_enabled()) { + int sec_ret = 0; + struct secdetector_task sec_task = { .bprm = bprm }; + + trace_secdetector_chktaskevent( + &sec_task, SECDETECTOR_TASK_BPRM_CHECK, &sec_ret); + if (sec_ret != 0) + return sec_ret; + } +#endif + retval = -ENOENT; retry: read_lock(&binfmt_lock); @@ -1849,6 +1863,30 @@ static int do_execveat_common(int fd, struct filename *filename, struct linux_binprm *bprm; int retval; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkapievent_enabled()) { + int sec_ret = 0; + struct secdetector_api sec_api = { + .api_name = "do_execveat_common", + .cur_task = current, +#ifdef CONFIG_COMPAT + .argv.is_compat = argv.is_compat, + .argv.compat = argv.ptr.compat, + .envp.is_compat = envp.is_compat, + .envp.compat = envp.ptr.compat, +#else + .argv.native = argv.ptr.native, + .envp.native = argv.ptr.native, +#endif + .exec_filename = filename + }; + trace_secdetector_chkapievent(&sec_api, SECDETECTOR_API_EXECVE, + &sec_ret); + if (sec_ret != 0) + return sec_ret; + } +#endif + if (IS_ERR(filename)) return PTR_ERR(filename); diff --git a/fs/namei.c b/fs/namei.c index 7b99aa8c9ab5..dc5b9a41ffc8 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -40,6 +40,10 @@ #include #include +#ifdef CONFIG_SECDETECTOR +#include +#endif + #include "internal.h" #include "mount.h" @@ -52,8 +56,8 @@ * The new code replaces the old recursive symlink resolution with * an iterative one (in case of non-nested symlink chains). It does * this with calls to _follow_link(). - * As a side effect, dir_namei(), _namei() and follow_link() are now - * replaced with a single function lookup_dentry() that can handle all + * As a side effect, dir_namei(), _namei() and follow_link() are now + * replaced with a single function lookup_dentry() that can handle all * the special cases of the former code. * * With the new dcache, the pathname is stored at each inode, at least as @@ -3468,6 +3472,13 @@ struct file *do_filp_open(int dfd, struct filename *pathname, if (unlikely(filp == ERR_PTR(-ESTALE))) filp = path_openat(&nd, op, flags | LOOKUP_REVAL); restore_nameidata(); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .file = filp, + .opflag = op->open_flag }; + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_OPEN, NULL); + } +#endif return filp; } @@ -3650,6 +3661,22 @@ static long do_mknodat(int dfd, const char __user *filename, umode_t mode, int error; unsigned int lookup_flags = 0; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkapievent_enabled()) { + int sec_ret = 0; + struct secdetector_api sec_api = { .api_name = "do_mknodat", + .cur_task = current, + .dfd = dfd, + .pipe_name = filename, + .mode = mode, + .dev = dev }; + trace_secdetector_chkapievent(&sec_api, SECDETECTOR_API_MKNOD, + &sec_ret); + if (sec_ret != 0) + return sec_ret; + } +#endif + error = may_mknod(mode); if (error) return error; @@ -3887,6 +3914,19 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate if (!dir->i_op->unlink) return -EPERM; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { + .dentry = dentry, + .dir = dir, + }; + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_UNLINK_PRE, + &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif inode_lock(target); if (IS_SWAPFILE(target)) error = -EPERM; @@ -3911,9 +3951,27 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate /* We don't d_delete() NFS sillyrenamed files--they still exist. */ if (!error && dentry->d_flags & DCACHE_NFSFS_RENAMED) { fsnotify_unlink(dir, dentry); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .dentry = dentry }; + + trace_secdetector_chkfsevent( + &sf, SECDETECTOR_FILE_UNLINK_NFS, NULL); + } +#endif } else if (!error) { fsnotify_link_count(target); d_delete_notify(dir, dentry); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .dentry = dentry }; + + trace_secdetector_chkfsevent( + &sf, SECDETECTOR_FILE_UNLINK, NULL); + } +#endif } return error; @@ -4347,6 +4405,23 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (error) return error; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { .file = NULL, + .dentry = old_dentry, + .new_dentry = new_dentry, + .rename_flag = flags, + .name = old_name.name.name, + .oldinode = old_dir, + .newinode = new_dir }; + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_RENAME_PRE, + &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif + take_dentry_name_snapshot(&old_name, old_dentry); dget(new_dentry); if (!is_dir || (flags & RENAME_EXCHANGE)) @@ -4412,6 +4487,22 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, fsnotify_move(new_dir, old_dir, &old_dentry->d_name, new_is_dir, NULL, new_dentry); } +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { + .file = NULL, + .dentry = old_dentry, + .new_dentry = new_dentry, + .rename_flag = flags, + .name = old_name.name.name, + .oldinode = old_dir, + .newinode = new_dir + }; + trace_secdetector_chkfsevent( + &sf, SECDETECTOR_FILE_RENAME, NULL); + } +#endif } release_dentry_name_snapshot(&old_name); diff --git a/fs/open.c b/fs/open.c index 8530ca1c0345..3790da03a095 100644 --- a/fs/open.c +++ b/fs/open.c @@ -33,6 +33,9 @@ #include #include +#ifdef CONFIG_SECDETECTOR +#include +#endif #include "internal.h" int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, @@ -573,6 +576,20 @@ int chmod_common(const struct path *path, umode_t mode) error = mnt_want_write(path->mnt); if (error) return error; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { + .dentry = path->dentry, + .path = path, + .mode = mode, + }; + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_CHMOD_PRE, + &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif retry_deleg: inode_lock(inode); error = security_path_chmod(path, mode); @@ -589,6 +606,14 @@ int chmod_common(const struct path *path, umode_t mode) goto retry_deleg; } mnt_drop_write(path->mnt); +#ifdef CONFIG_SECDETECTOR + if (error == 0 && secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .dentry = path->dentry }; + + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_CHMOD, NULL); + } +#endif return error; } @@ -650,7 +675,21 @@ int chown_common(const struct path *path, uid_t user, gid_t group) uid = make_kuid(current_user_ns(), user); gid = make_kgid(current_user_ns(), group); - +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { + .dentry = path->dentry, + .path = path, + .uid = uid, + .gid = gid, + }; + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_CHOWN_PRE, + &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif retry_deleg: newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { @@ -678,6 +717,14 @@ int chown_common(const struct path *path, uid_t user, gid_t group) if (!error) goto retry_deleg; } +#ifdef CONFIG_SECDETECTOR + if (error == 0 && secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .dentry = path->dentry }; + + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_CHOWN, NULL); + } +#endif return error; } @@ -1146,7 +1193,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode) { struct filename *name = getname_kernel(filename); struct file *file = ERR_CAST(name); - + if (!IS_ERR(name)) { file = file_open_name(name, flags, mode); putname(name); diff --git a/fs/pipe.c b/fs/pipe.c index 981d30af7d7d..f6a0cc3b4dac 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -31,6 +31,10 @@ #include "internal.h" +#ifdef CONFIG_SECDETECTOR +#include +#endif + /* * New pipe buffers will be restricted to this size while the user is exceeding * their pipe buffer quota. The general pipe use case needs at least two @@ -1008,6 +1012,18 @@ static int do_pipe2(int __user *fildes, int flags) int fd[2]; int error; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkapievent_enabled()) { + int sec_ret = 0; + struct secdetector_api sec_api = { .api_name = "do_pipe2", + .cur_task = current }; + trace_secdetector_chkapievent(&sec_api, SECDETECTOR_API_PIPE, + &sec_ret); + if (sec_ret != 0) + return sec_ret; + } +#endif + error = __do_pipe_flags(fd, files, flags); if (!error) { if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) { diff --git a/fs/proc/array.c b/fs/proc/array.c index 18a4588c35be..88c1e924b673 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -269,6 +269,11 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) int num_threads = 0; unsigned int qsize = 0; unsigned long qlim = 0; +#ifdef CONFIG_SECDETECTOR + pid_t eppid1 = 0, eppid2 = 0; + char *epexe1 = NULL; + char *epexe2 = NULL; +#endif sigemptyset(&pending); sigemptyset(&shpending); @@ -276,6 +281,11 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) sigemptyset(&ignored); sigemptyset(&caught); +#ifdef CONFIG_SECDETECTOR + epexe1 = kzalloc(PATH_MAX, GFP_KERNEL); + epexe2 = kzalloc(PATH_MAX, GFP_KERNEL); +#endif + if (lock_task_sighand(p, &flags)) { pending = p->pending.signal; shpending = p->signal->shared_pending.signal; @@ -286,9 +296,25 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) qsize = atomic_read(&__task_cred(p)->user->sigpending); rcu_read_unlock(); qlim = task_rlimit(p, RLIMIT_SIGPENDING); +#ifdef CONFIG_SECDETECTOR + if (p->signal->secdetector_process) { + if (epexe1 && p->signal->secdetector_process->epexe1) + strcpy(epexe1, p->signal->secdetector_process->epexe1); + if (epexe2 && p->signal->secdetector_process->epexe2) + strcpy(epexe2, p->signal->secdetector_process->epexe2); + eppid1 = p->signal->secdetector_process->eppid1; + eppid2 = p->signal->secdetector_process->eppid2; + } +#endif unlock_task_sighand(p, &flags); } +#ifdef CONFIG_SECDETECTOR + seq_printf(m, "eppid1: %d\n", eppid1); + seq_printf(m, "eppid2: %d\n", eppid2); + seq_printf(m, "epexe1: %s\n", epexe1 ?: "NULL"); + seq_printf(m, "epexe2: %s\n", epexe2 ?: "NULL"); +#endif seq_put_decimal_ull(m, "Threads:\t", num_threads); seq_put_decimal_ull(m, "\nSigQ:\t", qsize); seq_put_decimal_ull(m, "/", qlim); @@ -299,6 +325,10 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) render_sigset_t(m, "SigBlk:\t", &blocked); render_sigset_t(m, "SigIgn:\t", &ignored); render_sigset_t(m, "SigCgt:\t", &caught); +#ifdef CONFIG_SECDETECTOR + kfree(epexe1); + kfree(epexe2); +#endif } static void render_cap_t(struct seq_file *m, const char *header, diff --git a/fs/read_write.c b/fs/read_write.c index 371a5a76f30e..92b63ada99f7 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -27,6 +27,10 @@ #define CREATE_TRACE_POINTS #include +#ifdef CONFIG_SECDETECTOR +#include +#endif + const struct file_operations generic_ro_fops = { .llseek = generic_file_llseek, .read_iter = generic_file_read_iter, @@ -484,6 +488,19 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) ret = rw_verify_area(READ, file, pos, count); if (ret) return ret; + +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { .file = file }; + + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_READ_PRE, + &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif + if (count > MAX_RW_COUNT) count = MAX_RW_COUNT; @@ -496,6 +513,15 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) if (ret > 0) { fsnotify_access(file); add_rchar(current, ret); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .file = file }; + + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_READ, + NULL); + } +#endif } inc_syscr(current); return ret; @@ -593,6 +619,17 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ ret = rw_verify_area(WRITE, file, pos, count); if (ret) return ret; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { .file = file }; + + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_WRITE_PRE, + &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif if (count > MAX_RW_COUNT) count = MAX_RW_COUNT; file_start_write(file); @@ -605,6 +642,16 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ if (ret > 0) { fsnotify_modify(file); add_wchar(current, ret); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .file = file, + .buf = buf, + .buf_len = count }; + trace_secdetector_chkfsevent( + &sf, SECDETECTOR_FILE_WRITE, NULL); + } +#endif } inc_syscw(current); file_end_write(file); @@ -705,7 +752,7 @@ ssize_t ksys_pwrite64(unsigned int fd, const char __user *buf, f = fdget(fd); if (f.file) { ret = -ESPIPE; - if (f.file->f_mode & FMODE_PWRITE) + if (f.file->f_mode & FMODE_PWRITE) ret = vfs_write(f.file, buf, count, &pos); fdput(f); } diff --git a/fs/utimes.c b/fs/utimes.c index fd3cc4226224..65f0ba352f84 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -8,6 +8,10 @@ #include #include +#ifdef CONFIG_SECDETECTOR +#include +#endif + static bool nsec_valid(long nsec) { if (nsec == UTIME_OMIT || nsec == UTIME_NOW) @@ -36,6 +40,21 @@ int vfs_utimes(const struct path *path, struct timespec64 *times) if (error) goto out; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { + .dentry = path->dentry, + .path = path, + }; + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_UTIMES_PRE, + &sec_ret); + if (sec_ret) { + error = sec_ret; + goto out; + } + } +#endif newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { if (times[0].tv_nsec == UTIME_OMIT) @@ -71,6 +90,14 @@ int vfs_utimes(const struct path *path, struct timespec64 *times) } mnt_drop_write(path->mnt); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .dentry = path->dentry }; + + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_UTIMES, + NULL); + } +#endif out: return error; } diff --git a/fs/xattr.c b/fs/xattr.c index a00d866fb029..960cf30419d0 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -27,6 +27,9 @@ #include #include +#ifdef CONFIG_SECDETECTOR +#include +#endif static const char * strcmp_prefix(const char *a, const char *a_prefix) @@ -211,6 +214,18 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, error = __vfs_setxattr(dentry, inode, name, value, size, flags); if (!error) { fsnotify_xattr(dentry); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .dentry = dentry, + .name = name, + .value = value, + .value_len = + size }; + trace_secdetector_chkfsevent( + &sf, SECDETECTOR_FILE_SETXATTR, NULL); + } +#endif security_inode_post_setxattr(dentry, name, value, size, flags); } @@ -226,8 +241,24 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, error = security_inode_setsecurity(inode, suffix, value, size, flags); - if (!error) + if (!error) { fsnotify_xattr(dentry); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf_tmp = { + .dentry = dentry, + .name = name, + .value = value, + .value_len = size + }; + trace_secdetector_chkfsevent( + &sf_tmp, + SECDETECTOR_FILE_SETXATTR2, + NULL); + } +#endif + } } } @@ -262,6 +293,23 @@ __vfs_setxattr_locked(struct dentry *dentry, const char *name, if (error) goto out; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { + .dentry = dentry, + .name = name, + .value = value, + .value_len = size, + .flags = flags, + }; + trace_secdetector_chkfsevent(&sf, SECDETECTOR_FILE_SETXATTR_PRE, + &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif + error = try_break_deleg(inode, delegated_inode); if (error) goto out; @@ -468,7 +516,17 @@ __vfs_removexattr_locked(struct dentry *dentry, const char *name, error = security_inode_removexattr(dentry, name); if (error) goto out; - +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkfsevent_enabled()) { + int sec_ret = 0; + struct secdetector_file sf = { .dentry = dentry, .name = name }; + + trace_secdetector_chkfsevent( + &sf, SECDETECTOR_FILE_REMOVEXATTR_PRE, &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif error = try_break_deleg(inode, delegated_inode); if (error) goto out; @@ -481,6 +539,15 @@ __vfs_removexattr_locked(struct dentry *dentry, const char *name, ima_inode_post_removexattr(dentry, name); #endif evm_inode_post_removexattr(dentry, name); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chkfsevent_enabled()) { + struct secdetector_file sf = { .dentry = dentry, + .name = name }; + trace_secdetector_chkfsevent( + &sf, SECDETECTOR_FILE_REMOVEXATTR, NULL); + } +#endif } out: diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 174735dbad31..bd1415c605ba 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -73,6 +73,15 @@ struct multiprocess_signals { struct hlist_node node; }; +#ifdef CONFIG_SECDETECTOR +struct secdetector_process_struct { + pid_t eppid1; + pid_t eppid2; + char *epexe1; + char *epexe2; +}; +#endif + /* * NOTE! "signal_struct" does not have its own * locking, because a shared signal_struct always @@ -236,8 +245,11 @@ struct signal_struct { * and may have inconsistent * permissions. */ - +#if defined(CONFIG_SECDETECTOR) && !defined(__GENKSYMS__) + struct secdetector_process_struct *secdetector_process; +#else KABI_RESERVE(1) +#endif KABI_RESERVE(2) KABI_RESERVE(3) KABI_RESERVE(4) diff --git a/include/linux/secdetector.h b/include/linux/secdetector.h new file mode 100644 index 000000000000..8be216080fce --- /dev/null +++ b/include/linux/secdetector.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifdef CONFIG_SECDETECTOR +#ifndef _SECDETECTOR_H +#define _SECDETECTOR_H + +#include + +struct secdetector_file { + struct file *file; + struct dentry *dentry; + struct dentry *new_dentry; + unsigned int rename_flag; + int opflag; + const char *name; + const void *value; + size_t value_len; + struct inode *oldinode; + struct inode *newinode; + struct inode *dir; + const struct path *path; + umode_t mode; + kuid_t uid; + kgid_t gid; + const char __user *buf; + size_t buf_len; + int flags; +}; + +struct secdetector_net { + struct socket *sock; + struct socket *newsock; + struct sockaddr *address; + int addrlen; + struct msghdr *msg; + int size; + int backlog; +}; + +struct secdetector_task { + struct task_struct *task; + const struct cred *old_cred; + const struct cred *new_cred; + const struct linux_binprm *bprm; +}; + +typedef u32 compat_uptr_t; + +struct sec_user_arg_ptr { +#ifdef CONFIG_COMPAT + bool is_compat; +#endif + const char __user *const __user *native; +#ifdef CONFIG_COMPAT + const compat_uptr_t __user *compat; +#endif +}; + +struct secdetector_api { + const char *api_name; + struct task_struct *cur_task; + struct task_struct *arg_task; + struct filename *exec_filename; + struct sec_user_arg_ptr argv; + struct sec_user_arg_ptr envp; + int dfd; + const char __user *pipe_name; + umode_t mode; + unsigned int dev; +}; + +enum SECDETECTOR_FILE_EVENT { + SECDETECTOR_FILE_WRITE = 1, + SECDETECTOR_FILE_UNLINK_NFS = 2, + SECDETECTOR_FILE_UNLINK = 3, + SECDETECTOR_FILE_OPEN = 4, + SECDETECTOR_FILE_RENAME = 5, + SECDETECTOR_FILE_SETXATTR = 6, + SECDETECTOR_FILE_SETXATTR2 = 7, + SECDETECTOR_FILE_REMOVEXATTR = 8, + SECDETECTOR_FILE_READ = 9, + SECDETECTOR_FILE_CHMOD = 10, + SECDETECTOR_FILE_CHOWN = 11, + SECDETECTOR_FILE_UTIMES = 12, + SECDETECTOR_FILE_RENAME_PRE = 15, + SECDETECTOR_FILE_WRITE_PRE = 14, + SECDETECTOR_FILE_READ_PRE = 13, + SECDETECTOR_FILE_UNLINK_PRE = 16, + SECDETECTOR_FILE_SETXATTR_PRE = 17, + SECDETECTOR_FILE_REMOVEXATTR_PRE = 18, + SECDETECTOR_FILE_CHMOD_PRE = 19, + SECDETECTOR_FILE_CHOWN_PRE = 20, + SECDETECTOR_FILE_UTIMES_PRE = 21, + SECDETECTOR_FILE_NUM, +}; + +enum SECDETECTOR_NET_EVENT { + SECDETECTOR_NET_SENDMSG = 1, + SECDETECTOR_NET_RECVMSG = 2, + SECDETECTOR_NET_BIND = 3, + SECDETECTOR_NET_LISTEN = 4, + SECDETECTOR_NET_ACCEPT = 5, + SECDETECTOR_NET_CONNECT = 6, + SECDETECTOR_NET_SENDMSG_PRE = 7, + SECDETECTOR_NET_RECVMSG_PRE = 8, + SECDETECTOR_NET_BIND_PRE = 9, + SECDETECTOR_NET_LISTEN_PRE = 10, + SECDETECTOR_NET_ACCEPT_PRE = 11, + SECDETECTOR_NET_CONNECT_PRE = 12, + SECDETECTOR_NET_NUM, +}; + +enum SECDETECTOR_TASK_EVENT { + SECDETECTOR_TASK_BPRM_CHECK = 1, + SECDETECTOR_TASK_CRED_CHANGE = 2, + SECDETECTOR_TASK_NUM, +}; + +enum SECDETECTOR_API_EVENT { + SECDETECTOR_API_PTRACE = 1, + SECDETECTOR_API_MEMFD = 2, + SECDETECTOR_API_EXECVE = 3, + SECDETECTOR_API_PIPE = 4, + SECDETECTOR_API_MKNOD = 5, + SECDETECTOR_API_NUM, +}; + +extern bool secdetector_enable; + +DECLARE_TRACE(secdetector_chkfsevent, + TP_PROTO(struct secdetector_file *file, int flag, int *sec_ret), + TP_ARGS(file, flag, sec_ret)); + +DECLARE_TRACE(secdetector_chknetevent, + TP_PROTO(struct secdetector_net *net, int flag, int *sec_ret), + TP_ARGS(net, flag, sec_ret)); + +DECLARE_TRACE(secdetector_chktaskevent, + TP_PROTO(struct secdetector_task *task, int flag, int *sec_ret), + TP_ARGS(task, flag, sec_ret)); + +DECLARE_TRACE(secdetector_chkapievent, + TP_PROTO(struct secdetector_api *api, int flag, int *sec_ret), + TP_ARGS(api, flag, sec_ret)); + +#endif +#endif diff --git a/kernel/Makefile b/kernel/Makefile index 3ae3b70c46e8..697992737f8c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -124,6 +124,10 @@ obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o +ifeq ($(CONFIG_SECDETECTOR),y) +obj-y += secdetector.o +endif + CFLAGS_stackleak.o += $(DISABLE_STACKLEAK_PLUGIN) obj-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak.o KASAN_SANITIZE_stackleak.o := n diff --git a/kernel/cred.c b/kernel/cred.c index 421b1149c651..30ffb3967b2d 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -16,6 +16,9 @@ #include #include #include +#ifdef CONFIG_SECDETECTOR +#include +#endif #if 0 #define kdebug(FMT, ...) \ @@ -450,6 +453,17 @@ int commit_creds(struct cred *new) validate_creds(new); #endif BUG_ON(atomic_read(&new->usage) < 1); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chktaskevent_enabled()) { + int sec_ret = 0; + struct secdetector_task sec_task = { .old_cred = old, + .new_cred = new }; + trace_secdetector_chktaskevent( + &sec_task, SECDETECTOR_TASK_CRED_CHANGE, &sec_ret); + if (sec_ret != 0) + return sec_ret; + } +#endif get_cred(new); /* we will require a ref for the subj creds too */ diff --git a/kernel/fork.c b/kernel/fork.c index a531fd38d111..7a6876798dfa 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -110,6 +110,10 @@ #define CREATE_TRACE_POINTS #include +#ifdef CONFIG_SECDETECTOR +#include +#endif + /* * Minimum number of threads to boot the kernel */ @@ -725,6 +729,16 @@ static inline void free_signal_struct(struct signal_struct *sig) */ if (sig->oom_mm) mmdrop_async(sig->oom_mm); +#ifdef CONFIG_SECDETECTOR + kfree(sig->secdetector_process->epexe1); + sig->secdetector_process->epexe1 = NULL; + + kfree(sig->secdetector_process->epexe2); + sig->secdetector_process->epexe2 = NULL; + + kfree(sig->secdetector_process); + sig->secdetector_process = NULL; +#endif kmem_cache_free(signal_cachep, sig); } @@ -1642,6 +1656,30 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig) posix_cputimers_group_init(pct, cpu_limit); } +#ifdef CONFIG_SECDETECTOR +static void copy_pexe(struct signal_struct *sig) +{ + char *kbuf; + char *exe_path; + struct file *f; + + kbuf = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL); + if (!kbuf) + return; + f = get_task_exe_file(current); + if (!f) + goto out_free; + + exe_path = d_path(&f->f_path, kbuf, PATH_MAX); + if (!IS_ERR(exe_path)) + sig->secdetector_process->epexe1 = kstrdup(exe_path, GFP_KERNEL); + + fput(f); +out_free: + kfree(kbuf); +} +#endif + static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) { struct signal_struct *sig; @@ -1654,6 +1692,28 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) if (!sig) return -ENOMEM; +#ifdef CONFIG_SECDETECTOR + sig->secdetector_process = kzalloc(sizeof(struct secdetector_process_struct), GFP_KERNEL); + if (!sig->secdetector_process) + return -ENOMEM; + + sig->secdetector_process->eppid1 = task_tgid_vnr(current); + if (!current->signal->secdetector_process) + sig->secdetector_process->eppid2 = 1; + else + sig->secdetector_process->eppid2 = + current->signal->secdetector_process->eppid1; + + if (sig->secdetector_process->eppid2 == 0) + sig->secdetector_process->eppid2 = 1; // the root always is 1 + + copy_pexe(sig); + if (current->signal->secdetector_process + && current->signal->secdetector_process->epexe1) + sig->secdetector_process->epexe2 = + kstrdup(current->signal->secdetector_process->epexe1, + GFP_KERNEL); +#endif sig->nr_threads = 1; atomic_set(&sig->live, 1); refcount_set(&sig->sigcnt, 1); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 6d82fba43c97..caf55a238ea3 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -35,6 +35,10 @@ #include /* for syscall_get_* */ +#ifdef CONFIG_SECDETECTOR +#include +#endif + /* * Access another process' address space via ptrace. * Source/target buffer must be kernel space, @@ -417,6 +421,19 @@ static int ptrace_attach(struct task_struct *task, long request, flags = PT_PTRACED; } +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkapievent_enabled()) { + int sec_ret = 0; + struct secdetector_api sec_api = { .api_name = "ptrace", + .cur_task = current, + .arg_task = task }; + trace_secdetector_chkapievent(&sec_api, SECDETECTOR_API_PTRACE, + &sec_ret); + if (sec_ret != 0) + return sec_ret; + } +#endif + audit_ptrace(task); retval = -EPERM; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 5d17bffffaf4..39f78966dab4 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -42,6 +42,11 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_cfs_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_se_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp); +#ifdef CONFIG_SECDETECTOR +EXPORT_TRACEPOINT_SYMBOL_GPL(sched_process_fork); +EXPORT_TRACEPOINT_SYMBOL_GPL(sched_process_exec); +EXPORT_TRACEPOINT_SYMBOL_GPL(sched_process_exit); +#endif DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); diff --git a/kernel/secdetector.c b/kernel/secdetector.c new file mode 100644 index 000000000000..3aa5264ee9e6 --- /dev/null +++ b/kernel/secdetector.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#ifdef CONFIG_SECDETECTOR + +#include + +DEFINE_TRACE(secdetector_chkfsevent, + TP_PROTO(struct secdetector_file *file, int flag, int *sec_ret), + TP_ARGS(file, flag, sec_ret)); +EXPORT_TRACEPOINT_SYMBOL(secdetector_chkfsevent); + +DEFINE_TRACE(secdetector_chknetevent, + TP_PROTO(struct secdetector_net *net, int flag, int *sec_ret), + TP_ARGS(net, flag, sec_ret)); +EXPORT_TRACEPOINT_SYMBOL(secdetector_chknetevent); + +DEFINE_TRACE(secdetector_chktaskevent, + TP_PROTO(struct secdetector_task *task, int flag, int *sec_ret), + TP_ARGS(task, flag, sec_ret)); +EXPORT_TRACEPOINT_SYMBOL(secdetector_chktaskevent); + +DEFINE_TRACE(secdetector_chkapievent, + TP_PROTO(struct secdetector_api *api, int flag, int *sec_ret), + TP_ARGS(api, flag, sec_ret)); +EXPORT_TRACEPOINT_SYMBOL(secdetector_chkapievent); + +bool secdetector_enable __ro_after_init; +static int __init secdetector_enable_setup(char *str) +{ + secdetector_enable = true; + return 1; +} +__setup("secdetector_enable", secdetector_enable_setup); + +#endif diff --git a/mm/memfd.c b/mm/memfd.c index fae4142f7d25..84a99baf034c 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -20,6 +20,10 @@ #include #include +#ifdef CONFIG_SECDETECTOR +#include +#endif + /* * We need a tag: a new tag would expand every xa_node by 8 bytes, * so reuse a tag which we firmly believe is never set or cleared on tmpfs @@ -273,6 +277,18 @@ SYSCALL_DEFINE2(memfd_create, char *name; long len; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chkapievent_enabled()) { + int sec_ret = 0; + struct secdetector_api sec_api = { .api_name = "memfd_create", + .cur_task = current }; + trace_secdetector_chkapievent(&sec_api, SECDETECTOR_API_MEMFD, + &sec_ret); + if (sec_ret != 0) + return sec_ret; + } +#endif + if (!(flags & MFD_HUGETLB)) { if (flags & ~(unsigned int)MFD_ALL_FLAGS) return -EINVAL; diff --git a/net/socket.c b/net/socket.c index 01d530af98ca..7c944f98f97a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -105,6 +105,10 @@ #include #include +#ifdef CONFIG_SECDETECTOR +#include +#endif + #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sysctl_net_busy_read __read_mostly; unsigned int sysctl_net_busy_poll __read_mostly; @@ -667,8 +671,26 @@ static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) */ int sock_sendmsg(struct socket *sock, struct msghdr *msg) { - int err = security_socket_sendmsg(sock, msg, - msg_data_left(msg)); + int err; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chknetevent_enabled()) { + int sec_ret = 0; + struct secdetector_net sn = { .sock = sock, .msg = msg }; + + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_SENDMSG_PRE, &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif + + err = security_socket_sendmsg(sock, msg, msg_data_left(msg)); +#ifdef CONFIG_SECDETECTOR + if (err == 0 && secdetector_enable) { + struct secdetector_net sn = { .sock = sock, .msg = msg }; + + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_SENDMSG, NULL); + } +#endif return err ?: sock_sendmsg_nosec(sock, msg); } @@ -900,8 +922,25 @@ static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, */ int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags) { - int err = security_socket_recvmsg(sock, msg, msg_data_left(msg), flags); + int err; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chknetevent_enabled()) { + int sec_ret = 0; + struct secdetector_net sn = { .sock = sock, .msg = msg }; + + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_RECVMSG_PRE, &sec_ret); + if (sec_ret) + return sec_ret; + } +#endif + err = security_socket_recvmsg(sock, msg, msg_data_left(msg), flags); +#ifdef CONFIG_SECDETECTOR + if (err == 0 && secdetector_enable) { + struct secdetector_net sn = { .sock = sock, .msg = msg }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_RECVMSG, NULL); + } +#endif return err ?: sock_recvmsg_nosec(sock, msg, flags); } EXPORT_SYMBOL(sock_recvmsg); @@ -1643,10 +1682,37 @@ int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) err = security_socket_bind(sock, (struct sockaddr *)&address, addrlen); - if (!err) +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chknetevent_enabled()) { + int sec_ret = 0; + struct secdetector_net sn = { + .sock = sock, + .address = (struct sockaddr *)&address, + .addrlen = addrlen, + }; + trace_secdetector_chknetevent(&sn, + SECDETECTOR_NET_BIND_PRE, &sec_ret); + if (sec_ret) + err = sec_ret; + } +#endif + if (!err) { err = sock->ops->bind(sock, (struct sockaddr *) &address, addrlen); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable) { + struct secdetector_net sn = { + .sock = sock, + .address = (struct sockaddr + *)&address + }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_BIND, + NULL); + } +#endif + } } fput_light(sock->file, fput_needed); } @@ -1677,9 +1743,29 @@ int __sys_listen(int fd, int backlog) backlog = somaxconn; err = security_socket_listen(sock, backlog); - if (!err) +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && + trace_secdetector_chknetevent_enabled()) { + int sec_ret = 0; + struct secdetector_net sn = { + .sock = sock, + .backlog = backlog, + }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_LISTEN_PRE, &sec_ret); + if (sec_ret) + err = sec_ret; + } +#endif + if (!err) { err = sock->ops->listen(sock, backlog); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable) { + struct secdetector_net sn = { .sock = sock }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_LISTEN, NULL); + } +#endif + } fput_light(sock->file, fput_needed); } return err; @@ -1724,11 +1810,31 @@ struct file *do_accept(struct file *file, unsigned file_flags, if (err) goto out_fd; +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chknetevent_enabled()) { + int sec_ret = 0; + struct secdetector_net sn = { + .sock = sock, + .newsock = newsock, + }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_ACCEPT_PRE, &sec_ret); + if (sec_ret) { + err = sec_ret; + goto out_fd; + } + } +#endif err = sock->ops->accept(sock, newsock, sock->file->f_flags | file_flags, false); if (err < 0) goto out_fd; - +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable) { + struct secdetector_net sn = { .sock = sock, + .newsock = newsock }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_ACCEPT, NULL); + } +#endif if (upeer_sockaddr) { len = newsock->ops->getname(newsock, (struct sockaddr *)&address, 2); @@ -1844,9 +1950,31 @@ int __sys_connect_file(struct file *file, struct sockaddr_storage *address, security_socket_connect(sock, (struct sockaddr *)address, addrlen); if (err) goto out; - +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable && trace_secdetector_chknetevent_enabled()) { + int sec_ret = 0; + struct secdetector_net sn = { + .sock = sock, + .address = (struct sockaddr *)address, + .addrlen = addrlen, + }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_CONNECT_PRE, &sec_ret); + if (sec_ret) { + err = sec_ret; + goto out; + } + } +#endif err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, sock->file->f_flags | file_flags); +#ifdef CONFIG_SECDETECTOR + if (secdetector_enable) { + struct secdetector_net sn = { + .sock = sock, .address = (struct sockaddr *)address + }; + trace_secdetector_chknetevent(&sn, SECDETECTOR_NET_CONNECT, NULL); + } +#endif out: return err; } diff --git a/security/Kconfig b/security/Kconfig index c5cbae420e82..d22d3ccc9214 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -290,5 +290,13 @@ config SECURITY_BOOT_INIT help No support init and rdinit parameters in cmdline +config SECDETECTOR + bool "secDetector support" + depends on TRACEPOINTS + default y + help + secDetector means Kernel Intrusion Detection System. + Say yes heare to support the feature. + If unsure, say N. endmenu -- Gitee