Message ID | 20160804071140.GA19121@ircssh.c.rugged-nimbus-611.internal (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
+void register_checmate_prog_ops(void); maybe it is extern void register_checmate_prog_ops(void);? + preempt_disable(); + rcu_read_lock(); IMHO, it is not necessary to use the above 2 since rcu_read_lock will call preempt_disable. Zhu Yanjun On Thu, Aug 4, 2016 at 3:11 PM, Sargun Dhillon <sargun@sargun.me> wrote: > This adds the minor LSM Checmate. The purpose of Checmate is to act as an > extensible LSM in which you can load security modules. The module has a > simple API, as it's meant to have most of the logic in BPF hooks. It has > three APIs that are accessible via prctl. > > As follows: > * Install hook: This appends a new BPF program to a given hook. Hook > programs themselves must be unique BPF programs. > * Reset hook: This detaches all bpf programs asssociated with a hook. > * Deny Reset: This locks a hook, preventing reset. In production > operation, it's expected that the user would lock > their hooks. > > Signed-off-by: Sargun Dhillon <sargun@sargun.me> > --- > include/linux/checmate.h | 38 +++++ > include/uapi/linux/Kbuild | 1 + > include/uapi/linux/bpf.h | 1 + > include/uapi/linux/checmate.h | 65 +++++++++ > include/uapi/linux/prctl.h | 3 + > security/Kconfig | 1 + > security/Makefile | 2 + > security/checmate/Kconfig | 6 + > security/checmate/Makefile | 3 + > security/checmate/checmate_bpf.c | 67 +++++++++ > security/checmate/checmate_lsm.c | 304 +++++++++++++++++++++++++++++++++++++++ > 11 files changed, 491 insertions(+) > create mode 100644 include/linux/checmate.h > create mode 100644 include/uapi/linux/checmate.h > create mode 100644 security/checmate/Kconfig > create mode 100644 security/checmate/Makefile > create mode 100644 security/checmate/checmate_bpf.c > create mode 100644 security/checmate/checmate_lsm.c > > diff --git a/include/linux/checmate.h b/include/linux/checmate.h > new file mode 100644 > index 0000000..3e492b0 > --- /dev/null > +++ b/include/linux/checmate.h > @@ -0,0 +1,38 @@ > +#ifndef _LINUX_CHECMATE_H_ > +#define _LINUX_CHECMATE_H_ 1 > +#include <uapi/linux/checmate.h> > +#include <linux/security.h> > + > +/* Miscellanious contexts */ > +struct checmate_file_open_ctx { > + struct file *file; > + const struct cred *cred; > +}; > + > +struct checmate_task_create_ctx { > + unsigned long clone_flags; > +}; > + > +struct checmate_task_free_ctx { > + struct task_struct *task; > +}; > + > +struct checmate_socket_connect_ctx { > + struct socket *sock; > + struct sockaddr *address; > + int addrlen; > +}; > + > +struct checmate_ctx { > + int hook; > + union { > + /* Miscellanious contexts */ > + struct checmate_file_open_ctx file_open_ctx; > + struct checmate_task_create_ctx task_create_ctx; > + struct checmate_task_free_ctx task_free_ctx; > + /* CONFIG_SECURITY_NET contexts */ > + struct checmate_socket_connect_ctx socket_connect_ctx; > + }; > +}; > + > +#endif > diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild > index ec10cfe..f8670a7 100644 > --- a/include/uapi/linux/Kbuild > +++ b/include/uapi/linux/Kbuild > @@ -82,6 +82,7 @@ header-y += cciss_defs.h > header-y += cciss_ioctl.h > header-y += cdrom.h > header-y += cgroupstats.h > +header-y += checmate.h > header-y += chio.h > header-y += cm4000_cs.h > header-y += cn_proc.h > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index da218fe..6cafb58 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -95,6 +95,7 @@ enum bpf_prog_type { > BPF_PROG_TYPE_SCHED_ACT, > BPF_PROG_TYPE_TRACEPOINT, > BPF_PROG_TYPE_XDP, > + BPF_PROG_TYPE_CHECMATE, > }; > > #define BPF_PSEUDO_MAP_FD 1 > diff --git a/include/uapi/linux/checmate.h b/include/uapi/linux/checmate.h > new file mode 100644 > index 0000000..18af381 > --- /dev/null > +++ b/include/uapi/linux/checmate.h > @@ -0,0 +1,65 @@ > +#ifndef _UAPI__LINUX_CHECMATE_H__ > +#define _UAPI__LINUX_CHECMATE_H__ > + > +#define CHECMATE_INSTALL_HOOK 1 > +#define CHECMATE_DENY_RESET 2 > +#define CHECMATE_RESET 3 > + > +enum checmate_hook { > + CHECMATE_HOOK_UNSPEC, > + /* CONFIG_SECURITY_NET hooks */ > + CHECMATE_HOOK_UNIX_STREAM_CONNECT, > + CHECMATE_HOOK_UNIX_MAY_SEND, > + CHECMATE_HOOK_SOCKET_CREATE, > + CHECMATE_HOOK_SOCKET_POST_CREATE, > + CHECMATE_HOOK_SOCKET_BIND, > + CHECMATE_HOOK_SOCKET_CONNECT, > + CHECMATE_HOOK_SOCKET_LISTEN, > + CHECMATE_HOOK_SOCKET_ACCEPT, > + CHECMATE_HOOK_SOCKET_SENDMSG, > + CHECMATE_HOOK_SOCKET_RECVMSG, > + CHECMATE_HOOK_SOCKET_GETSOCKNAME, > + CHECMATE_HOOK_SOCKET_GETPEERNAME, > + CHECMATE_HOOK_SOCKET_GETSOCKOPT, > + CHECMATE_HOOK_SOCKET_SETSOCKOPT, > + CHECMATE_HOOK_SOCKET_SHUTDOWN, > + CHECMATE_HOOK_SOCKET_SOCK_RCV_SKB, > + CHECMATE_HOOK_SOCKET_GETPEERSEC_STREAM, > + CHECMATE_HOOK_SOCKET_GETPEERSEC_DGRAM, > + CHECMATE_HOOK_SK_ALLOC_SECURITY, > + CHECMATE_HOOK_SK_FREE_SECURITY, > + CHECMATE_HOOK_SK_CLONE_SECURITY, > + CHECMATE_HOOK_SK_GETSECID, > + CHECMATE_HOOK_SOCK_GRAFT, > + CHECMATE_HOOK_INET_CONN_REQUEST, > + CHECMATE_HOOK_INET_CSK_CLONE, > + CHECMATE_HOOK_INET_CONN_ESTABLISHED, > + CHECMATE_HOOK_SECMARK_RELABEL_PACKET, > + CHECMATE_HOOK_SECMARK_REFCOUNT_INC, > + CHECMATE_HOOK_SECMARK_REFCOUNT_DEC, > + CHECMATE_HOOK_REQ_CLASSIFY_FLOW, > + CHECMATE_HOOK_TUN_DEV_ALLOC_SECURITY, > + CHECMATE_HOOK_TUN_DEV_FREE_SECURITY, > + CHECMATE_HOOK_TUN_DEV_CREATE, > + CHECMATE_HOOK_TUN_DEV_ATTACH_QUEUE, > + CHECMATE_HOOK_TUN_DEV_ATTACH, > + CHECMATE_HOOK_TUN_DEV_OPEN, > + /* CONFIG_SECURITY_PATH hooks */ > + CHECMATE_HOOK_PATH_UNLINK, > + CHECMATE_HOOK_PATH_MKDIR, > + CHECMATE_HOOK_PATH_RMDIR, > + CHECMATE_HOOK_PATH_MKNOD, > + CHECMATE_HOOK_PATH_TRUNCATE, > + CHECMATE_HOOK_PATH_SYMLINK, > + CHECMATE_HOOK_PATH_LINK, > + CHECMATE_HOOK_PATH_RENAME, > + CHECMATE_HOOK_PATH_CHMOD, > + CHECMATE_HOOK_PATH_CHOWN, > + CHECMATE_HOOK_PATH_CHROOT, > + /* Other hooks */ > + CHECMATE_HOOK_FILE_OPEN, > + CHECMATE_HOOK_TASK_CREATE, > + CHECMATE_HOOK_TASK_FREE, > + __CHECMATE_HOOK_MAX, > +}; > +#endif > diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h > index a8d0759..f520d1e 100644 > --- a/include/uapi/linux/prctl.h > +++ b/include/uapi/linux/prctl.h > @@ -197,4 +197,7 @@ struct prctl_mm_map { > # define PR_CAP_AMBIENT_LOWER 3 > # define PR_CAP_AMBIENT_CLEAR_ALL 4 > > +/* (CHEC)MATE operations */ > +#define PR_CHECMATE 0x43484543 > + > #endif /* _LINUX_PRCTL_H */ > diff --git a/security/Kconfig b/security/Kconfig > index 176758c..36cafc7 100644 > --- a/security/Kconfig > +++ b/security/Kconfig > @@ -124,6 +124,7 @@ source security/tomoyo/Kconfig > source security/apparmor/Kconfig > source security/loadpin/Kconfig > source security/yama/Kconfig > +source security/checmate/Kconfig > > source security/integrity/Kconfig > > diff --git a/security/Makefile b/security/Makefile > index f2d71cd..6cc3342 100644 > --- a/security/Makefile > +++ b/security/Makefile > @@ -8,6 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack > subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo > subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor > subdir-$(CONFIG_SECURITY_YAMA) += yama > +subdir-$(CONFIG_SECURITY_CHECMATE) += checmate > subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin > > # always enable default capabilities > @@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ > obj-$(CONFIG_SECURITY_YAMA) += yama/ > obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ > obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o > +obj-$(CONFIG_SECURITY_CHECMATE) += checmate/ > > # Object integrity file lists > subdir-$(CONFIG_INTEGRITY) += integrity > diff --git a/security/checmate/Kconfig b/security/checmate/Kconfig > new file mode 100644 > index 0000000..6a5c3f3 > --- /dev/null > +++ b/security/checmate/Kconfig > @@ -0,0 +1,6 @@ > +config SECURITY_CHECMATE > + bool "Checmate support" > + depends on SECURITY > + default n > + help > + This turns on checmate > diff --git a/security/checmate/Makefile b/security/checmate/Makefile > new file mode 100644 > index 0000000..c676773 > --- /dev/null > +++ b/security/checmate/Makefile > @@ -0,0 +1,3 @@ > +obj-$(CONFIG_SECURITY_CHECMATE) := checmate.o > + > +checmate-y := checmate_bpf.o checmate_lsm.o > diff --git a/security/checmate/checmate_bpf.c b/security/checmate/checmate_bpf.c > new file mode 100644 > index 0000000..5bf1a8e > --- /dev/null > +++ b/security/checmate/checmate_bpf.c > @@ -0,0 +1,67 @@ > +/* > + * Checmate Linux Security Module > + * > + * Copyright (C) 2016 Sargun Dhillon <sargun@sargun.me> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2, as > + * published by the Free Software Foundation. > + * > + */ > + > +#include <linux/bpf.h> > +#include <linux/checmate.h> > + > +static const struct bpf_func_proto *checmate_prog_func_proto(enum bpf_func_id func_id) > +{ > + switch (func_id) { > + case BPF_FUNC_map_lookup_elem: > + return &bpf_map_lookup_elem_proto; > + case BPF_FUNC_map_update_elem: > + return &bpf_map_update_elem_proto; > + case BPF_FUNC_map_delete_elem: > + return &bpf_map_delete_elem_proto; > + case BPF_FUNC_probe_read: > + return &bpf_probe_read_proto; > + case BPF_FUNC_tail_call: > + return &bpf_tail_call_proto; > + case BPF_FUNC_get_current_pid_tgid: > + return &bpf_get_current_pid_tgid_proto; > + case BPF_FUNC_get_current_task: > + return &bpf_get_current_task_proto; > + case BPF_FUNC_get_current_uid_gid: > + return &bpf_get_current_uid_gid_proto; > + case BPF_FUNC_get_current_comm: > + return &bpf_get_current_comm_proto; > + case BPF_FUNC_trace_printk: > + return bpf_get_trace_printk_proto(); > + default: > + return NULL; > + } > +} > + > +static bool checmate_prog_is_valid_access(int off, int size, > + enum bpf_access_type type, > + enum bpf_reg_type *reg_type) > +{ > + if (type != BPF_READ) > + return false; > + if (off < 0 || off >= sizeof(struct checmate_ctx)) > + return false; > + return true; > +} > + > +static const struct bpf_verifier_ops checmate_prog_ops = { > + .get_func_proto = checmate_prog_func_proto, > + .is_valid_access = checmate_prog_is_valid_access, > +}; > + > +static struct bpf_prog_type_list checmate_tl = { > + .ops = &checmate_prog_ops, > + .type = BPF_PROG_TYPE_CHECMATE, > +}; > + > +void register_checmate_prog_ops(void) > +{ > + bpf_register_prog_type(&checmate_tl); > +} > diff --git a/security/checmate/checmate_lsm.c b/security/checmate/checmate_lsm.c > new file mode 100644 > index 0000000..ba403e5 > --- /dev/null > +++ b/security/checmate/checmate_lsm.c > @@ -0,0 +1,304 @@ > +/* > + * Checmate Linux Security Module > + * > + * Copyright (C) 2016 Sargun Dhillon <sargun@sargun.me> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2, as > + * published by the Free Software Foundation. > + * > + */ > + > +#include <linux/prctl.h> > +#include <linux/checmate.h> > +#include <linux/lsm_hooks.h> > +#include <linux/mutex.h> > +#include <linux/bpf.h> > +#include <linux/filter.h> > + > +#define HOOK_LIST_INIT(HOOK_NUM) \ > + LIST_HEAD_INIT(checmate_bpf_hooks[HOOK_NUM].hook_list) > + > +#define CHECMATE_HOOK(HOOK_NUM) \ > + [HOOK_NUM] = \ > + { \ > + .enabled = true, \ > + .hook_list = HOOK_LIST_INIT(HOOK_NUM), \ > + } > + > +void register_checmate_prog_ops(void); > + > +/* > + * Global write lock for all BPF program hook manipulation. This shouldn't > + * see much contention, as installation / reset / deny_reset are rare > + * operations. > + */ > +static DEFINE_MUTEX(checmate_write_lock); > + > +struct checmate_bpf_hook { > + bool enabled; > + bool deny_reset; > + struct list_head hook_list; > +}; > + > +struct checmate_bpf_hook_instance { > + struct list_head list; > + struct bpf_prog *prog; > +}; > + > +/* This is the internal array of the heads of BPF hooks */ > +static struct checmate_bpf_hook checmate_bpf_hooks[__CHECMATE_HOOK_MAX] = { > + CHECMATE_HOOK(CHECMATE_HOOK_FILE_OPEN), > + CHECMATE_HOOK(CHECMATE_HOOK_TASK_CREATE), > + CHECMATE_HOOK(CHECMATE_HOOK_TASK_FREE), > +#ifdef CONFIG_SECURITY_NETWORK > + CHECMATE_HOOK(CHECMATE_HOOK_SOCKET_CONNECT), > +#endif /* CONFIG_SECURITY_NETWORK */ > +}; > + > +/* > + * checmate_task_prctl_install_hook - Install a checmate hook > + * @hook: Hook ID > + * @prog_fd: BPF prog fd > + * > + * Return 0 on success, return -ve on error > + */ > +static int checmate_prctl_install_hook(int hook, int prog_fd) > +{ > + int rc = 0; > + struct bpf_prog *prog; > + struct checmate_bpf_hook_instance *hook_instance; > + > + prog = bpf_prog_get_type(prog_fd, BPF_PROG_TYPE_CHECMATE); > + if (IS_ERR(prog)) > + return PTR_ERR(prog); > + > + mutex_lock(&checmate_write_lock); > + list_for_each_entry(hook_instance, > + &checmate_bpf_hooks[hook].hook_list, list) { > + if (hook_instance->prog == prog) { > + rc = -EEXIST; > + goto err; > + } > + } > + hook_instance = kmalloc(sizeof(*hook_instance), GFP_KERNEL); > + > + if (!hook_instance) { > + rc = -ENOMEM; > + goto err; > + } > + hook_instance->prog = prog; > + list_add_tail_rcu(&hook_instance->list, > + &checmate_bpf_hooks[hook].hook_list); > + mutex_unlock(&checmate_write_lock); > + return rc; > + > +err: > + mutex_unlock(&checmate_write_lock); > + bpf_prog_put(prog); > + return rc; > +} > + > +/* > + * checmate_prctl_deny_reset - Set deny bit on hook > + * @hook: The Hook ID > + * > + * Return 0 or -EALREADY on success, to indicate the deny bit was set > + */ > +static int checmate_prctl_deny_reset(int hook) > +{ > + int rc = 0; > + > + mutex_lock(&checmate_write_lock); > + if (checmate_bpf_hooks[hook].deny_reset) > + rc = -EALREADY; > + else > + checmate_bpf_hooks[hook].deny_reset = true; > + mutex_unlock(&checmate_write_lock); > + > + return rc; > +} > + > +/* > + * checmate_reset - Reset (disassociate) the BPF programs for a checmate hook > + * @hook: Hook ID > + * > + * Return 0 on success, -ve on error. > + */ > +static int checmate_reset(int hook) > +{ > + int rc = 0; > + struct checmate_bpf_hook_instance *hook_instance, *next; > + > + mutex_lock(&checmate_write_lock); > + if (checmate_bpf_hooks[hook].deny_reset) { > + rc = -EPERM; > + goto out; > + } > + list_for_each_entry_safe(hook_instance, next, > + &checmate_bpf_hooks[hook].hook_list, list) { > + list_del_rcu(&hook_instance->list); > + synchronize_rcu(); > + bpf_prog_put(hook_instance->prog); > + kfree(hook_instance); > + } > +out: > + mutex_unlock(&checmate_write_lock); > + return rc; > +} > + > +/* checmate_task_prctl_op - Run a checmate specific prctl operation > + * @op - Used to specify the Checmate operation ID > + * @hook - Hook ID > + * @ufd - BPF Program user file descriptor > + * @arg5 - Unused > + * > + * Return 0 on success, -ve on error. -EINVAL when option unhandled. > + */ > + > +static int checmate_task_prctl_op(unsigned long op, unsigned long hook, > + unsigned long ufd, unsigned long arg5) > +{ > + if (!capable(CAP_SYS_ADMIN)) > + return -EPERM; > + if (!(hook > 0 && hook < __CHECMATE_HOOK_MAX)) > + return -EINVAL; > + if (!checmate_bpf_hooks[hook].enabled) > + return -ENOENT; > + > + if (op == CHECMATE_INSTALL_HOOK) > + return checmate_prctl_install_hook(hook, ufd); > + else if (op == CHECMATE_DENY_RESET) > + return checmate_prctl_deny_reset(hook); > + else if (op == CHECMATE_RESET) > + return checmate_reset(hook); > + > + return -EINVAL; > +} > + > +/* > + * checmate_task_prctl - check for Checmate-specific prctl operations > + * @option: If PR_CHECMATE, passes to handler > + * @arg2: > + * @arg3: > + * @arg4: > + * @arg5: > + * > + * Return 0 on success, -ve on error. -ENOSYS is returned when checmate > + * does not handle the given option. > + */ > +static int checmate_task_prctl(int option, unsigned long arg2, > + unsigned long arg3, unsigned long arg4, > + unsigned long arg5) > +{ > + if (option == PR_CHECMATE) > + return checmate_task_prctl_op(arg2, arg3, arg4, arg5); > + return -ENOSYS; > +} > + > +/* > + * call_bpf_int_hook - Run all the BPF programs associated with a hook > + * @hook: The Hook ID > + * @ctx: The context which is passed to the hook > + * > + * Return 0 on success, on first hook erroring, the error is returned > + * to the caller > + * > + * Requires that the context struct is populated before passing, but > + * the actual ctx->hook is set inside this function > + */ > +static int call_bpf_int_hook(int hook, struct checmate_ctx *ctx) > +{ > + int rc = 0; > + struct checmate_bpf_hook_instance *hook_instance; > + > + ctx->hook = hook; > + > + preempt_disable(); > + rcu_read_lock(); > + list_for_each_entry_rcu(hook_instance, > + &checmate_bpf_hooks[hook].hook_list, list) { > + rc = BPF_PROG_RUN(hook_instance->prog, (void *)ctx); > + if (rc != 0) > + goto out; > + } > +out: > + rcu_read_unlock(); > + preempt_enable(); > + return rc; > +} > + > +/* > + * call_bpf_void_hook - Run all the BPF programs associated with a hook > + * @hook: The Hook ID > + * @ctx: The context which is passed to the hook > + * > + * Return 0 on success, on first hook erroring, the error is returned > + * to the caller > + * > + * Requires that the context struct is populated before passing, but > + * the actual ctx->hook is set inside this function > + */ > +static void call_bpf_void_hook(int hook, struct checmate_ctx *ctx) > +{ > + call_bpf_int_hook(hook, ctx); > +} > + > +/* Checmate hooks */ > +static int checmate_file_open(struct file *file, const struct cred *cred) > +{ > + struct checmate_ctx ctx; > + > + ctx.file_open_ctx.file = file; > + ctx.file_open_ctx.cred = cred; > + return call_bpf_int_hook(CHECMATE_HOOK_FILE_OPEN, &ctx); > +} > + > +static int checmate_task_create(unsigned long clone_flags) > +{ > + struct checmate_ctx ctx; > + > + ctx.task_create_ctx.clone_flags = clone_flags; > + return call_bpf_int_hook(CHECMATE_HOOK_TASK_CREATE, &ctx); > +} > + > +static void checmate_task_free(struct task_struct *task) > +{ > + struct checmate_ctx ctx; > + > + ctx.task_free_ctx.task = task; > + call_bpf_void_hook(CHECMATE_HOOK_TASK_FREE, &ctx); > +} > + > +#ifdef CONFIG_SECURITY_NETWORK > +static int checmate_socket_connect(struct socket *sock, > + struct sockaddr *address, int addrlen) > +{ > + struct checmate_ctx ctx; > + > + ctx.socket_connect_ctx.sock = sock; > + ctx.socket_connect_ctx.address = address; > + ctx.socket_connect_ctx.addrlen = addrlen; > + return call_bpf_int_hook(CHECMATE_HOOK_SOCKET_CONNECT, &ctx); > +} > + > +#endif /* CONFIG_SECURITY_NETWORK */ > + > +static struct security_hook_list checmate_hooks[] = { > + LSM_HOOK_INIT(task_prctl, checmate_task_prctl), > + LSM_HOOK_INIT(file_open, checmate_file_open), > + LSM_HOOK_INIT(task_create, checmate_task_create), > + LSM_HOOK_INIT(task_free, checmate_task_free), > +#ifdef CONFIG_SECURITY_NETWORK > + LSM_HOOK_INIT(socket_connect, checmate_socket_connect), > +#endif /* CONFIG_SECURITY_NETWORK */ > +}; > + > +static int __init checmate_setup(void) > +{ > + pr_info("Checmate activating.\n"); > + register_checmate_prog_ops(); > + security_add_hooks(checmate_hooks, ARRAY_SIZE(checmate_hooks)); > + return 0; > +} > +late_initcall(checmate_setup); > -- > 2.7.4 > -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Please do not top post On Thu, 2016-08-04 at 16:08 +0800, zhuyj wrote: > +void register_checmate_prog_ops(void); > maybe it is extern void register_checmate_prog_ops(void);? > > + preempt_disable(); > + rcu_read_lock(); > IMHO, it is not necessary to use the above 2 since rcu_read_lock will > call preempt_disable. You might double check if this claim is true if CONFIG_PREEMPT_RCU=y -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Sure. Is it better to add #ifndef CONFIG_PREEMPT_RCU ? On Thu, Aug 4, 2016 at 4:28 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote: > Please do not top post > > On Thu, 2016-08-04 at 16:08 +0800, zhuyj wrote: >> +void register_checmate_prog_ops(void); >> maybe it is extern void register_checmate_prog_ops(void);? >> >> + preempt_disable(); >> + rcu_read_lock(); >> IMHO, it is not necessary to use the above 2 since rcu_read_lock will >> call preempt_disable. > > You might double check if this claim is true if CONFIG_PREEMPT_RCU=y > > > -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Aug 04, 2016 at 05:34:32PM +0800, zhuyj wrote: > Sure. > Is it better to add > #ifndef CONFIG_PREEMPT_RCU ? > > On Thu, Aug 4, 2016 at 4:28 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote: > > Please do not top post > > > > On Thu, 2016-08-04 at 16:08 +0800, zhuyj wrote: > >> +void register_checmate_prog_ops(void); > >> maybe it is extern void register_checmate_prog_ops(void);? > >> > >> + preempt_disable(); > >> + rcu_read_lock(); > >> IMHO, it is not necessary to use the above 2 since rcu_read_lock will > >> call preempt_disable. > > > > You might double check if this claim is true if CONFIG_PREEMPT_RCU=y > > > > > > Thanks for your feedback zhuyj, Looking at kernel documentation itself, it looks like this is the preferred mechanism[1]. Their example: 1 preempt_disable(); 2 rcu_read_lock(); 3 do_something(); 4 rcu_read_unlock(); 5 preempt_enable(); But, I think you're right. Do you know if there's a great benefit of doing this? Or does it make sense to implement a new macro, a la rcu_read_lock_and_preent_disable()? [1] https://www.kernel.org/doc/Documentation/RCU/Design/Requirements/Requirements.html#Disabling Preemption Does Not Block Grace Periods -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Sure. Why are preempt_disable and rcu_read_lock used here? is there a great benefit of dong this? On Fri, Aug 5, 2016 at 3:05 PM, Sargun Dhillon <sargun@sargun.me> wrote: > On Thu, Aug 04, 2016 at 05:34:32PM +0800, zhuyj wrote: >> Sure. >> Is it better to add >> #ifndef CONFIG_PREEMPT_RCU ? >> >> On Thu, Aug 4, 2016 at 4:28 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote: >> > Please do not top post >> > >> > On Thu, 2016-08-04 at 16:08 +0800, zhuyj wrote: >> >> +void register_checmate_prog_ops(void); >> >> maybe it is extern void register_checmate_prog_ops(void);? >> >> >> >> + preempt_disable(); >> >> + rcu_read_lock(); >> >> IMHO, it is not necessary to use the above 2 since rcu_read_lock will >> >> call preempt_disable. >> > >> > You might double check if this claim is true if CONFIG_PREEMPT_RCU=y >> > >> > >> > > Thanks for your feedback zhuyj, Looking at kernel documentation itself, it looks > like this is the preferred mechanism[1]. Their example: > > 1 preempt_disable(); > 2 rcu_read_lock(); > 3 do_something(); > 4 rcu_read_unlock(); > 5 preempt_enable(); > > But, I think you're right. Do you know if there's a great benefit of doing this? > Or does it make sense to implement a new macro, a la > rcu_read_lock_and_preent_disable()? > > [1] https://www.kernel.org/doc/Documentation/RCU/Design/Requirements/Requirements.html#Disabling Preemption Does Not Block Grace Periods -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/include/linux/checmate.h b/include/linux/checmate.h new file mode 100644 index 0000000..3e492b0 --- /dev/null +++ b/include/linux/checmate.h @@ -0,0 +1,38 @@ +#ifndef _LINUX_CHECMATE_H_ +#define _LINUX_CHECMATE_H_ 1 +#include <uapi/linux/checmate.h> +#include <linux/security.h> + +/* Miscellanious contexts */ +struct checmate_file_open_ctx { + struct file *file; + const struct cred *cred; +}; + +struct checmate_task_create_ctx { + unsigned long clone_flags; +}; + +struct checmate_task_free_ctx { + struct task_struct *task; +}; + +struct checmate_socket_connect_ctx { + struct socket *sock; + struct sockaddr *address; + int addrlen; +}; + +struct checmate_ctx { + int hook; + union { + /* Miscellanious contexts */ + struct checmate_file_open_ctx file_open_ctx; + struct checmate_task_create_ctx task_create_ctx; + struct checmate_task_free_ctx task_free_ctx; + /* CONFIG_SECURITY_NET contexts */ + struct checmate_socket_connect_ctx socket_connect_ctx; + }; +}; + +#endif diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index ec10cfe..f8670a7 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -82,6 +82,7 @@ header-y += cciss_defs.h header-y += cciss_ioctl.h header-y += cdrom.h header-y += cgroupstats.h +header-y += checmate.h header-y += chio.h header-y += cm4000_cs.h header-y += cn_proc.h diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index da218fe..6cafb58 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -95,6 +95,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_TRACEPOINT, BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_CHECMATE, }; #define BPF_PSEUDO_MAP_FD 1 diff --git a/include/uapi/linux/checmate.h b/include/uapi/linux/checmate.h new file mode 100644 index 0000000..18af381 --- /dev/null +++ b/include/uapi/linux/checmate.h @@ -0,0 +1,65 @@ +#ifndef _UAPI__LINUX_CHECMATE_H__ +#define _UAPI__LINUX_CHECMATE_H__ + +#define CHECMATE_INSTALL_HOOK 1 +#define CHECMATE_DENY_RESET 2 +#define CHECMATE_RESET 3 + +enum checmate_hook { + CHECMATE_HOOK_UNSPEC, + /* CONFIG_SECURITY_NET hooks */ + CHECMATE_HOOK_UNIX_STREAM_CONNECT, + CHECMATE_HOOK_UNIX_MAY_SEND, + CHECMATE_HOOK_SOCKET_CREATE, + CHECMATE_HOOK_SOCKET_POST_CREATE, + CHECMATE_HOOK_SOCKET_BIND, + CHECMATE_HOOK_SOCKET_CONNECT, + CHECMATE_HOOK_SOCKET_LISTEN, + CHECMATE_HOOK_SOCKET_ACCEPT, + CHECMATE_HOOK_SOCKET_SENDMSG, + CHECMATE_HOOK_SOCKET_RECVMSG, + CHECMATE_HOOK_SOCKET_GETSOCKNAME, + CHECMATE_HOOK_SOCKET_GETPEERNAME, + CHECMATE_HOOK_SOCKET_GETSOCKOPT, + CHECMATE_HOOK_SOCKET_SETSOCKOPT, + CHECMATE_HOOK_SOCKET_SHUTDOWN, + CHECMATE_HOOK_SOCKET_SOCK_RCV_SKB, + CHECMATE_HOOK_SOCKET_GETPEERSEC_STREAM, + CHECMATE_HOOK_SOCKET_GETPEERSEC_DGRAM, + CHECMATE_HOOK_SK_ALLOC_SECURITY, + CHECMATE_HOOK_SK_FREE_SECURITY, + CHECMATE_HOOK_SK_CLONE_SECURITY, + CHECMATE_HOOK_SK_GETSECID, + CHECMATE_HOOK_SOCK_GRAFT, + CHECMATE_HOOK_INET_CONN_REQUEST, + CHECMATE_HOOK_INET_CSK_CLONE, + CHECMATE_HOOK_INET_CONN_ESTABLISHED, + CHECMATE_HOOK_SECMARK_RELABEL_PACKET, + CHECMATE_HOOK_SECMARK_REFCOUNT_INC, + CHECMATE_HOOK_SECMARK_REFCOUNT_DEC, + CHECMATE_HOOK_REQ_CLASSIFY_FLOW, + CHECMATE_HOOK_TUN_DEV_ALLOC_SECURITY, + CHECMATE_HOOK_TUN_DEV_FREE_SECURITY, + CHECMATE_HOOK_TUN_DEV_CREATE, + CHECMATE_HOOK_TUN_DEV_ATTACH_QUEUE, + CHECMATE_HOOK_TUN_DEV_ATTACH, + CHECMATE_HOOK_TUN_DEV_OPEN, + /* CONFIG_SECURITY_PATH hooks */ + CHECMATE_HOOK_PATH_UNLINK, + CHECMATE_HOOK_PATH_MKDIR, + CHECMATE_HOOK_PATH_RMDIR, + CHECMATE_HOOK_PATH_MKNOD, + CHECMATE_HOOK_PATH_TRUNCATE, + CHECMATE_HOOK_PATH_SYMLINK, + CHECMATE_HOOK_PATH_LINK, + CHECMATE_HOOK_PATH_RENAME, + CHECMATE_HOOK_PATH_CHMOD, + CHECMATE_HOOK_PATH_CHOWN, + CHECMATE_HOOK_PATH_CHROOT, + /* Other hooks */ + CHECMATE_HOOK_FILE_OPEN, + CHECMATE_HOOK_TASK_CREATE, + CHECMATE_HOOK_TASK_FREE, + __CHECMATE_HOOK_MAX, +}; +#endif diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index a8d0759..f520d1e 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -197,4 +197,7 @@ struct prctl_mm_map { # define PR_CAP_AMBIENT_LOWER 3 # define PR_CAP_AMBIENT_CLEAR_ALL 4 +/* (CHEC)MATE operations */ +#define PR_CHECMATE 0x43484543 + #endif /* _LINUX_PRCTL_H */ diff --git a/security/Kconfig b/security/Kconfig index 176758c..36cafc7 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -124,6 +124,7 @@ source security/tomoyo/Kconfig source security/apparmor/Kconfig source security/loadpin/Kconfig source security/yama/Kconfig +source security/checmate/Kconfig source security/integrity/Kconfig diff --git a/security/Makefile b/security/Makefile index f2d71cd..6cc3342 100644 --- a/security/Makefile +++ b/security/Makefile @@ -8,6 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama +subdir-$(CONFIG_SECURITY_CHECMATE) += checmate subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin # always enable default capabilities @@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o +obj-$(CONFIG_SECURITY_CHECMATE) += checmate/ # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity diff --git a/security/checmate/Kconfig b/security/checmate/Kconfig new file mode 100644 index 0000000..6a5c3f3 --- /dev/null +++ b/security/checmate/Kconfig @@ -0,0 +1,6 @@ +config SECURITY_CHECMATE + bool "Checmate support" + depends on SECURITY + default n + help + This turns on checmate diff --git a/security/checmate/Makefile b/security/checmate/Makefile new file mode 100644 index 0000000..c676773 --- /dev/null +++ b/security/checmate/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_SECURITY_CHECMATE) := checmate.o + +checmate-y := checmate_bpf.o checmate_lsm.o diff --git a/security/checmate/checmate_bpf.c b/security/checmate/checmate_bpf.c new file mode 100644 index 0000000..5bf1a8e --- /dev/null +++ b/security/checmate/checmate_bpf.c @@ -0,0 +1,67 @@ +/* + * Checmate Linux Security Module + * + * Copyright (C) 2016 Sargun Dhillon <sargun@sargun.me> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include <linux/bpf.h> +#include <linux/checmate.h> + +static const struct bpf_func_proto *checmate_prog_func_proto(enum bpf_func_id func_id) +{ + switch (func_id) { + case BPF_FUNC_map_lookup_elem: + return &bpf_map_lookup_elem_proto; + case BPF_FUNC_map_update_elem: + return &bpf_map_update_elem_proto; + case BPF_FUNC_map_delete_elem: + return &bpf_map_delete_elem_proto; + case BPF_FUNC_probe_read: + return &bpf_probe_read_proto; + case BPF_FUNC_tail_call: + return &bpf_tail_call_proto; + case BPF_FUNC_get_current_pid_tgid: + return &bpf_get_current_pid_tgid_proto; + case BPF_FUNC_get_current_task: + return &bpf_get_current_task_proto; + case BPF_FUNC_get_current_uid_gid: + return &bpf_get_current_uid_gid_proto; + case BPF_FUNC_get_current_comm: + return &bpf_get_current_comm_proto; + case BPF_FUNC_trace_printk: + return bpf_get_trace_printk_proto(); + default: + return NULL; + } +} + +static bool checmate_prog_is_valid_access(int off, int size, + enum bpf_access_type type, + enum bpf_reg_type *reg_type) +{ + if (type != BPF_READ) + return false; + if (off < 0 || off >= sizeof(struct checmate_ctx)) + return false; + return true; +} + +static const struct bpf_verifier_ops checmate_prog_ops = { + .get_func_proto = checmate_prog_func_proto, + .is_valid_access = checmate_prog_is_valid_access, +}; + +static struct bpf_prog_type_list checmate_tl = { + .ops = &checmate_prog_ops, + .type = BPF_PROG_TYPE_CHECMATE, +}; + +void register_checmate_prog_ops(void) +{ + bpf_register_prog_type(&checmate_tl); +} diff --git a/security/checmate/checmate_lsm.c b/security/checmate/checmate_lsm.c new file mode 100644 index 0000000..ba403e5 --- /dev/null +++ b/security/checmate/checmate_lsm.c @@ -0,0 +1,304 @@ +/* + * Checmate Linux Security Module + * + * Copyright (C) 2016 Sargun Dhillon <sargun@sargun.me> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include <linux/prctl.h> +#include <linux/checmate.h> +#include <linux/lsm_hooks.h> +#include <linux/mutex.h> +#include <linux/bpf.h> +#include <linux/filter.h> + +#define HOOK_LIST_INIT(HOOK_NUM) \ + LIST_HEAD_INIT(checmate_bpf_hooks[HOOK_NUM].hook_list) + +#define CHECMATE_HOOK(HOOK_NUM) \ + [HOOK_NUM] = \ + { \ + .enabled = true, \ + .hook_list = HOOK_LIST_INIT(HOOK_NUM), \ + } + +void register_checmate_prog_ops(void); + +/* + * Global write lock for all BPF program hook manipulation. This shouldn't + * see much contention, as installation / reset / deny_reset are rare + * operations. + */ +static DEFINE_MUTEX(checmate_write_lock); + +struct checmate_bpf_hook { + bool enabled; + bool deny_reset; + struct list_head hook_list; +}; + +struct checmate_bpf_hook_instance { + struct list_head list; + struct bpf_prog *prog; +}; + +/* This is the internal array of the heads of BPF hooks */ +static struct checmate_bpf_hook checmate_bpf_hooks[__CHECMATE_HOOK_MAX] = { + CHECMATE_HOOK(CHECMATE_HOOK_FILE_OPEN), + CHECMATE_HOOK(CHECMATE_HOOK_TASK_CREATE), + CHECMATE_HOOK(CHECMATE_HOOK_TASK_FREE), +#ifdef CONFIG_SECURITY_NETWORK + CHECMATE_HOOK(CHECMATE_HOOK_SOCKET_CONNECT), +#endif /* CONFIG_SECURITY_NETWORK */ +}; + +/* + * checmate_task_prctl_install_hook - Install a checmate hook + * @hook: Hook ID + * @prog_fd: BPF prog fd + * + * Return 0 on success, return -ve on error + */ +static int checmate_prctl_install_hook(int hook, int prog_fd) +{ + int rc = 0; + struct bpf_prog *prog; + struct checmate_bpf_hook_instance *hook_instance; + + prog = bpf_prog_get_type(prog_fd, BPF_PROG_TYPE_CHECMATE); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + mutex_lock(&checmate_write_lock); + list_for_each_entry(hook_instance, + &checmate_bpf_hooks[hook].hook_list, list) { + if (hook_instance->prog == prog) { + rc = -EEXIST; + goto err; + } + } + hook_instance = kmalloc(sizeof(*hook_instance), GFP_KERNEL); + + if (!hook_instance) { + rc = -ENOMEM; + goto err; + } + hook_instance->prog = prog; + list_add_tail_rcu(&hook_instance->list, + &checmate_bpf_hooks[hook].hook_list); + mutex_unlock(&checmate_write_lock); + return rc; + +err: + mutex_unlock(&checmate_write_lock); + bpf_prog_put(prog); + return rc; +} + +/* + * checmate_prctl_deny_reset - Set deny bit on hook + * @hook: The Hook ID + * + * Return 0 or -EALREADY on success, to indicate the deny bit was set + */ +static int checmate_prctl_deny_reset(int hook) +{ + int rc = 0; + + mutex_lock(&checmate_write_lock); + if (checmate_bpf_hooks[hook].deny_reset) + rc = -EALREADY; + else + checmate_bpf_hooks[hook].deny_reset = true; + mutex_unlock(&checmate_write_lock); + + return rc; +} + +/* + * checmate_reset - Reset (disassociate) the BPF programs for a checmate hook + * @hook: Hook ID + * + * Return 0 on success, -ve on error. + */ +static int checmate_reset(int hook) +{ + int rc = 0; + struct checmate_bpf_hook_instance *hook_instance, *next; + + mutex_lock(&checmate_write_lock); + if (checmate_bpf_hooks[hook].deny_reset) { + rc = -EPERM; + goto out; + } + list_for_each_entry_safe(hook_instance, next, + &checmate_bpf_hooks[hook].hook_list, list) { + list_del_rcu(&hook_instance->list); + synchronize_rcu(); + bpf_prog_put(hook_instance->prog); + kfree(hook_instance); + } +out: + mutex_unlock(&checmate_write_lock); + return rc; +} + +/* checmate_task_prctl_op - Run a checmate specific prctl operation + * @op - Used to specify the Checmate operation ID + * @hook - Hook ID + * @ufd - BPF Program user file descriptor + * @arg5 - Unused + * + * Return 0 on success, -ve on error. -EINVAL when option unhandled. + */ + +static int checmate_task_prctl_op(unsigned long op, unsigned long hook, + unsigned long ufd, unsigned long arg5) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!(hook > 0 && hook < __CHECMATE_HOOK_MAX)) + return -EINVAL; + if (!checmate_bpf_hooks[hook].enabled) + return -ENOENT; + + if (op == CHECMATE_INSTALL_HOOK) + return checmate_prctl_install_hook(hook, ufd); + else if (op == CHECMATE_DENY_RESET) + return checmate_prctl_deny_reset(hook); + else if (op == CHECMATE_RESET) + return checmate_reset(hook); + + return -EINVAL; +} + +/* + * checmate_task_prctl - check for Checmate-specific prctl operations + * @option: If PR_CHECMATE, passes to handler + * @arg2: + * @arg3: + * @arg4: + * @arg5: + * + * Return 0 on success, -ve on error. -ENOSYS is returned when checmate + * does not handle the given option. + */ +static int checmate_task_prctl(int option, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + unsigned long arg5) +{ + if (option == PR_CHECMATE) + return checmate_task_prctl_op(arg2, arg3, arg4, arg5); + return -ENOSYS; +} + +/* + * call_bpf_int_hook - Run all the BPF programs associated with a hook + * @hook: The Hook ID + * @ctx: The context which is passed to the hook + * + * Return 0 on success, on first hook erroring, the error is returned + * to the caller + * + * Requires that the context struct is populated before passing, but + * the actual ctx->hook is set inside this function + */ +static int call_bpf_int_hook(int hook, struct checmate_ctx *ctx) +{ + int rc = 0; + struct checmate_bpf_hook_instance *hook_instance; + + ctx->hook = hook; + + preempt_disable(); + rcu_read_lock(); + list_for_each_entry_rcu(hook_instance, + &checmate_bpf_hooks[hook].hook_list, list) { + rc = BPF_PROG_RUN(hook_instance->prog, (void *)ctx); + if (rc != 0) + goto out; + } +out: + rcu_read_unlock(); + preempt_enable(); + return rc; +} + +/* + * call_bpf_void_hook - Run all the BPF programs associated with a hook + * @hook: The Hook ID + * @ctx: The context which is passed to the hook + * + * Return 0 on success, on first hook erroring, the error is returned + * to the caller + * + * Requires that the context struct is populated before passing, but + * the actual ctx->hook is set inside this function + */ +static void call_bpf_void_hook(int hook, struct checmate_ctx *ctx) +{ + call_bpf_int_hook(hook, ctx); +} + +/* Checmate hooks */ +static int checmate_file_open(struct file *file, const struct cred *cred) +{ + struct checmate_ctx ctx; + + ctx.file_open_ctx.file = file; + ctx.file_open_ctx.cred = cred; + return call_bpf_int_hook(CHECMATE_HOOK_FILE_OPEN, &ctx); +} + +static int checmate_task_create(unsigned long clone_flags) +{ + struct checmate_ctx ctx; + + ctx.task_create_ctx.clone_flags = clone_flags; + return call_bpf_int_hook(CHECMATE_HOOK_TASK_CREATE, &ctx); +} + +static void checmate_task_free(struct task_struct *task) +{ + struct checmate_ctx ctx; + + ctx.task_free_ctx.task = task; + call_bpf_void_hook(CHECMATE_HOOK_TASK_FREE, &ctx); +} + +#ifdef CONFIG_SECURITY_NETWORK +static int checmate_socket_connect(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + struct checmate_ctx ctx; + + ctx.socket_connect_ctx.sock = sock; + ctx.socket_connect_ctx.address = address; + ctx.socket_connect_ctx.addrlen = addrlen; + return call_bpf_int_hook(CHECMATE_HOOK_SOCKET_CONNECT, &ctx); +} + +#endif /* CONFIG_SECURITY_NETWORK */ + +static struct security_hook_list checmate_hooks[] = { + LSM_HOOK_INIT(task_prctl, checmate_task_prctl), + LSM_HOOK_INIT(file_open, checmate_file_open), + LSM_HOOK_INIT(task_create, checmate_task_create), + LSM_HOOK_INIT(task_free, checmate_task_free), +#ifdef CONFIG_SECURITY_NETWORK + LSM_HOOK_INIT(socket_connect, checmate_socket_connect), +#endif /* CONFIG_SECURITY_NETWORK */ +}; + +static int __init checmate_setup(void) +{ + pr_info("Checmate activating.\n"); + register_checmate_prog_ops(); + security_add_hooks(checmate_hooks, ARRAY_SIZE(checmate_hooks)); + return 0; +} +late_initcall(checmate_setup);
This adds the minor LSM Checmate. The purpose of Checmate is to act as an extensible LSM in which you can load security modules. The module has a simple API, as it's meant to have most of the logic in BPF hooks. It has three APIs that are accessible via prctl. As follows: * Install hook: This appends a new BPF program to a given hook. Hook programs themselves must be unique BPF programs. * Reset hook: This detaches all bpf programs asssociated with a hook. * Deny Reset: This locks a hook, preventing reset. In production operation, it's expected that the user would lock their hooks. Signed-off-by: Sargun Dhillon <sargun@sargun.me> --- include/linux/checmate.h | 38 +++++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/bpf.h | 1 + include/uapi/linux/checmate.h | 65 +++++++++ include/uapi/linux/prctl.h | 3 + security/Kconfig | 1 + security/Makefile | 2 + security/checmate/Kconfig | 6 + security/checmate/Makefile | 3 + security/checmate/checmate_bpf.c | 67 +++++++++ security/checmate/checmate_lsm.c | 304 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 491 insertions(+) create mode 100644 include/linux/checmate.h create mode 100644 include/uapi/linux/checmate.h create mode 100644 security/checmate/Kconfig create mode 100644 security/checmate/Makefile create mode 100644 security/checmate/checmate_bpf.c create mode 100644 security/checmate/checmate_lsm.c