All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
@ 2018-03-01  7:38 ` Masanobu Koike
  0 siblings, 0 replies; 10+ messages in thread
From: Masanobu Koike @ 2018-03-01  7:38 UTC (permalink / raw)
  To: jmorris, serge, linux-security-module, linux-kernel; +Cc: Masanobu Koike

This RFC provides implementation of WhiteEgret.

Signed-off-by: Masanobu Koike <masanobu2.koike@toshiba.co.jp>
---
 security/Kconfig                   |   6 +
 security/Makefile                  |   2 +
 security/whiteegret/Kconfig        |  11 ++
 security/whiteegret/Makefile       |   2 +
 security/whiteegret/init.c         |  75 ++++++++++
 security/whiteegret/main.c         | 251 +++++++++++++++++++++++++++++++++
 security/whiteegret/request.c      | 151 ++++++++++++++++++++
 security/whiteegret/request.h      |  52 +++++++
 security/whiteegret/we.h           |  66 +++++++++
 security/whiteegret/we_fs.c        | 280 +++++++++++++++++++++++++++++++++++++
 security/whiteegret/we_fs.h        |  23 +++
 security/whiteegret/we_fs_common.h |  36 +++++
 12 files changed, 955 insertions(+)
 create mode 100644 security/whiteegret/Kconfig
 create mode 100644 security/whiteegret/Makefile
 create mode 100644 security/whiteegret/init.c
 create mode 100644 security/whiteegret/main.c
 create mode 100644 security/whiteegret/request.c
 create mode 100644 security/whiteegret/request.h
 create mode 100644 security/whiteegret/we.h
 create mode 100644 security/whiteegret/we_fs.c
 create mode 100644 security/whiteegret/we_fs.h
 create mode 100644 security/whiteegret/we_fs_common.h

diff --git a/security/Kconfig b/security/Kconfig
index c4302067a3ad..f17fefecaf84 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -237,6 +237,7 @@ source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/loadpin/Kconfig
 source security/yama/Kconfig
+source security/whiteegret/Kconfig
 
 source security/integrity/Kconfig
 
@@ -246,6 +247,7 @@ choice
 	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
 	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
 	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
+	default DEFAULT_SECURITY_WHITEEGRET if SECURITY_WHITEEGRET
 	default DEFAULT_SECURITY_DAC
 
 	help
@@ -264,6 +266,9 @@ choice
 	config DEFAULT_SECURITY_APPARMOR
 		bool "AppArmor" if SECURITY_APPARMOR=y
 
+	config DEFAULT_SECURITY_WHITEEGRET
+		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
+
 	config DEFAULT_SECURITY_DAC
 		bool "Unix Discretionary Access Controls"
 
@@ -275,6 +280,7 @@ config DEFAULT_SECURITY
 	default "smack" if DEFAULT_SECURITY_SMACK
 	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
 	default "apparmor" if DEFAULT_SECURITY_APPARMOR
+	default "whiteegret" if DEFAULT_SECURITY_WHITEEGRET
 	default "" if DEFAULT_SECURITY_DAC
 
 endmenu
diff --git a/security/Makefile b/security/Makefile
index 4d2d3782ddef..3a8249c77288 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
 subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
+subdir-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
 obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
+obj-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret/
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/whiteegret/Kconfig b/security/whiteegret/Kconfig
new file mode 100644
index 000000000000..32845977745f
--- /dev/null
+++ b/security/whiteegret/Kconfig
@@ -0,0 +1,11 @@
+config SECURITY_WHITEEGRET
+        bool "WhiteEgret support"
+        depends on SECURITY
+        default n
+        help
+	  This enables the WhiteEgret security module.
+	  WhiteEgret provides a whitelisting execution control capability,
+	  which helps stop the execution of unauthorized software
+	  such as malware.
+	  You will also need a user application and an execution whitelist.
+          If you are unsure how to answer this question, answer N.
diff --git a/security/whiteegret/Makefile b/security/whiteegret/Makefile
new file mode 100644
index 000000000000..16bd3afd9324
--- /dev/null
+++ b/security/whiteegret/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SECURITY_WHITEEGRET) += whiteegret.o
+whiteegret-y := init.o main.o request.o we_fs.o
diff --git a/security/whiteegret/init.c b/security/whiteegret/init.c
new file mode 100644
index 000000000000..3691cca6bc27
--- /dev/null
+++ b/security/whiteegret/init.c
@@ -0,0 +1,75 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#define pr_fmt(fmt) "WhiteEgret: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/security.h>
+#include <linux/fs.h>
+#include "we.h"
+
+#include <linux/lsm_hooks.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("WhiteEgret Linux Security Module");
+
+static int we_security_bprm_check(struct linux_binprm *bprm)
+{
+	if (we_security_bprm_check_main(bprm) == -EACCES)
+		return -EACCES;
+
+	return 0;
+}
+
+static int we_security_mmap_check(struct file *file, unsigned long reqprot,
+		unsigned long prot, unsigned long flags)
+{
+	if (we_security_mmap_check_main(file, reqprot, flags) == -EACCES)
+		return -EACCES;
+
+	return 0;
+}
+
+static struct security_hook_list we_hooks[] = {
+	LSM_HOOK_INIT(bprm_check_security, we_security_bprm_check),
+	LSM_HOOK_INIT(mmap_file, we_security_mmap_check),
+};
+
+static int __init we_init(void)
+{
+	int rc;
+
+	if (!security_module_enable("whiteegret"))
+		return 0;
+
+	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks), "whiteegret");
+
+	rc = we_specific_init();
+	if (rc) {
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+		return rc;
+	}
+
+	pr_warn("WhiteEgret (LSM) initialized.\n");
+
+	return 0;
+}
+
+static void __exit we_exit(void)
+{
+	we_specific_exit();
+
+	pr_warn("WhiteEgret (LSM) exited.\n");
+}
+
+module_init(we_init);
+module_exit(we_exit);
diff --git a/security/whiteegret/main.c b/security/whiteegret/main.c
new file mode 100644
index 000000000000..f60e1d325011
--- /dev/null
+++ b/security/whiteegret/main.c
@@ -0,0 +1,251 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#define pr_fmt(fmt) "WhiteEgret: " fmt
+
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/binfmts.h>
+#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/mman.h>
+#include "we.h"
+#include "request.h"
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "we_fs.h"
+
+
+static int send_receive_we_obj_info(
+		struct we_obj_info *we_obj_info, int *checkresult);
+
+/**
+ * we_specific_init - Initialize fs.
+ *
+ * Returns 0.
+ */
+int we_specific_init(void)
+{
+	int rc = 0;
+
+	rc = we_fs_init();
+	if (rc < 0) {
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+		return rc;
+	}
+
+	we_req_q_head_init();
+
+	return 0;
+}
+
+/**
+ * we_specific_exit - Nothing to do in the implementation.
+ *
+ * Returns 0.
+ */
+int we_specific_exit(void)
+{
+	return 0;
+}
+
+/**
+ * we_check_main - Common function for security_bprm_check and mmap_file.
+ *
+ * @file: Pointer to struct file.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int we_check_main(struct file *file)
+{
+	struct inode *inode;
+	struct we_obj_info we_obj_info;
+	char *pathnamebuf;
+	char *new_pathnamebuf;
+	char *pathname;
+	char *shortnamebuf;
+	int pathsize;
+	int rc;
+	int i;
+	int checkresult;
+
+	if (unlikely(file == NULL))
+		return 0;
+
+	pathsize = EXPECTPATHSIZE;
+	pathnamebuf = kmalloc(pathsize, GFP_KERNEL);
+	if (unlikely(!pathnamebuf)) {
+		rc = -ENOMEM;
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+		goto failure;
+	}
+	while (pathsize <= MAXPATHSIZE) {
+		pathname = d_absolute_path(&file->f_path, pathnamebuf,
+				pathsize-1);
+		if (!IS_ERR(pathname))
+			break;
+
+		pathsize += ADDEDEXPECTPATHSIZE;
+		new_pathnamebuf = krealloc(pathnamebuf, pathsize,
+				GFP_KERNEL);
+		if (unlikely(!new_pathnamebuf)) {
+			rc = -ENOMEM;
+			pr_err("error %d at %d in %s\n", rc,
+					__LINE__, __FILE__);
+			goto failure;
+		}
+		pathnamebuf = new_pathnamebuf;
+	}
+	if (unlikely(pathsize >= MAXPATHSIZE)) {
+		rc = -ENOMEM;
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+		goto failure;
+	}
+
+	shortnamebuf = pathname;
+	for (i = 0; i < pathsize; i++) {
+		if (pathname[i] == '\0')
+			break;
+		if (pathname[i] == '/')
+			shortnamebuf = pathname + (i + 1);
+	}
+	strncpy(we_obj_info.shortname, shortnamebuf, SHORTNAMELENGTH);
+	we_obj_info.path = pathname;
+	inode = file_inode(file);
+	we_obj_info.ino = inode->i_ino;
+	we_obj_info.dmajor = MAJOR(inode->i_sb->s_dev);
+	we_obj_info.dminor = MINOR(inode->i_sb->s_dev);
+	we_obj_info.pid = current->pid;
+	we_obj_info.pathsize = strlen(pathname);
+	we_obj_info.ppid = current->tgid;
+
+	rc = send_receive_we_obj_info(&we_obj_info, &checkresult);
+	if (rc < 0)
+		goto failure;
+
+	rc = checkresult;
+
+	if (rc == -EACCES)
+		pr_warn("block %s, ino=%ld, devno=0x%x.\n",
+			pathname, we_obj_info.ino,
+			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
+	else
+		pr_info("permit %s, ino=%ld, devno=0x%x.\n",
+			pathname, we_obj_info.ino,
+			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
+
+failure:
+	if (pathnamebuf != NULL) {
+		kfree(pathnamebuf);
+		pathnamebuf = NULL;
+	}
+
+	if ((rc != 0) && (rc != -EACCES))
+		pr_warn("Checking white list does not work.\n");
+
+	return rc;
+}
+
+/**
+ * send_receive_we_obj_info - Send message and wait.
+ *
+ * @we_obj_info: Pointer to struct we_obj_info.
+ * @result: Pointer to result of matching to white list.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+static int send_receive_we_obj_info(
+		struct we_obj_info *we_obj_info, int *checkresult)
+{
+	int i;
+	int rc;
+	struct we_req_q req;
+
+	we_req_q_init(&req, we_obj_info);
+
+	if ((we_req_q_search(&(req.data))) == NULL) {
+		rc = we_req_q_push(&req);
+		if (rc < 0) {
+			pr_err("error %d at %d in %s\n", rc,
+					__LINE__, __FILE__);
+			goto failure;
+		}
+	}
+
+	for (i = 0; i < MAXCOMRETRY; i++) {
+		rc = send_we_obj_info(&req);
+
+		if (likely(req.finish_flag == START_EXEC)) {
+			break;
+		} else if (unlikely(rc == -ERESTARTSYS)) {
+			pr_info("Signal detected (%d)\n", rc);
+			break;
+		}
+	}
+
+	we_req_q_pop(&req);
+
+	if (unlikely(i >= MAXCOMRETRY) && req.finish_flag != START_EXEC) {
+		rc = -EINVAL;
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+	}
+
+	*checkresult = req.permit;
+
+failure:
+	return rc;
+}
+
+/**
+ * we_security_bprm_check_main - Target for security_bprm_check.
+ *
+ * @bprm: Pointer to struct linux_binprm.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int we_security_bprm_check_main(struct linux_binprm *bprm)
+{
+	if (unlikely(!from_task))
+		return 0;
+
+	return we_check_main(bprm->file);
+}
+
+/**
+ * we_security_mmap_check_main - Target for mmap_file.
+ *
+ * @file: Pointer to struct file to map.
+ * @reqprot: Protection requested by the application.
+ * @flags: Operational flags.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int we_security_mmap_check_main(struct file *file,
+		unsigned long reqprot, unsigned long flags)
+{
+	if (unlikely(!from_task))
+		return 0;
+
+	if (!(reqprot & PROT_EXEC))
+		return 0;
+
+	if ((flags & MAP_EXECUTABLE))
+		return 0;
+
+	if (!file)
+		return 0;
+
+	if (!file->f_path.dentry)
+		return 0;
+
+	return we_check_main(file);
+}
diff --git a/security/whiteegret/request.c b/security/whiteegret/request.c
new file mode 100644
index 000000000000..7d28e133ebd6
--- /dev/null
+++ b/security/whiteegret/request.c
@@ -0,0 +1,151 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rwlock_types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "request.h"
+
+struct we_req_q_head we_q_head;
+
+static int match_we_req_data(struct we_req_data *data1,
+		struct we_req_data *data2);
+
+/**
+ * we_req_q_init - Initialize the global variable we_q_head.
+ *
+ * Returns 0.
+ */
+int we_req_q_head_init(void)
+{
+	rwlock_init(&(we_q_head.lock));
+	INIT_LIST_HEAD(&(we_q_head.head));
+	init_waitqueue_head(&(we_q_head.waitq));
+
+	return 0;
+}
+
+/**
+ * we_req_q_push - Add queue to tail of the list.
+ *
+ * @queue: Pointer to we_req_q to be added to the list.
+ *
+ * Returns 0.
+ */
+int we_req_q_push(struct we_req_q *queue)
+{
+	write_lock(&(we_q_head.lock));
+	list_add_tail(&(queue->queue), &we_q_head.head);
+	write_unlock(&(we_q_head.lock));
+
+	return 0;
+}
+
+/**
+ * we_req_q_search - Search data in the list.
+ *
+ * @data: Pointer to we_req_data to be searched in the list.
+ *
+ * Returns pointer to data if data is found in the list,
+ * NULL otherwise.
+ */
+struct we_req_q *we_req_q_search(struct we_req_data *data)
+{
+	struct list_head *p;
+	struct we_req_q *req;
+
+	read_lock(&(we_q_head.lock));
+
+	list_for_each(p, &(we_q_head.head)) {
+		req = list_entry(p, struct we_req_q, queue);
+
+		if (match_we_req_data(data, &(req->data))) {
+			read_unlock(&(we_q_head.lock));
+			return req;
+		}
+	}
+
+	read_unlock(&(we_q_head.lock));
+
+	return NULL;
+}
+
+/**
+ * we_req_q_init - Initialize queue.
+ *
+ * @req: Pointer to we_req_q to be initialized.
+ * @info: Pointer to we_obj_info.
+ *
+ * Returns 0.
+ */
+int we_req_q_init(struct we_req_q *req, struct we_obj_info *info)
+{
+	req->finish_flag = STOP_EXEC;
+	req->data.we_obj_info = info;
+	req->permit = -EACCES;
+	init_waitqueue_head(&req->waitq);
+
+	return 0;
+}
+
+/**
+ * we_req_q_pop - Delete queue in the list.
+ *
+ * Returns 0.
+ */
+int we_req_q_pop(struct we_req_q *queue)
+{
+	write_lock(&(we_q_head.lock));
+	list_del(&queue->queue);
+	write_unlock(&(we_q_head.lock));
+
+	return 0;
+}
+
+/**
+ * match_we_req_data - Compare two we_req_data data.
+ *
+ * @data1: Pointer to we_req_data
+ * @data2: Pointer to we_req_data
+ *
+ * Returns 1 if ppid of both we_req_data data are equal,
+ * 0 otherwise.
+ */
+static int match_we_req_data(struct we_req_data *data1,
+		struct we_req_data *data2)
+{
+	if (data1->we_obj_info->ppid == data2->we_obj_info->ppid)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * we_req_q_cleanup - Cleaning up queues.
+ *
+ * Returns 0.
+ */
+int we_req_q_cleanup(void)
+{
+	struct list_head *p;
+	struct we_req_q *req;
+
+	write_lock(&(we_q_head.lock));
+	list_for_each(p, &we_q_head.head) {
+		req = list_entry(p, struct we_req_q, queue);
+		req->finish_flag = START_EXEC;
+		req->permit = -EINVAL;
+	}
+	write_unlock(&(we_q_head.lock));
+
+	return 0;
+}
diff --git a/security/whiteegret/request.h b/security/whiteegret/request.h
new file mode 100644
index 000000000000..4a735fc70c63
--- /dev/null
+++ b/security/whiteegret/request.h
@@ -0,0 +1,52 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _REQUEST_H
+#define _REQUEST_H
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "we.h"
+
+struct we_req_q_head {
+	struct list_head head;
+	rwlock_t lock;
+	wait_queue_head_t waitq;
+};
+
+
+#define STOP_EXEC  0
+#define START_EXEC 1
+
+extern struct we_req_q_head we_q_head;
+
+/* Structure for information of request from kernel space to user space */
+struct we_req_data {
+	struct we_obj_info *we_obj_info;
+};
+
+struct we_req_q {
+	struct list_head queue;
+	int finish_flag;
+	struct we_req_data data;
+	int permit;
+	wait_queue_head_t waitq;
+};
+
+int we_req_q_pop(struct we_req_q *queue);
+int we_req_q_cleanup(void);
+
+int we_req_q_head_init(void);
+int we_req_q_init(struct we_req_q *req, struct we_obj_info *info);
+int we_req_q_push(struct we_req_q *queue);
+struct we_req_q *we_req_q_search(struct we_req_data *data);
+
+#endif  /* _REQUEST_H */
diff --git a/security/whiteegret/we.h b/security/whiteegret/we.h
new file mode 100644
index 000000000000..fc14e67d4f7d
--- /dev/null
+++ b/security/whiteegret/we.h
@@ -0,0 +1,66 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _WE_H
+#define _WE_H
+
+#include <linux/binfmts.h>
+
+/*
+ * Initial size in byte of memory allocation to store the path
+ * of an object file
+ */
+#define EXPECTPATHSIZE 1023
+
+/*
+ * Default size in byte to expand block that stores the path
+ * of an object file when the memory block is too small
+ * to store the path
+ */
+#define ADDEDEXPECTPATHSIZE 1023
+
+/* Maximum length in byte of path of object file */
+#define MAXPATHSIZE 8184
+
+/* Maximum length in byte of name of executable file */
+#define SHORTNAMELENGTH 256
+
+/*
+ * Maximum number of retry for sending the same message
+ * to user whitelisting application
+ */
+#define MAXCOMRETRY 10
+
+/* Timeout value in millisecond to aquire the semaphore */
+#define WERESULTTIMEOUT 1000
+
+/*
+ * Structure for an object to be tested whether it is contained
+ * in the whitelist or not
+ */
+struct we_obj_info {
+	unsigned long ino;                /* inode number */
+	unsigned int dmajor;              /* major version of device number */
+	unsigned int dminor;              /* minor version of device number */
+	char shortname[SHORTNAMELENGTH];  /* short name for the object */
+	int pathsize;
+	char *path;                       /* full path to the object */
+	pid_t pid;
+	pid_t ppid;
+};
+
+int we_security_bprm_check_main(struct linux_binprm *bprm);
+int we_security_mmap_check_main(struct file *file,
+		unsigned long reqprot, unsigned long flags);
+
+int we_specific_init(void);
+int we_specific_exit(void);
+
+#endif  /* _WE_H */
diff --git a/security/whiteegret/we_fs.c b/security/whiteegret/we_fs.c
new file mode 100644
index 000000000000..27b76f093814
--- /dev/null
+++ b/security/whiteegret/we_fs.c
@@ -0,0 +1,280 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#define pr_fmt(fmt) "WhiteEgret: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+
+#include "we_fs.h"
+
+#define static_assert(constexpr) \
+	char dummy[(constexpr) ? 1 : -1] __attribute__((unused))
+
+#define WE_COPY_TO_USER(to, from, ret) \
+	do { \
+		static_assert(sizeof((to)) == sizeof((from))); \
+		(ret) = copy_to_user(&(to), &(from), sizeof(to)); \
+	} while (0)
+
+#define WE_COPY_FROM_USER(to, from, ret) \
+	do { \
+		static_assert(sizeof((to)) == sizeof((from))); \
+		(ret) = copy_from_user(&(to), &(from), sizeof(to)); \
+	} while (0)
+
+static struct we_req_q_head *root;
+struct task_struct *from_task;
+static DEFINE_RWLOCK(from_task_lock);
+
+static int check_we_pathsize(struct we_req_q *we_req, int size)
+{
+	if (size - sizeof(*we_req)
+			> we_req->data.we_obj_info->pathsize)
+		return 0;
+	else
+		return -1;
+}
+
+static int set_we_req_info(struct we_req_user *user,
+		struct we_obj_info *info)
+{
+	unsigned long ret;
+
+	WE_COPY_TO_USER(user->ino, info->ino, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->dmajor, info->dmajor, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->dminor, info->dminor, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->pid, info->pid, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->ppid, info->ppid, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->shortname, info->shortname, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->pathsize, info->pathsize, ret);
+	if (ret != 0)
+		return -EFAULT;
+	ret = copy_to_user(user->path, info->path, info->pathsize + 1);
+	if (ret != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_we_ack(struct we_ack *to, struct we_ack *from)
+{
+	unsigned long ret;
+
+	WE_COPY_FROM_USER(to->pid, from->pid, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_FROM_USER(to->permit, from->permit, ret);
+	if (ret != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static struct we_req_user *get_alive_we_req(struct we_req_q_head *root,
+		void *buf, int size)
+{
+	int pathsize;
+	struct list_head *p;
+	struct we_req_q *req;
+	struct we_req_user *user = NULL;
+
+	write_lock(&root->lock);
+	list_for_each(p, &root->head) {
+		req = list_entry(p, struct we_req_q, queue);
+		if (req->finish_flag == STOP_EXEC) {
+			if (unlikely(check_we_pathsize(req, size)))
+				goto SIZE_ERROR;
+			user = (struct we_req_user *)buf;
+			set_we_req_info(user, req->data.we_obj_info);
+			break;
+		}
+	}
+	write_unlock(&root->lock);
+
+	return user;
+SIZE_ERROR:
+	pathsize = req->data.we_obj_info->pathsize;
+	req->permit = -EACCES;
+	req->finish_flag = START_EXEC;
+	write_unlock(&root->lock);
+	pr_err("Path length of exec is too long (%d).\n", pathsize);
+	return NULL;
+}
+
+static ssize_t send_ack(struct we_req_q_head *root, struct we_ack *ack)
+{
+	struct list_head *p;
+	struct we_req_q *req = NULL, *temp;
+
+	write_lock(&root->lock);
+	list_for_each(p, &root->head) {
+		temp = list_entry(p, struct we_req_q, queue);
+		if (temp->data.we_obj_info->pid == ack->pid) {
+			req = temp;
+			req->permit = ack->permit;
+			wake_up_interruptible_sync(&req->waitq);
+			req->finish_flag = START_EXEC;
+		}
+	}
+	write_unlock(&root->lock);
+
+	if (unlikely(!req)) {
+		pr_warn("%s: can not find we_req. pid(%d)\n",
+			__func__, ack->pid);
+		return -EACCES;
+	}
+	return sizeof(*ack);
+}
+
+static ssize_t we_driver_read(struct file *file, char *buf,
+		size_t size, loff_t *off)
+{
+	int ret;
+	struct we_req_user *user;
+
+	while (1) {
+		ret = wait_event_interruptible(root->waitq,
+				(user = get_alive_we_req(root, buf, size)));
+		if (unlikely(ret < 0)) {
+			pr_info("%s: signal (%d)", __func__, ret);
+			return 0;
+		}
+		if (likely(user))
+			break;
+	}
+
+	return sizeof(*user) + user->pathsize + 1;
+}
+
+static ssize_t we_driver_write(struct file *file, const char *buf,
+		size_t size, loff_t *off)
+{
+	int rc;
+	ssize_t ret;
+	struct we_ack ack;
+
+	rc = set_we_ack(&ack, (struct we_ack *)((void *)buf));
+	if (rc < 0)
+		return (ssize_t)rc;
+	ret = send_ack(root, &ack);
+
+	return ret;
+}
+
+static long we_driver_ioctl(struct file *file,
+		unsigned int arg0, unsigned long arg1)
+{
+	return 0;
+}
+
+static int we_driver_release(struct inode *inode, struct file *filp)
+{
+	int ret = 0;
+
+	write_lock(&from_task_lock);
+	if (!from_task) {
+		pr_warn("WhiteEgret has not started.\n");
+		ret =  -EACCES;
+		goto END;
+	}
+	if (from_task != current) {
+		pr_warn("This task is not registered to WhiteEgret.\n");
+		ret = -EACCES;
+		goto END;
+	}
+	from_task = NULL;
+	we_req_q_cleanup();
+END:
+	write_unlock(&from_task_lock);
+	return ret;
+}
+
+static int we_driver_open(struct inode *inode, struct file *filp)
+{
+	write_lock(&from_task_lock);
+	if (from_task) {
+		write_unlock(&(from_task_lock));
+		pr_warn("WhiteEgret has already started.\n");
+		return -EACCES;
+	}
+
+	from_task = current;
+	root = &we_q_head;
+	write_unlock(&from_task_lock);
+
+	return 0;
+}
+
+static const struct file_operations we_driver_fops = {
+	.owner = THIS_MODULE,
+	.read = we_driver_read,
+	.write = we_driver_write,
+	.unlocked_ioctl = we_driver_ioctl,
+	.open =  we_driver_open,
+	.release = we_driver_release,
+};
+
+int we_fs_init(void)
+{
+	struct dentry *we_dir;
+	struct dentry *wecom;
+
+	we_dir = securityfs_create_dir(WE_FS_DIR_NAME, NULL);
+	if (IS_ERR(we_dir))
+		return PTR_ERR(we_dir);
+
+	wecom = securityfs_create_file(WE_DEV_NAME, 0600, we_dir, NULL, &we_driver_fops);
+	if (IS_ERR(wecom)) {
+		securityfs_remove(we_dir);
+		return PTR_ERR(wecom);
+	}
+
+	return 0;
+}
+
+/**
+ * send_we_obj_info - Wait response from user's whitelisting application.
+ *
+ * @req: Pointer to struct we_req_q.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int send_we_obj_info(struct we_req_q *req)
+{
+	/* If there exists queue waiting for this request req done,
+	 * then wake it up.
+	 */
+	if (waitqueue_active(&(we_q_head.waitq)))
+		wake_up(&(we_q_head.waitq));
+
+	return wait_event_interruptible_timeout(req->waitq,
+			(req->finish_flag == START_EXEC),
+			WERESULTTIMEOUT);
+}
diff --git a/security/whiteegret/we_fs.h b/security/whiteegret/we_fs.h
new file mode 100644
index 000000000000..9af245d7aca4
--- /dev/null
+++ b/security/whiteegret/we_fs.h
@@ -0,0 +1,23 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _WE_FS_H
+#define _WE_FS_H
+
+#include "request.h"
+#include "we_fs_common.h"
+
+extern struct task_struct *from_task;
+
+int we_fs_init(void);
+
+int send_we_obj_info(struct we_req_q *req);
+
+#endif  /* _WE_FS_H */
diff --git a/security/whiteegret/we_fs_common.h b/security/whiteegret/we_fs_common.h
new file mode 100644
index 000000000000..259f300d9738
--- /dev/null
+++ b/security/whiteegret/we_fs_common.h
@@ -0,0 +1,36 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _WE_FS_COMMON_H
+#define _WE_FS_COMMON_H
+
+#define WE_FS_DIR_NAME "whiteegret"
+#define WE_DEV_NAME "wecom"
+#define WE_DEV_PATH "/sys/kernel/security/"WE_FS_DIR_NAME"/"WE_DEV_NAME
+
+#define SHORTNAMELENGTH 256
+
+struct we_req_user {
+	unsigned long ino;
+	unsigned int dmajor;
+	unsigned int dminor;
+	pid_t pid;
+	pid_t ppid;
+	char shortname[SHORTNAMELENGTH];
+	int pathsize;
+	char path[0];
+};
+
+struct we_ack {
+	int permit;
+	pid_t pid;
+};
+
+#endif  /* _WE_FS_COMMON_H */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
@ 2018-03-01  7:38 ` Masanobu Koike
  0 siblings, 0 replies; 10+ messages in thread
From: Masanobu Koike @ 2018-03-01  7:38 UTC (permalink / raw)
  To: linux-security-module

This RFC provides implementation of WhiteEgret.

Signed-off-by: Masanobu Koike <masanobu2.koike@toshiba.co.jp>
---
 security/Kconfig                   |   6 +
 security/Makefile                  |   2 +
 security/whiteegret/Kconfig        |  11 ++
 security/whiteegret/Makefile       |   2 +
 security/whiteegret/init.c         |  75 ++++++++++
 security/whiteegret/main.c         | 251 +++++++++++++++++++++++++++++++++
 security/whiteegret/request.c      | 151 ++++++++++++++++++++
 security/whiteegret/request.h      |  52 +++++++
 security/whiteegret/we.h           |  66 +++++++++
 security/whiteegret/we_fs.c        | 280 +++++++++++++++++++++++++++++++++++++
 security/whiteegret/we_fs.h        |  23 +++
 security/whiteegret/we_fs_common.h |  36 +++++
 12 files changed, 955 insertions(+)
 create mode 100644 security/whiteegret/Kconfig
 create mode 100644 security/whiteegret/Makefile
 create mode 100644 security/whiteegret/init.c
 create mode 100644 security/whiteegret/main.c
 create mode 100644 security/whiteegret/request.c
 create mode 100644 security/whiteegret/request.h
 create mode 100644 security/whiteegret/we.h
 create mode 100644 security/whiteegret/we_fs.c
 create mode 100644 security/whiteegret/we_fs.h
 create mode 100644 security/whiteegret/we_fs_common.h

diff --git a/security/Kconfig b/security/Kconfig
index c4302067a3ad..f17fefecaf84 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -237,6 +237,7 @@ source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/loadpin/Kconfig
 source security/yama/Kconfig
+source security/whiteegret/Kconfig
 
 source security/integrity/Kconfig
 
@@ -246,6 +247,7 @@ choice
 	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
 	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
 	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
+	default DEFAULT_SECURITY_WHITEEGRET if SECURITY_WHITEEGRET
 	default DEFAULT_SECURITY_DAC
 
 	help
@@ -264,6 +266,9 @@ choice
 	config DEFAULT_SECURITY_APPARMOR
 		bool "AppArmor" if SECURITY_APPARMOR=y
 
+	config DEFAULT_SECURITY_WHITEEGRET
+		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
+
 	config DEFAULT_SECURITY_DAC
 		bool "Unix Discretionary Access Controls"
 
@@ -275,6 +280,7 @@ config DEFAULT_SECURITY
 	default "smack" if DEFAULT_SECURITY_SMACK
 	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
 	default "apparmor" if DEFAULT_SECURITY_APPARMOR
+	default "whiteegret" if DEFAULT_SECURITY_WHITEEGRET
 	default "" if DEFAULT_SECURITY_DAC
 
 endmenu
diff --git a/security/Makefile b/security/Makefile
index 4d2d3782ddef..3a8249c77288 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
 subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
+subdir-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
 obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
+obj-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret/
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/whiteegret/Kconfig b/security/whiteegret/Kconfig
new file mode 100644
index 000000000000..32845977745f
--- /dev/null
+++ b/security/whiteegret/Kconfig
@@ -0,0 +1,11 @@
+config SECURITY_WHITEEGRET
+        bool "WhiteEgret support"
+        depends on SECURITY
+        default n
+        help
+	  This enables the WhiteEgret security module.
+	  WhiteEgret provides a whitelisting execution control capability,
+	  which helps stop the execution of unauthorized software
+	  such as malware.
+	  You will also need a user application and an execution whitelist.
+          If you are unsure how to answer this question, answer N.
diff --git a/security/whiteegret/Makefile b/security/whiteegret/Makefile
new file mode 100644
index 000000000000..16bd3afd9324
--- /dev/null
+++ b/security/whiteegret/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SECURITY_WHITEEGRET) += whiteegret.o
+whiteegret-y := init.o main.o request.o we_fs.o
diff --git a/security/whiteegret/init.c b/security/whiteegret/init.c
new file mode 100644
index 000000000000..3691cca6bc27
--- /dev/null
+++ b/security/whiteegret/init.c
@@ -0,0 +1,75 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#define pr_fmt(fmt) "WhiteEgret: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/security.h>
+#include <linux/fs.h>
+#include "we.h"
+
+#include <linux/lsm_hooks.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("WhiteEgret Linux Security Module");
+
+static int we_security_bprm_check(struct linux_binprm *bprm)
+{
+	if (we_security_bprm_check_main(bprm) == -EACCES)
+		return -EACCES;
+
+	return 0;
+}
+
+static int we_security_mmap_check(struct file *file, unsigned long reqprot,
+		unsigned long prot, unsigned long flags)
+{
+	if (we_security_mmap_check_main(file, reqprot, flags) == -EACCES)
+		return -EACCES;
+
+	return 0;
+}
+
+static struct security_hook_list we_hooks[] = {
+	LSM_HOOK_INIT(bprm_check_security, we_security_bprm_check),
+	LSM_HOOK_INIT(mmap_file, we_security_mmap_check),
+};
+
+static int __init we_init(void)
+{
+	int rc;
+
+	if (!security_module_enable("whiteegret"))
+		return 0;
+
+	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks), "whiteegret");
+
+	rc = we_specific_init();
+	if (rc) {
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+		return rc;
+	}
+
+	pr_warn("WhiteEgret (LSM) initialized.\n");
+
+	return 0;
+}
+
+static void __exit we_exit(void)
+{
+	we_specific_exit();
+
+	pr_warn("WhiteEgret (LSM) exited.\n");
+}
+
+module_init(we_init);
+module_exit(we_exit);
diff --git a/security/whiteegret/main.c b/security/whiteegret/main.c
new file mode 100644
index 000000000000..f60e1d325011
--- /dev/null
+++ b/security/whiteegret/main.c
@@ -0,0 +1,251 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#define pr_fmt(fmt) "WhiteEgret: " fmt
+
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/binfmts.h>
+#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/mman.h>
+#include "we.h"
+#include "request.h"
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "we_fs.h"
+
+
+static int send_receive_we_obj_info(
+		struct we_obj_info *we_obj_info, int *checkresult);
+
+/**
+ * we_specific_init - Initialize fs.
+ *
+ * Returns 0.
+ */
+int we_specific_init(void)
+{
+	int rc = 0;
+
+	rc = we_fs_init();
+	if (rc < 0) {
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+		return rc;
+	}
+
+	we_req_q_head_init();
+
+	return 0;
+}
+
+/**
+ * we_specific_exit - Nothing to do in the implementation.
+ *
+ * Returns 0.
+ */
+int we_specific_exit(void)
+{
+	return 0;
+}
+
+/**
+ * we_check_main - Common function for security_bprm_check and mmap_file.
+ *
+ * @file: Pointer to struct file.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int we_check_main(struct file *file)
+{
+	struct inode *inode;
+	struct we_obj_info we_obj_info;
+	char *pathnamebuf;
+	char *new_pathnamebuf;
+	char *pathname;
+	char *shortnamebuf;
+	int pathsize;
+	int rc;
+	int i;
+	int checkresult;
+
+	if (unlikely(file == NULL))
+		return 0;
+
+	pathsize = EXPECTPATHSIZE;
+	pathnamebuf = kmalloc(pathsize, GFP_KERNEL);
+	if (unlikely(!pathnamebuf)) {
+		rc = -ENOMEM;
+		pr_err("error %d@%d in %s\n", rc, __LINE__, __FILE__);
+		goto failure;
+	}
+	while (pathsize <= MAXPATHSIZE) {
+		pathname = d_absolute_path(&file->f_path, pathnamebuf,
+				pathsize-1);
+		if (!IS_ERR(pathname))
+			break;
+
+		pathsize += ADDEDEXPECTPATHSIZE;
+		new_pathnamebuf = krealloc(pathnamebuf, pathsize,
+				GFP_KERNEL);
+		if (unlikely(!new_pathnamebuf)) {
+			rc = -ENOMEM;
+			pr_err("error %d at %d in %s\n", rc,
+					__LINE__, __FILE__);
+			goto failure;
+		}
+		pathnamebuf = new_pathnamebuf;
+	}
+	if (unlikely(pathsize >= MAXPATHSIZE)) {
+		rc = -ENOMEM;
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+		goto failure;
+	}
+
+	shortnamebuf = pathname;
+	for (i = 0; i < pathsize; i++) {
+		if (pathname[i] == '\0')
+			break;
+		if (pathname[i] == '/')
+			shortnamebuf = pathname + (i + 1);
+	}
+	strncpy(we_obj_info.shortname, shortnamebuf, SHORTNAMELENGTH);
+	we_obj_info.path = pathname;
+	inode = file_inode(file);
+	we_obj_info.ino = inode->i_ino;
+	we_obj_info.dmajor = MAJOR(inode->i_sb->s_dev);
+	we_obj_info.dminor = MINOR(inode->i_sb->s_dev);
+	we_obj_info.pid = current->pid;
+	we_obj_info.pathsize = strlen(pathname);
+	we_obj_info.ppid = current->tgid;
+
+	rc = send_receive_we_obj_info(&we_obj_info, &checkresult);
+	if (rc < 0)
+		goto failure;
+
+	rc = checkresult;
+
+	if (rc == -EACCES)
+		pr_warn("block %s, ino=%ld, devno=0x%x.\n",
+			pathname, we_obj_info.ino,
+			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
+	else
+		pr_info("permit %s, ino=%ld, devno=0x%x.\n",
+			pathname, we_obj_info.ino,
+			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
+
+failure:
+	if (pathnamebuf != NULL) {
+		kfree(pathnamebuf);
+		pathnamebuf = NULL;
+	}
+
+	if ((rc != 0) && (rc != -EACCES))
+		pr_warn("Checking white list does not work.\n");
+
+	return rc;
+}
+
+/**
+ * send_receive_we_obj_info - Send message and wait.
+ *
+ * @we_obj_info: Pointer to struct we_obj_info.
+ * @result: Pointer to result of matching to white list.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+static int send_receive_we_obj_info(
+		struct we_obj_info *we_obj_info, int *checkresult)
+{
+	int i;
+	int rc;
+	struct we_req_q req;
+
+	we_req_q_init(&req, we_obj_info);
+
+	if ((we_req_q_search(&(req.data))) == NULL) {
+		rc = we_req_q_push(&req);
+		if (rc < 0) {
+			pr_err("error %d@%d in %s\n", rc,
+					__LINE__, __FILE__);
+			goto failure;
+		}
+	}
+
+	for (i = 0; i < MAXCOMRETRY; i++) {
+		rc = send_we_obj_info(&req);
+
+		if (likely(req.finish_flag == START_EXEC)) {
+			break;
+		} else if (unlikely(rc == -ERESTARTSYS)) {
+			pr_info("Signal detected (%d)\n", rc);
+			break;
+		}
+	}
+
+	we_req_q_pop(&req);
+
+	if (unlikely(i >= MAXCOMRETRY) && req.finish_flag != START_EXEC) {
+		rc = -EINVAL;
+		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
+	}
+
+	*checkresult = req.permit;
+
+failure:
+	return rc;
+}
+
+/**
+ * we_security_bprm_check_main - Target for security_bprm_check.
+ *
+ * @bprm: Pointer to struct linux_binprm.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int we_security_bprm_check_main(struct linux_binprm *bprm)
+{
+	if (unlikely(!from_task))
+		return 0;
+
+	return we_check_main(bprm->file);
+}
+
+/**
+ * we_security_mmap_check_main - Target for mmap_file.
+ *
+ * @file: Pointer to struct file to map.
+ * @reqprot: Protection requested by the application.
+ * @flags: Operational flags.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int we_security_mmap_check_main(struct file *file,
+		unsigned long reqprot, unsigned long flags)
+{
+	if (unlikely(!from_task))
+		return 0;
+
+	if (!(reqprot & PROT_EXEC))
+		return 0;
+
+	if ((flags & MAP_EXECUTABLE))
+		return 0;
+
+	if (!file)
+		return 0;
+
+	if (!file->f_path.dentry)
+		return 0;
+
+	return we_check_main(file);
+}
diff --git a/security/whiteegret/request.c b/security/whiteegret/request.c
new file mode 100644
index 000000000000..7d28e133ebd6
--- /dev/null
+++ b/security/whiteegret/request.c
@@ -0,0 +1,151 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rwlock_types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "request.h"
+
+struct we_req_q_head we_q_head;
+
+static int match_we_req_data(struct we_req_data *data1,
+		struct we_req_data *data2);
+
+/**
+ * we_req_q_init - Initialize the global variable we_q_head.
+ *
+ * Returns 0.
+ */
+int we_req_q_head_init(void)
+{
+	rwlock_init(&(we_q_head.lock));
+	INIT_LIST_HEAD(&(we_q_head.head));
+	init_waitqueue_head(&(we_q_head.waitq));
+
+	return 0;
+}
+
+/**
+ * we_req_q_push - Add queue to tail of the list.
+ *
+ * @queue: Pointer to we_req_q to be added to the list.
+ *
+ * Returns 0.
+ */
+int we_req_q_push(struct we_req_q *queue)
+{
+	write_lock(&(we_q_head.lock));
+	list_add_tail(&(queue->queue), &we_q_head.head);
+	write_unlock(&(we_q_head.lock));
+
+	return 0;
+}
+
+/**
+ * we_req_q_search - Search data in the list.
+ *
+ * @data: Pointer to we_req_data to be searched in the list.
+ *
+ * Returns pointer to data if data is found in the list,
+ * NULL otherwise.
+ */
+struct we_req_q *we_req_q_search(struct we_req_data *data)
+{
+	struct list_head *p;
+	struct we_req_q *req;
+
+	read_lock(&(we_q_head.lock));
+
+	list_for_each(p, &(we_q_head.head)) {
+		req = list_entry(p, struct we_req_q, queue);
+
+		if (match_we_req_data(data, &(req->data))) {
+			read_unlock(&(we_q_head.lock));
+			return req;
+		}
+	}
+
+	read_unlock(&(we_q_head.lock));
+
+	return NULL;
+}
+
+/**
+ * we_req_q_init - Initialize queue.
+ *
+ * @req: Pointer to we_req_q to be initialized.
+ * @info: Pointer to we_obj_info.
+ *
+ * Returns 0.
+ */
+int we_req_q_init(struct we_req_q *req, struct we_obj_info *info)
+{
+	req->finish_flag = STOP_EXEC;
+	req->data.we_obj_info = info;
+	req->permit = -EACCES;
+	init_waitqueue_head(&req->waitq);
+
+	return 0;
+}
+
+/**
+ * we_req_q_pop - Delete queue in the list.
+ *
+ * Returns 0.
+ */
+int we_req_q_pop(struct we_req_q *queue)
+{
+	write_lock(&(we_q_head.lock));
+	list_del(&queue->queue);
+	write_unlock(&(we_q_head.lock));
+
+	return 0;
+}
+
+/**
+ * match_we_req_data - Compare two we_req_data data.
+ *
+ * @data1: Pointer to we_req_data
+ * @data2: Pointer to we_req_data
+ *
+ * Returns 1 if ppid of both we_req_data data are equal,
+ * 0 otherwise.
+ */
+static int match_we_req_data(struct we_req_data *data1,
+		struct we_req_data *data2)
+{
+	if (data1->we_obj_info->ppid == data2->we_obj_info->ppid)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * we_req_q_cleanup - Cleaning up queues.
+ *
+ * Returns 0.
+ */
+int we_req_q_cleanup(void)
+{
+	struct list_head *p;
+	struct we_req_q *req;
+
+	write_lock(&(we_q_head.lock));
+	list_for_each(p, &we_q_head.head) {
+		req = list_entry(p, struct we_req_q, queue);
+		req->finish_flag = START_EXEC;
+		req->permit = -EINVAL;
+	}
+	write_unlock(&(we_q_head.lock));
+
+	return 0;
+}
diff --git a/security/whiteegret/request.h b/security/whiteegret/request.h
new file mode 100644
index 000000000000..4a735fc70c63
--- /dev/null
+++ b/security/whiteegret/request.h
@@ -0,0 +1,52 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _REQUEST_H
+#define _REQUEST_H
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#include "we.h"
+
+struct we_req_q_head {
+	struct list_head head;
+	rwlock_t lock;
+	wait_queue_head_t waitq;
+};
+
+
+#define STOP_EXEC  0
+#define START_EXEC 1
+
+extern struct we_req_q_head we_q_head;
+
+/* Structure for information of request from kernel space to user space */
+struct we_req_data {
+	struct we_obj_info *we_obj_info;
+};
+
+struct we_req_q {
+	struct list_head queue;
+	int finish_flag;
+	struct we_req_data data;
+	int permit;
+	wait_queue_head_t waitq;
+};
+
+int we_req_q_pop(struct we_req_q *queue);
+int we_req_q_cleanup(void);
+
+int we_req_q_head_init(void);
+int we_req_q_init(struct we_req_q *req, struct we_obj_info *info);
+int we_req_q_push(struct we_req_q *queue);
+struct we_req_q *we_req_q_search(struct we_req_data *data);
+
+#endif  /* _REQUEST_H */
diff --git a/security/whiteegret/we.h b/security/whiteegret/we.h
new file mode 100644
index 000000000000..fc14e67d4f7d
--- /dev/null
+++ b/security/whiteegret/we.h
@@ -0,0 +1,66 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _WE_H
+#define _WE_H
+
+#include <linux/binfmts.h>
+
+/*
+ * Initial size in byte of memory allocation to store the path
+ * of an object file
+ */
+#define EXPECTPATHSIZE 1023
+
+/*
+ * Default size in byte to expand block that stores the path
+ * of an object file when the memory block is too small
+ * to store the path
+ */
+#define ADDEDEXPECTPATHSIZE 1023
+
+/* Maximum length in byte of path of object file */
+#define MAXPATHSIZE 8184
+
+/* Maximum length in byte of name of executable file */
+#define SHORTNAMELENGTH 256
+
+/*
+ * Maximum number of retry for sending the same message
+ * to user whitelisting application
+ */
+#define MAXCOMRETRY 10
+
+/* Timeout value in millisecond to aquire the semaphore */
+#define WERESULTTIMEOUT 1000
+
+/*
+ * Structure for an object to be tested whether it is contained
+ * in the whitelist or not
+ */
+struct we_obj_info {
+	unsigned long ino;                /* inode number */
+	unsigned int dmajor;              /* major version of device number */
+	unsigned int dminor;              /* minor version of device number */
+	char shortname[SHORTNAMELENGTH];  /* short name for the object */
+	int pathsize;
+	char *path;                       /* full path to the object */
+	pid_t pid;
+	pid_t ppid;
+};
+
+int we_security_bprm_check_main(struct linux_binprm *bprm);
+int we_security_mmap_check_main(struct file *file,
+		unsigned long reqprot, unsigned long flags);
+
+int we_specific_init(void);
+int we_specific_exit(void);
+
+#endif  /* _WE_H */
diff --git a/security/whiteegret/we_fs.c b/security/whiteegret/we_fs.c
new file mode 100644
index 000000000000..27b76f093814
--- /dev/null
+++ b/security/whiteegret/we_fs.c
@@ -0,0 +1,280 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#define pr_fmt(fmt) "WhiteEgret: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+
+#include "we_fs.h"
+
+#define static_assert(constexpr) \
+	char dummy[(constexpr) ? 1 : -1] __attribute__((unused))
+
+#define WE_COPY_TO_USER(to, from, ret) \
+	do { \
+		static_assert(sizeof((to)) == sizeof((from))); \
+		(ret) = copy_to_user(&(to), &(from), sizeof(to)); \
+	} while (0)
+
+#define WE_COPY_FROM_USER(to, from, ret) \
+	do { \
+		static_assert(sizeof((to)) == sizeof((from))); \
+		(ret) = copy_from_user(&(to), &(from), sizeof(to)); \
+	} while (0)
+
+static struct we_req_q_head *root;
+struct task_struct *from_task;
+static DEFINE_RWLOCK(from_task_lock);
+
+static int check_we_pathsize(struct we_req_q *we_req, int size)
+{
+	if (size - sizeof(*we_req)
+			> we_req->data.we_obj_info->pathsize)
+		return 0;
+	else
+		return -1;
+}
+
+static int set_we_req_info(struct we_req_user *user,
+		struct we_obj_info *info)
+{
+	unsigned long ret;
+
+	WE_COPY_TO_USER(user->ino, info->ino, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->dmajor, info->dmajor, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->dminor, info->dminor, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->pid, info->pid, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->ppid, info->ppid, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->shortname, info->shortname, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_TO_USER(user->pathsize, info->pathsize, ret);
+	if (ret != 0)
+		return -EFAULT;
+	ret = copy_to_user(user->path, info->path, info->pathsize + 1);
+	if (ret != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_we_ack(struct we_ack *to, struct we_ack *from)
+{
+	unsigned long ret;
+
+	WE_COPY_FROM_USER(to->pid, from->pid, ret);
+	if (ret != 0)
+		return -EFAULT;
+	WE_COPY_FROM_USER(to->permit, from->permit, ret);
+	if (ret != 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static struct we_req_user *get_alive_we_req(struct we_req_q_head *root,
+		void *buf, int size)
+{
+	int pathsize;
+	struct list_head *p;
+	struct we_req_q *req;
+	struct we_req_user *user = NULL;
+
+	write_lock(&root->lock);
+	list_for_each(p, &root->head) {
+		req = list_entry(p, struct we_req_q, queue);
+		if (req->finish_flag == STOP_EXEC) {
+			if (unlikely(check_we_pathsize(req, size)))
+				goto SIZE_ERROR;
+			user = (struct we_req_user *)buf;
+			set_we_req_info(user, req->data.we_obj_info);
+			break;
+		}
+	}
+	write_unlock(&root->lock);
+
+	return user;
+SIZE_ERROR:
+	pathsize = req->data.we_obj_info->pathsize;
+	req->permit = -EACCES;
+	req->finish_flag = START_EXEC;
+	write_unlock(&root->lock);
+	pr_err("Path length of exec is too long (%d).\n", pathsize);
+	return NULL;
+}
+
+static ssize_t send_ack(struct we_req_q_head *root, struct we_ack *ack)
+{
+	struct list_head *p;
+	struct we_req_q *req = NULL, *temp;
+
+	write_lock(&root->lock);
+	list_for_each(p, &root->head) {
+		temp = list_entry(p, struct we_req_q, queue);
+		if (temp->data.we_obj_info->pid == ack->pid) {
+			req = temp;
+			req->permit = ack->permit;
+			wake_up_interruptible_sync(&req->waitq);
+			req->finish_flag = START_EXEC;
+		}
+	}
+	write_unlock(&root->lock);
+
+	if (unlikely(!req)) {
+		pr_warn("%s: can not find we_req. pid(%d)\n",
+			__func__, ack->pid);
+		return -EACCES;
+	}
+	return sizeof(*ack);
+}
+
+static ssize_t we_driver_read(struct file *file, char *buf,
+		size_t size, loff_t *off)
+{
+	int ret;
+	struct we_req_user *user;
+
+	while (1) {
+		ret = wait_event_interruptible(root->waitq,
+				(user = get_alive_we_req(root, buf, size)));
+		if (unlikely(ret < 0)) {
+			pr_info("%s: signal (%d)", __func__, ret);
+			return 0;
+		}
+		if (likely(user))
+			break;
+	}
+
+	return sizeof(*user) + user->pathsize + 1;
+}
+
+static ssize_t we_driver_write(struct file *file, const char *buf,
+		size_t size, loff_t *off)
+{
+	int rc;
+	ssize_t ret;
+	struct we_ack ack;
+
+	rc = set_we_ack(&ack, (struct we_ack *)((void *)buf));
+	if (rc < 0)
+		return (ssize_t)rc;
+	ret = send_ack(root, &ack);
+
+	return ret;
+}
+
+static long we_driver_ioctl(struct file *file,
+		unsigned int arg0, unsigned long arg1)
+{
+	return 0;
+}
+
+static int we_driver_release(struct inode *inode, struct file *filp)
+{
+	int ret = 0;
+
+	write_lock(&from_task_lock);
+	if (!from_task) {
+		pr_warn("WhiteEgret has not started.\n");
+		ret =  -EACCES;
+		goto END;
+	}
+	if (from_task != current) {
+		pr_warn("This task is not registered to WhiteEgret.\n");
+		ret = -EACCES;
+		goto END;
+	}
+	from_task = NULL;
+	we_req_q_cleanup();
+END:
+	write_unlock(&from_task_lock);
+	return ret;
+}
+
+static int we_driver_open(struct inode *inode, struct file *filp)
+{
+	write_lock(&from_task_lock);
+	if (from_task) {
+		write_unlock(&(from_task_lock));
+		pr_warn("WhiteEgret has already started.\n");
+		return -EACCES;
+	}
+
+	from_task = current;
+	root = &we_q_head;
+	write_unlock(&from_task_lock);
+
+	return 0;
+}
+
+static const struct file_operations we_driver_fops = {
+	.owner = THIS_MODULE,
+	.read = we_driver_read,
+	.write = we_driver_write,
+	.unlocked_ioctl = we_driver_ioctl,
+	.open =  we_driver_open,
+	.release = we_driver_release,
+};
+
+int we_fs_init(void)
+{
+	struct dentry *we_dir;
+	struct dentry *wecom;
+
+	we_dir = securityfs_create_dir(WE_FS_DIR_NAME, NULL);
+	if (IS_ERR(we_dir))
+		return PTR_ERR(we_dir);
+
+	wecom = securityfs_create_file(WE_DEV_NAME, 0600, we_dir, NULL, &we_driver_fops);
+	if (IS_ERR(wecom)) {
+		securityfs_remove(we_dir);
+		return PTR_ERR(wecom);
+	}
+
+	return 0;
+}
+
+/**
+ * send_we_obj_info - Wait response from user's whitelisting application.
+ *
+ * @req: Pointer to struct we_req_q.
+ *
+ * Returns 0 if succeeded, < 0 otherwise.
+ */
+int send_we_obj_info(struct we_req_q *req)
+{
+	/* If there exists queue waiting for this request req done,
+	 * then wake it up.
+	 */
+	if (waitqueue_active(&(we_q_head.waitq)))
+		wake_up(&(we_q_head.waitq));
+
+	return wait_event_interruptible_timeout(req->waitq,
+			(req->finish_flag == START_EXEC),
+			WERESULTTIMEOUT);
+}
diff --git a/security/whiteegret/we_fs.h b/security/whiteegret/we_fs.h
new file mode 100644
index 000000000000..9af245d7aca4
--- /dev/null
+++ b/security/whiteegret/we_fs.h
@@ -0,0 +1,23 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _WE_FS_H
+#define _WE_FS_H
+
+#include "request.h"
+#include "we_fs_common.h"
+
+extern struct task_struct *from_task;
+
+int we_fs_init(void);
+
+int send_we_obj_info(struct we_req_q *req);
+
+#endif  /* _WE_FS_H */
diff --git a/security/whiteegret/we_fs_common.h b/security/whiteegret/we_fs_common.h
new file mode 100644
index 000000000000..259f300d9738
--- /dev/null
+++ b/security/whiteegret/we_fs_common.h
@@ -0,0 +1,36 @@
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Copyright (C) 2017-2018 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ */
+
+#ifndef _WE_FS_COMMON_H
+#define _WE_FS_COMMON_H
+
+#define WE_FS_DIR_NAME "whiteegret"
+#define WE_DEV_NAME "wecom"
+#define WE_DEV_PATH "/sys/kernel/security/"WE_FS_DIR_NAME"/"WE_DEV_NAME
+
+#define SHORTNAMELENGTH 256
+
+struct we_req_user {
+	unsigned long ino;
+	unsigned int dmajor;
+	unsigned int dminor;
+	pid_t pid;
+	pid_t ppid;
+	char shortname[SHORTNAMELENGTH];
+	int pathsize;
+	char path[0];
+};
+
+struct we_ack {
+	int permit;
+	pid_t pid;
+};
+
+#endif  /* _WE_FS_COMMON_H */
-- 
2.14.1


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
  2018-03-01  7:38 ` Masanobu Koike
@ 2018-03-01 15:43   ` Casey Schaufler
  -1 siblings, 0 replies; 10+ messages in thread
From: Casey Schaufler @ 2018-03-01 15:43 UTC (permalink / raw)
  To: Masanobu Koike, jmorris, serge, linux-security-module, linux-kernel

On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> This RFC provides implementation of WhiteEgret.
>
> Signed-off-by: Masanobu Koike <masanobu2.koike@toshiba.co.jp>
> ---
>  security/Kconfig                   |   6 +
>  security/Makefile                  |   2 +
>  security/whiteegret/Kconfig        |  11 ++
>  security/whiteegret/Makefile       |   2 +
>  security/whiteegret/init.c         |  75 ++++++++++
>  security/whiteegret/main.c         | 251 +++++++++++++++++++++++++++++++++
>  security/whiteegret/request.c      | 151 ++++++++++++++++++++
>  security/whiteegret/request.h      |  52 +++++++
>  security/whiteegret/we.h           |  66 +++++++++
>  security/whiteegret/we_fs.c        | 280 +++++++++++++++++++++++++++++++++++++
>  security/whiteegret/we_fs.h        |  23 +++
>  security/whiteegret/we_fs_common.h |  36 +++++
>  12 files changed, 955 insertions(+)
>  create mode 100644 security/whiteegret/Kconfig
>  create mode 100644 security/whiteegret/Makefile
>  create mode 100644 security/whiteegret/init.c
>  create mode 100644 security/whiteegret/main.c
>  create mode 100644 security/whiteegret/request.c
>  create mode 100644 security/whiteegret/request.h
>  create mode 100644 security/whiteegret/we.h
>  create mode 100644 security/whiteegret/we_fs.c
>  create mode 100644 security/whiteegret/we_fs.h
>  create mode 100644 security/whiteegret/we_fs_common.h
>
> diff --git a/security/Kconfig b/security/Kconfig
> index c4302067a3ad..f17fefecaf84 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -237,6 +237,7 @@ source security/tomoyo/Kconfig
>  source security/apparmor/Kconfig
>  source security/loadpin/Kconfig
>  source security/yama/Kconfig
> +source security/whiteegret/Kconfig
>  
>  source security/integrity/Kconfig
>  
> @@ -246,6 +247,7 @@ choice
>  	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
>  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
>  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> +	default DEFAULT_SECURITY_WHITEEGRET if SECURITY_WHITEEGRET
>  	default DEFAULT_SECURITY_DAC
>  
>  	help
> @@ -264,6 +266,9 @@ choice
>  	config DEFAULT_SECURITY_APPARMOR
>  		bool "AppArmor" if SECURITY_APPARMOR=y
>  
> +	config DEFAULT_SECURITY_WHITEEGRET
> +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> +

I don't see this module using any security blobs. Is there
a reason you're not making this a minor (like yama) module
instead of a major (like AppArmor) module?

>  	config DEFAULT_SECURITY_DAC
>  		bool "Unix Discretionary Access Controls"
>  
> @@ -275,6 +280,7 @@ config DEFAULT_SECURITY
>  	default "smack" if DEFAULT_SECURITY_SMACK
>  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
>  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
> +	default "whiteegret" if DEFAULT_SECURITY_WHITEEGRET
>  	default "" if DEFAULT_SECURITY_DAC
>  
>  endmenu
> diff --git a/security/Makefile b/security/Makefile
> index 4d2d3782ddef..3a8249c77288 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
>  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
>  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
>  subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
> +subdir-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret
>  
>  # always enable default capabilities
>  obj-y					+= commoncap.o
> @@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
>  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
>  obj-$(CONFIG_SECURITY_YAMA)		+= yama/
>  obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
> +obj-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret/
>  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
>  
>  # Object integrity file lists
> diff --git a/security/whiteegret/Kconfig b/security/whiteegret/Kconfig
> new file mode 100644
> index 000000000000..32845977745f
> --- /dev/null
> +++ b/security/whiteegret/Kconfig
> @@ -0,0 +1,11 @@
> +config SECURITY_WHITEEGRET
> +        bool "WhiteEgret support"
> +        depends on SECURITY
> +        default n
> +        help
> +	  This enables the WhiteEgret security module.
> +	  WhiteEgret provides a whitelisting execution control capability,
> +	  which helps stop the execution of unauthorized software
> +	  such as malware.
> +	  You will also need a user application and an execution whitelist.
> +          If you are unsure how to answer this question, answer N.
> diff --git a/security/whiteegret/Makefile b/security/whiteegret/Makefile
> new file mode 100644
> index 000000000000..16bd3afd9324
> --- /dev/null
> +++ b/security/whiteegret/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_SECURITY_WHITEEGRET) += whiteegret.o
> +whiteegret-y := init.o main.o request.o we_fs.o
> diff --git a/security/whiteegret/init.c b/security/whiteegret/init.c
> new file mode 100644
> index 000000000000..3691cca6bc27
> --- /dev/null
> +++ b/security/whiteegret/init.c
> @@ -0,0 +1,75 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#define pr_fmt(fmt) "WhiteEgret: " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/security.h>
> +#include <linux/fs.h>
> +#include "we.h"
> +
> +#include <linux/lsm_hooks.h>
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("WhiteEgret Linux Security Module");
> +
> +static int we_security_bprm_check(struct linux_binprm *bprm)
> +{
> +	if (we_security_bprm_check_main(bprm) == -EACCES)
> +		return -EACCES;
> +
> +	return 0;
> +}
> +
> +static int we_security_mmap_check(struct file *file, unsigned long reqprot,
> +		unsigned long prot, unsigned long flags)
> +{
> +	if (we_security_mmap_check_main(file, reqprot, flags) == -EACCES)
> +		return -EACCES;
> +
> +	return 0;
> +}
> +
> +static struct security_hook_list we_hooks[] = {
> +	LSM_HOOK_INIT(bprm_check_security, we_security_bprm_check),
> +	LSM_HOOK_INIT(mmap_file, we_security_mmap_check),
> +};
> +
> +static int __init we_init(void)
> +{
> +	int rc;
> +
> +	if (!security_module_enable("whiteegret"))
> +		return 0;
> +
> +	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks), "whiteegret");
> +
> +	rc = we_specific_init();
> +	if (rc) {
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		return rc;
> +	}
> +
> +	pr_warn("WhiteEgret (LSM) initialized.\n");
> +
> +	return 0;
> +}
> +
> +static void __exit we_exit(void)
> +{
> +	we_specific_exit();
> +
> +	pr_warn("WhiteEgret (LSM) exited.\n");
> +}
> +
> +module_init(we_init);
> +module_exit(we_exit);
> diff --git a/security/whiteegret/main.c b/security/whiteegret/main.c
> new file mode 100644
> index 000000000000..f60e1d325011
> --- /dev/null
> +++ b/security/whiteegret/main.c
> @@ -0,0 +1,251 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#define pr_fmt(fmt) "WhiteEgret: " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/semaphore.h>
> +#include <linux/binfmts.h>
> +#include <linux/dcache.h>
> +#include <linux/fs.h>
> +#include <linux/mman.h>
> +#include "we.h"
> +#include "request.h"
> +
> +#include <linux/sched.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include "we_fs.h"
> +
> +
> +static int send_receive_we_obj_info(
> +		struct we_obj_info *we_obj_info, int *checkresult);
> +
> +/**
> + * we_specific_init - Initialize fs.
> + *
> + * Returns 0.
> + */
> +int we_specific_init(void)
> +{
> +	int rc = 0;
> +
> +	rc = we_fs_init();
> +	if (rc < 0) {
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		return rc;
> +	}
> +
> +	we_req_q_head_init();
> +
> +	return 0;
> +}
> +
> +/**
> + * we_specific_exit - Nothing to do in the implementation.
> + *
> + * Returns 0.
> + */
> +int we_specific_exit(void)
> +{
> +	return 0;
> +}
> +
> +/**
> + * we_check_main - Common function for security_bprm_check and mmap_file.
> + *
> + * @file: Pointer to struct file.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int we_check_main(struct file *file)
> +{
> +	struct inode *inode;
> +	struct we_obj_info we_obj_info;
> +	char *pathnamebuf;
> +	char *new_pathnamebuf;
> +	char *pathname;
> +	char *shortnamebuf;
> +	int pathsize;
> +	int rc;
> +	int i;
> +	int checkresult;
> +
> +	if (unlikely(file == NULL))
> +		return 0;
> +
> +	pathsize = EXPECTPATHSIZE;
> +	pathnamebuf = kmalloc(pathsize, GFP_KERNEL);
> +	if (unlikely(!pathnamebuf)) {
> +		rc = -ENOMEM;
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		goto failure;
> +	}
> +	while (pathsize <= MAXPATHSIZE) {
> +		pathname = d_absolute_path(&file->f_path, pathnamebuf,
> +				pathsize-1);
> +		if (!IS_ERR(pathname))
> +			break;
> +
> +		pathsize += ADDEDEXPECTPATHSIZE;
> +		new_pathnamebuf = krealloc(pathnamebuf, pathsize,
> +				GFP_KERNEL);
> +		if (unlikely(!new_pathnamebuf)) {
> +			rc = -ENOMEM;
> +			pr_err("error %d at %d in %s\n", rc,
> +					__LINE__, __FILE__);
> +			goto failure;
> +		}
> +		pathnamebuf = new_pathnamebuf;
> +	}
> +	if (unlikely(pathsize >= MAXPATHSIZE)) {
> +		rc = -ENOMEM;
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		goto failure;
> +	}
> +
> +	shortnamebuf = pathname;
> +	for (i = 0; i < pathsize; i++) {
> +		if (pathname[i] == '\0')
> +			break;
> +		if (pathname[i] == '/')
> +			shortnamebuf = pathname + (i + 1);
> +	}
> +	strncpy(we_obj_info.shortname, shortnamebuf, SHORTNAMELENGTH);
> +	we_obj_info.path = pathname;
> +	inode = file_inode(file);
> +	we_obj_info.ino = inode->i_ino;
> +	we_obj_info.dmajor = MAJOR(inode->i_sb->s_dev);
> +	we_obj_info.dminor = MINOR(inode->i_sb->s_dev);
> +	we_obj_info.pid = current->pid;
> +	we_obj_info.pathsize = strlen(pathname);
> +	we_obj_info.ppid = current->tgid;
> +
> +	rc = send_receive_we_obj_info(&we_obj_info, &checkresult);
> +	if (rc < 0)
> +		goto failure;
> +
> +	rc = checkresult;
> +
> +	if (rc == -EACCES)
> +		pr_warn("block %s, ino=%ld, devno=0x%x.\n",
> +			pathname, we_obj_info.ino,
> +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> +	else
> +		pr_info("permit %s, ino=%ld, devno=0x%x.\n",
> +			pathname, we_obj_info.ino,
> +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> +
> +failure:
> +	if (pathnamebuf != NULL) {
> +		kfree(pathnamebuf);
> +		pathnamebuf = NULL;
> +	}
> +
> +	if ((rc != 0) && (rc != -EACCES))
> +		pr_warn("Checking white list does not work.\n");
> +
> +	return rc;
> +}
> +
> +/**
> + * send_receive_we_obj_info - Send message and wait.
> + *
> + * @we_obj_info: Pointer to struct we_obj_info.
> + * @result: Pointer to result of matching to white list.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +static int send_receive_we_obj_info(
> +		struct we_obj_info *we_obj_info, int *checkresult)
> +{
> +	int i;
> +	int rc;
> +	struct we_req_q req;
> +
> +	we_req_q_init(&req, we_obj_info);
> +
> +	if ((we_req_q_search(&(req.data))) == NULL) {
> +		rc = we_req_q_push(&req);
> +		if (rc < 0) {
> +			pr_err("error %d at %d in %s\n", rc,
> +					__LINE__, __FILE__);
> +			goto failure;
> +		}
> +	}
> +
> +	for (i = 0; i < MAXCOMRETRY; i++) {
> +		rc = send_we_obj_info(&req);
> +
> +		if (likely(req.finish_flag == START_EXEC)) {
> +			break;
> +		} else if (unlikely(rc == -ERESTARTSYS)) {
> +			pr_info("Signal detected (%d)\n", rc);
> +			break;
> +		}
> +	}
> +
> +	we_req_q_pop(&req);
> +
> +	if (unlikely(i >= MAXCOMRETRY) && req.finish_flag != START_EXEC) {
> +		rc = -EINVAL;
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +	}
> +
> +	*checkresult = req.permit;
> +
> +failure:
> +	return rc;
> +}
> +
> +/**
> + * we_security_bprm_check_main - Target for security_bprm_check.
> + *
> + * @bprm: Pointer to struct linux_binprm.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int we_security_bprm_check_main(struct linux_binprm *bprm)
> +{
> +	if (unlikely(!from_task))
> +		return 0;
> +
> +	return we_check_main(bprm->file);
> +}
> +
> +/**
> + * we_security_mmap_check_main - Target for mmap_file.
> + *
> + * @file: Pointer to struct file to map.
> + * @reqprot: Protection requested by the application.
> + * @flags: Operational flags.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int we_security_mmap_check_main(struct file *file,
> +		unsigned long reqprot, unsigned long flags)
> +{
> +	if (unlikely(!from_task))
> +		return 0;
> +
> +	if (!(reqprot & PROT_EXEC))
> +		return 0;
> +
> +	if ((flags & MAP_EXECUTABLE))
> +		return 0;
> +
> +	if (!file)
> +		return 0;
> +
> +	if (!file->f_path.dentry)
> +		return 0;
> +
> +	return we_check_main(file);
> +}
> diff --git a/security/whiteegret/request.c b/security/whiteegret/request.c
> new file mode 100644
> index 000000000000..7d28e133ebd6
> --- /dev/null
> +++ b/security/whiteegret/request.c
> @@ -0,0 +1,151 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/rwlock_types.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include "request.h"
> +
> +struct we_req_q_head we_q_head;
> +
> +static int match_we_req_data(struct we_req_data *data1,
> +		struct we_req_data *data2);
> +
> +/**
> + * we_req_q_init - Initialize the global variable we_q_head.
> + *
> + * Returns 0.
> + */
> +int we_req_q_head_init(void)
> +{
> +	rwlock_init(&(we_q_head.lock));
> +	INIT_LIST_HEAD(&(we_q_head.head));
> +	init_waitqueue_head(&(we_q_head.waitq));
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_push - Add queue to tail of the list.
> + *
> + * @queue: Pointer to we_req_q to be added to the list.
> + *
> + * Returns 0.
> + */
> +int we_req_q_push(struct we_req_q *queue)
> +{
> +	write_lock(&(we_q_head.lock));
> +	list_add_tail(&(queue->queue), &we_q_head.head);
> +	write_unlock(&(we_q_head.lock));
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_search - Search data in the list.
> + *
> + * @data: Pointer to we_req_data to be searched in the list.
> + *
> + * Returns pointer to data if data is found in the list,
> + * NULL otherwise.
> + */
> +struct we_req_q *we_req_q_search(struct we_req_data *data)
> +{
> +	struct list_head *p;
> +	struct we_req_q *req;
> +
> +	read_lock(&(we_q_head.lock));
> +
> +	list_for_each(p, &(we_q_head.head)) {
> +		req = list_entry(p, struct we_req_q, queue);
> +
> +		if (match_we_req_data(data, &(req->data))) {
> +			read_unlock(&(we_q_head.lock));
> +			return req;
> +		}
> +	}
> +
> +	read_unlock(&(we_q_head.lock));
> +
> +	return NULL;
> +}
> +
> +/**
> + * we_req_q_init - Initialize queue.
> + *
> + * @req: Pointer to we_req_q to be initialized.
> + * @info: Pointer to we_obj_info.
> + *
> + * Returns 0.
> + */
> +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info)
> +{
> +	req->finish_flag = STOP_EXEC;
> +	req->data.we_obj_info = info;
> +	req->permit = -EACCES;
> +	init_waitqueue_head(&req->waitq);
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_pop - Delete queue in the list.
> + *
> + * Returns 0.
> + */
> +int we_req_q_pop(struct we_req_q *queue)
> +{
> +	write_lock(&(we_q_head.lock));
> +	list_del(&queue->queue);
> +	write_unlock(&(we_q_head.lock));
> +
> +	return 0;
> +}
> +
> +/**
> + * match_we_req_data - Compare two we_req_data data.
> + *
> + * @data1: Pointer to we_req_data
> + * @data2: Pointer to we_req_data
> + *
> + * Returns 1 if ppid of both we_req_data data are equal,
> + * 0 otherwise.
> + */
> +static int match_we_req_data(struct we_req_data *data1,
> +		struct we_req_data *data2)
> +{
> +	if (data1->we_obj_info->ppid == data2->we_obj_info->ppid)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_cleanup - Cleaning up queues.
> + *
> + * Returns 0.
> + */
> +int we_req_q_cleanup(void)
> +{
> +	struct list_head *p;
> +	struct we_req_q *req;
> +
> +	write_lock(&(we_q_head.lock));
> +	list_for_each(p, &we_q_head.head) {
> +		req = list_entry(p, struct we_req_q, queue);
> +		req->finish_flag = START_EXEC;
> +		req->permit = -EINVAL;
> +	}
> +	write_unlock(&(we_q_head.lock));
> +
> +	return 0;
> +}
> diff --git a/security/whiteegret/request.h b/security/whiteegret/request.h
> new file mode 100644
> index 000000000000..4a735fc70c63
> --- /dev/null
> +++ b/security/whiteegret/request.h
> @@ -0,0 +1,52 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _REQUEST_H
> +#define _REQUEST_H
> +
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +
> +#include "we.h"
> +
> +struct we_req_q_head {
> +	struct list_head head;
> +	rwlock_t lock;
> +	wait_queue_head_t waitq;
> +};
> +
> +
> +#define STOP_EXEC  0
> +#define START_EXEC 1
> +
> +extern struct we_req_q_head we_q_head;
> +
> +/* Structure for information of request from kernel space to user space */
> +struct we_req_data {
> +	struct we_obj_info *we_obj_info;
> +};
> +
> +struct we_req_q {
> +	struct list_head queue;
> +	int finish_flag;
> +	struct we_req_data data;
> +	int permit;
> +	wait_queue_head_t waitq;
> +};
> +
> +int we_req_q_pop(struct we_req_q *queue);
> +int we_req_q_cleanup(void);
> +
> +int we_req_q_head_init(void);
> +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info);
> +int we_req_q_push(struct we_req_q *queue);
> +struct we_req_q *we_req_q_search(struct we_req_data *data);
> +
> +#endif  /* _REQUEST_H */
> diff --git a/security/whiteegret/we.h b/security/whiteegret/we.h
> new file mode 100644
> index 000000000000..fc14e67d4f7d
> --- /dev/null
> +++ b/security/whiteegret/we.h
> @@ -0,0 +1,66 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _WE_H
> +#define _WE_H
> +
> +#include <linux/binfmts.h>
> +
> +/*
> + * Initial size in byte of memory allocation to store the path
> + * of an object file
> + */
> +#define EXPECTPATHSIZE 1023
> +
> +/*
> + * Default size in byte to expand block that stores the path
> + * of an object file when the memory block is too small
> + * to store the path
> + */
> +#define ADDEDEXPECTPATHSIZE 1023
> +
> +/* Maximum length in byte of path of object file */
> +#define MAXPATHSIZE 8184
> +
> +/* Maximum length in byte of name of executable file */
> +#define SHORTNAMELENGTH 256
> +
> +/*
> + * Maximum number of retry for sending the same message
> + * to user whitelisting application
> + */
> +#define MAXCOMRETRY 10
> +
> +/* Timeout value in millisecond to aquire the semaphore */
> +#define WERESULTTIMEOUT 1000
> +
> +/*
> + * Structure for an object to be tested whether it is contained
> + * in the whitelist or not
> + */
> +struct we_obj_info {
> +	unsigned long ino;                /* inode number */
> +	unsigned int dmajor;              /* major version of device number */
> +	unsigned int dminor;              /* minor version of device number */
> +	char shortname[SHORTNAMELENGTH];  /* short name for the object */
> +	int pathsize;
> +	char *path;                       /* full path to the object */
> +	pid_t pid;
> +	pid_t ppid;
> +};
> +
> +int we_security_bprm_check_main(struct linux_binprm *bprm);
> +int we_security_mmap_check_main(struct file *file,
> +		unsigned long reqprot, unsigned long flags);
> +
> +int we_specific_init(void);
> +int we_specific_exit(void);
> +
> +#endif  /* _WE_H */
> diff --git a/security/whiteegret/we_fs.c b/security/whiteegret/we_fs.c
> new file mode 100644
> index 000000000000..27b76f093814
> --- /dev/null
> +++ b/security/whiteegret/we_fs.c
> @@ -0,0 +1,280 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#define pr_fmt(fmt) "WhiteEgret: " fmt
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/security.h>
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/wait.h>
> +#include <linux/sched.h>
> +#include <linux/uaccess.h>
> +#include <linux/cdev.h>
> +
> +#include "we_fs.h"
> +
> +#define static_assert(constexpr) \
> +	char dummy[(constexpr) ? 1 : -1] __attribute__((unused))
> +
> +#define WE_COPY_TO_USER(to, from, ret) \
> +	do { \
> +		static_assert(sizeof((to)) == sizeof((from))); \
> +		(ret) = copy_to_user(&(to), &(from), sizeof(to)); \
> +	} while (0)
> +
> +#define WE_COPY_FROM_USER(to, from, ret) \
> +	do { \
> +		static_assert(sizeof((to)) == sizeof((from))); \
> +		(ret) = copy_from_user(&(to), &(from), sizeof(to)); \
> +	} while (0)
> +
> +static struct we_req_q_head *root;
> +struct task_struct *from_task;
> +static DEFINE_RWLOCK(from_task_lock);
> +
> +static int check_we_pathsize(struct we_req_q *we_req, int size)
> +{
> +	if (size - sizeof(*we_req)
> +			> we_req->data.we_obj_info->pathsize)
> +		return 0;
> +	else
> +		return -1;
> +}
> +
> +static int set_we_req_info(struct we_req_user *user,
> +		struct we_obj_info *info)
> +{
> +	unsigned long ret;
> +
> +	WE_COPY_TO_USER(user->ino, info->ino, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->dmajor, info->dmajor, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->dminor, info->dminor, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->pid, info->pid, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->ppid, info->ppid, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->shortname, info->shortname, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->pathsize, info->pathsize, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	ret = copy_to_user(user->path, info->path, info->pathsize + 1);
> +	if (ret != 0)
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_we_ack(struct we_ack *to, struct we_ack *from)
> +{
> +	unsigned long ret;
> +
> +	WE_COPY_FROM_USER(to->pid, from->pid, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_FROM_USER(to->permit, from->permit, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static struct we_req_user *get_alive_we_req(struct we_req_q_head *root,
> +		void *buf, int size)
> +{
> +	int pathsize;
> +	struct list_head *p;
> +	struct we_req_q *req;
> +	struct we_req_user *user = NULL;
> +
> +	write_lock(&root->lock);
> +	list_for_each(p, &root->head) {
> +		req = list_entry(p, struct we_req_q, queue);
> +		if (req->finish_flag == STOP_EXEC) {
> +			if (unlikely(check_we_pathsize(req, size)))
> +				goto SIZE_ERROR;
> +			user = (struct we_req_user *)buf;
> +			set_we_req_info(user, req->data.we_obj_info);
> +			break;
> +		}
> +	}
> +	write_unlock(&root->lock);
> +
> +	return user;
> +SIZE_ERROR:
> +	pathsize = req->data.we_obj_info->pathsize;
> +	req->permit = -EACCES;
> +	req->finish_flag = START_EXEC;
> +	write_unlock(&root->lock);
> +	pr_err("Path length of exec is too long (%d).\n", pathsize);
> +	return NULL;
> +}
> +
> +static ssize_t send_ack(struct we_req_q_head *root, struct we_ack *ack)
> +{
> +	struct list_head *p;
> +	struct we_req_q *req = NULL, *temp;
> +
> +	write_lock(&root->lock);
> +	list_for_each(p, &root->head) {
> +		temp = list_entry(p, struct we_req_q, queue);
> +		if (temp->data.we_obj_info->pid == ack->pid) {
> +			req = temp;
> +			req->permit = ack->permit;
> +			wake_up_interruptible_sync(&req->waitq);
> +			req->finish_flag = START_EXEC;
> +		}
> +	}
> +	write_unlock(&root->lock);
> +
> +	if (unlikely(!req)) {
> +		pr_warn("%s: can not find we_req. pid(%d)\n",
> +			__func__, ack->pid);
> +		return -EACCES;
> +	}
> +	return sizeof(*ack);
> +}
> +
> +static ssize_t we_driver_read(struct file *file, char *buf,
> +		size_t size, loff_t *off)
> +{
> +	int ret;
> +	struct we_req_user *user;
> +
> +	while (1) {
> +		ret = wait_event_interruptible(root->waitq,
> +				(user = get_alive_we_req(root, buf, size)));
> +		if (unlikely(ret < 0)) {
> +			pr_info("%s: signal (%d)", __func__, ret);
> +			return 0;
> +		}
> +		if (likely(user))
> +			break;
> +	}
> +
> +	return sizeof(*user) + user->pathsize + 1;
> +}
> +
> +static ssize_t we_driver_write(struct file *file, const char *buf,
> +		size_t size, loff_t *off)
> +{
> +	int rc;
> +	ssize_t ret;
> +	struct we_ack ack;
> +
> +	rc = set_we_ack(&ack, (struct we_ack *)((void *)buf));
> +	if (rc < 0)
> +		return (ssize_t)rc;
> +	ret = send_ack(root, &ack);
> +
> +	return ret;
> +}
> +
> +static long we_driver_ioctl(struct file *file,
> +		unsigned int arg0, unsigned long arg1)
> +{
> +	return 0;
> +}
> +
> +static int we_driver_release(struct inode *inode, struct file *filp)
> +{
> +	int ret = 0;
> +
> +	write_lock(&from_task_lock);
> +	if (!from_task) {
> +		pr_warn("WhiteEgret has not started.\n");
> +		ret =  -EACCES;
> +		goto END;
> +	}
> +	if (from_task != current) {
> +		pr_warn("This task is not registered to WhiteEgret.\n");
> +		ret = -EACCES;
> +		goto END;
> +	}
> +	from_task = NULL;
> +	we_req_q_cleanup();
> +END:
> +	write_unlock(&from_task_lock);
> +	return ret;
> +}
> +
> +static int we_driver_open(struct inode *inode, struct file *filp)
> +{
> +	write_lock(&from_task_lock);
> +	if (from_task) {
> +		write_unlock(&(from_task_lock));
> +		pr_warn("WhiteEgret has already started.\n");
> +		return -EACCES;
> +	}
> +
> +	from_task = current;
> +	root = &we_q_head;
> +	write_unlock(&from_task_lock);
> +
> +	return 0;
> +}
> +
> +static const struct file_operations we_driver_fops = {
> +	.owner = THIS_MODULE,
> +	.read = we_driver_read,
> +	.write = we_driver_write,
> +	.unlocked_ioctl = we_driver_ioctl,
> +	.open =  we_driver_open,
> +	.release = we_driver_release,
> +};
> +
> +int we_fs_init(void)
> +{
> +	struct dentry *we_dir;
> +	struct dentry *wecom;
> +
> +	we_dir = securityfs_create_dir(WE_FS_DIR_NAME, NULL);
> +	if (IS_ERR(we_dir))
> +		return PTR_ERR(we_dir);
> +
> +	wecom = securityfs_create_file(WE_DEV_NAME, 0600, we_dir, NULL, &we_driver_fops);
> +	if (IS_ERR(wecom)) {
> +		securityfs_remove(we_dir);
> +		return PTR_ERR(wecom);
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * send_we_obj_info - Wait response from user's whitelisting application.
> + *
> + * @req: Pointer to struct we_req_q.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int send_we_obj_info(struct we_req_q *req)
> +{
> +	/* If there exists queue waiting for this request req done,
> +	 * then wake it up.
> +	 */
> +	if (waitqueue_active(&(we_q_head.waitq)))
> +		wake_up(&(we_q_head.waitq));
> +
> +	return wait_event_interruptible_timeout(req->waitq,
> +			(req->finish_flag == START_EXEC),
> +			WERESULTTIMEOUT);
> +}
> diff --git a/security/whiteegret/we_fs.h b/security/whiteegret/we_fs.h
> new file mode 100644
> index 000000000000..9af245d7aca4
> --- /dev/null
> +++ b/security/whiteegret/we_fs.h
> @@ -0,0 +1,23 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _WE_FS_H
> +#define _WE_FS_H
> +
> +#include "request.h"
> +#include "we_fs_common.h"
> +
> +extern struct task_struct *from_task;
> +
> +int we_fs_init(void);
> +
> +int send_we_obj_info(struct we_req_q *req);
> +
> +#endif  /* _WE_FS_H */
> diff --git a/security/whiteegret/we_fs_common.h b/security/whiteegret/we_fs_common.h
> new file mode 100644
> index 000000000000..259f300d9738
> --- /dev/null
> +++ b/security/whiteegret/we_fs_common.h
> @@ -0,0 +1,36 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _WE_FS_COMMON_H
> +#define _WE_FS_COMMON_H
> +
> +#define WE_FS_DIR_NAME "whiteegret"
> +#define WE_DEV_NAME "wecom"
> +#define WE_DEV_PATH "/sys/kernel/security/"WE_FS_DIR_NAME"/"WE_DEV_NAME
> +
> +#define SHORTNAMELENGTH 256
> +
> +struct we_req_user {
> +	unsigned long ino;
> +	unsigned int dmajor;
> +	unsigned int dminor;
> +	pid_t pid;
> +	pid_t ppid;
> +	char shortname[SHORTNAMELENGTH];
> +	int pathsize;
> +	char path[0];
> +};
> +
> +struct we_ack {
> +	int permit;
> +	pid_t pid;
> +};
> +
> +#endif  /* _WE_FS_COMMON_H */

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
@ 2018-03-01 15:43   ` Casey Schaufler
  0 siblings, 0 replies; 10+ messages in thread
From: Casey Schaufler @ 2018-03-01 15:43 UTC (permalink / raw)
  To: linux-security-module

On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> This RFC provides implementation of WhiteEgret.
>
> Signed-off-by: Masanobu Koike <masanobu2.koike@toshiba.co.jp>
> ---
>  security/Kconfig                   |   6 +
>  security/Makefile                  |   2 +
>  security/whiteegret/Kconfig        |  11 ++
>  security/whiteegret/Makefile       |   2 +
>  security/whiteegret/init.c         |  75 ++++++++++
>  security/whiteegret/main.c         | 251 +++++++++++++++++++++++++++++++++
>  security/whiteegret/request.c      | 151 ++++++++++++++++++++
>  security/whiteegret/request.h      |  52 +++++++
>  security/whiteegret/we.h           |  66 +++++++++
>  security/whiteegret/we_fs.c        | 280 +++++++++++++++++++++++++++++++++++++
>  security/whiteegret/we_fs.h        |  23 +++
>  security/whiteegret/we_fs_common.h |  36 +++++
>  12 files changed, 955 insertions(+)
>  create mode 100644 security/whiteegret/Kconfig
>  create mode 100644 security/whiteegret/Makefile
>  create mode 100644 security/whiteegret/init.c
>  create mode 100644 security/whiteegret/main.c
>  create mode 100644 security/whiteegret/request.c
>  create mode 100644 security/whiteegret/request.h
>  create mode 100644 security/whiteegret/we.h
>  create mode 100644 security/whiteegret/we_fs.c
>  create mode 100644 security/whiteegret/we_fs.h
>  create mode 100644 security/whiteegret/we_fs_common.h
>
> diff --git a/security/Kconfig b/security/Kconfig
> index c4302067a3ad..f17fefecaf84 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -237,6 +237,7 @@ source security/tomoyo/Kconfig
>  source security/apparmor/Kconfig
>  source security/loadpin/Kconfig
>  source security/yama/Kconfig
> +source security/whiteegret/Kconfig
>  
>  source security/integrity/Kconfig
>  
> @@ -246,6 +247,7 @@ choice
>  	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
>  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
>  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> +	default DEFAULT_SECURITY_WHITEEGRET if SECURITY_WHITEEGRET
>  	default DEFAULT_SECURITY_DAC
>  
>  	help
> @@ -264,6 +266,9 @@ choice
>  	config DEFAULT_SECURITY_APPARMOR
>  		bool "AppArmor" if SECURITY_APPARMOR=y
>  
> +	config DEFAULT_SECURITY_WHITEEGRET
> +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> +

I don't see this module using any security blobs. Is there
a reason you're not making this a minor (like yama) module
instead of a major (like AppArmor) module?

>  	config DEFAULT_SECURITY_DAC
>  		bool "Unix Discretionary Access Controls"
>  
> @@ -275,6 +280,7 @@ config DEFAULT_SECURITY
>  	default "smack" if DEFAULT_SECURITY_SMACK
>  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
>  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
> +	default "whiteegret" if DEFAULT_SECURITY_WHITEEGRET
>  	default "" if DEFAULT_SECURITY_DAC
>  
>  endmenu
> diff --git a/security/Makefile b/security/Makefile
> index 4d2d3782ddef..3a8249c77288 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
>  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
>  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
>  subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
> +subdir-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret
>  
>  # always enable default capabilities
>  obj-y					+= commoncap.o
> @@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
>  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
>  obj-$(CONFIG_SECURITY_YAMA)		+= yama/
>  obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
> +obj-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret/
>  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
>  
>  # Object integrity file lists
> diff --git a/security/whiteegret/Kconfig b/security/whiteegret/Kconfig
> new file mode 100644
> index 000000000000..32845977745f
> --- /dev/null
> +++ b/security/whiteegret/Kconfig
> @@ -0,0 +1,11 @@
> +config SECURITY_WHITEEGRET
> +        bool "WhiteEgret support"
> +        depends on SECURITY
> +        default n
> +        help
> +	  This enables the WhiteEgret security module.
> +	  WhiteEgret provides a whitelisting execution control capability,
> +	  which helps stop the execution of unauthorized software
> +	  such as malware.
> +	  You will also need a user application and an execution whitelist.
> +          If you are unsure how to answer this question, answer N.
> diff --git a/security/whiteegret/Makefile b/security/whiteegret/Makefile
> new file mode 100644
> index 000000000000..16bd3afd9324
> --- /dev/null
> +++ b/security/whiteegret/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_SECURITY_WHITEEGRET) += whiteegret.o
> +whiteegret-y := init.o main.o request.o we_fs.o
> diff --git a/security/whiteegret/init.c b/security/whiteegret/init.c
> new file mode 100644
> index 000000000000..3691cca6bc27
> --- /dev/null
> +++ b/security/whiteegret/init.c
> @@ -0,0 +1,75 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#define pr_fmt(fmt) "WhiteEgret: " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/sched.h>
> +#include <linux/security.h>
> +#include <linux/fs.h>
> +#include "we.h"
> +
> +#include <linux/lsm_hooks.h>
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("WhiteEgret Linux Security Module");
> +
> +static int we_security_bprm_check(struct linux_binprm *bprm)
> +{
> +	if (we_security_bprm_check_main(bprm) == -EACCES)
> +		return -EACCES;
> +
> +	return 0;
> +}
> +
> +static int we_security_mmap_check(struct file *file, unsigned long reqprot,
> +		unsigned long prot, unsigned long flags)
> +{
> +	if (we_security_mmap_check_main(file, reqprot, flags) == -EACCES)
> +		return -EACCES;
> +
> +	return 0;
> +}
> +
> +static struct security_hook_list we_hooks[] = {
> +	LSM_HOOK_INIT(bprm_check_security, we_security_bprm_check),
> +	LSM_HOOK_INIT(mmap_file, we_security_mmap_check),
> +};
> +
> +static int __init we_init(void)
> +{
> +	int rc;
> +
> +	if (!security_module_enable("whiteegret"))
> +		return 0;
> +
> +	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks), "whiteegret");
> +
> +	rc = we_specific_init();
> +	if (rc) {
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		return rc;
> +	}
> +
> +	pr_warn("WhiteEgret (LSM) initialized.\n");
> +
> +	return 0;
> +}
> +
> +static void __exit we_exit(void)
> +{
> +	we_specific_exit();
> +
> +	pr_warn("WhiteEgret (LSM) exited.\n");
> +}
> +
> +module_init(we_init);
> +module_exit(we_exit);
> diff --git a/security/whiteegret/main.c b/security/whiteegret/main.c
> new file mode 100644
> index 000000000000..f60e1d325011
> --- /dev/null
> +++ b/security/whiteegret/main.c
> @@ -0,0 +1,251 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#define pr_fmt(fmt) "WhiteEgret: " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/semaphore.h>
> +#include <linux/binfmts.h>
> +#include <linux/dcache.h>
> +#include <linux/fs.h>
> +#include <linux/mman.h>
> +#include "we.h"
> +#include "request.h"
> +
> +#include <linux/sched.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include "we_fs.h"
> +
> +
> +static int send_receive_we_obj_info(
> +		struct we_obj_info *we_obj_info, int *checkresult);
> +
> +/**
> + * we_specific_init - Initialize fs.
> + *
> + * Returns 0.
> + */
> +int we_specific_init(void)
> +{
> +	int rc = 0;
> +
> +	rc = we_fs_init();
> +	if (rc < 0) {
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		return rc;
> +	}
> +
> +	we_req_q_head_init();
> +
> +	return 0;
> +}
> +
> +/**
> + * we_specific_exit - Nothing to do in the implementation.
> + *
> + * Returns 0.
> + */
> +int we_specific_exit(void)
> +{
> +	return 0;
> +}
> +
> +/**
> + * we_check_main - Common function for security_bprm_check and mmap_file.
> + *
> + * @file: Pointer to struct file.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int we_check_main(struct file *file)
> +{
> +	struct inode *inode;
> +	struct we_obj_info we_obj_info;
> +	char *pathnamebuf;
> +	char *new_pathnamebuf;
> +	char *pathname;
> +	char *shortnamebuf;
> +	int pathsize;
> +	int rc;
> +	int i;
> +	int checkresult;
> +
> +	if (unlikely(file == NULL))
> +		return 0;
> +
> +	pathsize = EXPECTPATHSIZE;
> +	pathnamebuf = kmalloc(pathsize, GFP_KERNEL);
> +	if (unlikely(!pathnamebuf)) {
> +		rc = -ENOMEM;
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		goto failure;
> +	}
> +	while (pathsize <= MAXPATHSIZE) {
> +		pathname = d_absolute_path(&file->f_path, pathnamebuf,
> +				pathsize-1);
> +		if (!IS_ERR(pathname))
> +			break;
> +
> +		pathsize += ADDEDEXPECTPATHSIZE;
> +		new_pathnamebuf = krealloc(pathnamebuf, pathsize,
> +				GFP_KERNEL);
> +		if (unlikely(!new_pathnamebuf)) {
> +			rc = -ENOMEM;
> +			pr_err("error %d at %d in %s\n", rc,
> +					__LINE__, __FILE__);
> +			goto failure;
> +		}
> +		pathnamebuf = new_pathnamebuf;
> +	}
> +	if (unlikely(pathsize >= MAXPATHSIZE)) {
> +		rc = -ENOMEM;
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +		goto failure;
> +	}
> +
> +	shortnamebuf = pathname;
> +	for (i = 0; i < pathsize; i++) {
> +		if (pathname[i] == '\0')
> +			break;
> +		if (pathname[i] == '/')
> +			shortnamebuf = pathname + (i + 1);
> +	}
> +	strncpy(we_obj_info.shortname, shortnamebuf, SHORTNAMELENGTH);
> +	we_obj_info.path = pathname;
> +	inode = file_inode(file);
> +	we_obj_info.ino = inode->i_ino;
> +	we_obj_info.dmajor = MAJOR(inode->i_sb->s_dev);
> +	we_obj_info.dminor = MINOR(inode->i_sb->s_dev);
> +	we_obj_info.pid = current->pid;
> +	we_obj_info.pathsize = strlen(pathname);
> +	we_obj_info.ppid = current->tgid;
> +
> +	rc = send_receive_we_obj_info(&we_obj_info, &checkresult);
> +	if (rc < 0)
> +		goto failure;
> +
> +	rc = checkresult;
> +
> +	if (rc == -EACCES)
> +		pr_warn("block %s, ino=%ld, devno=0x%x.\n",
> +			pathname, we_obj_info.ino,
> +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> +	else
> +		pr_info("permit %s, ino=%ld, devno=0x%x.\n",
> +			pathname, we_obj_info.ino,
> +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> +
> +failure:
> +	if (pathnamebuf != NULL) {
> +		kfree(pathnamebuf);
> +		pathnamebuf = NULL;
> +	}
> +
> +	if ((rc != 0) && (rc != -EACCES))
> +		pr_warn("Checking white list does not work.\n");
> +
> +	return rc;
> +}
> +
> +/**
> + * send_receive_we_obj_info - Send message and wait.
> + *
> + * @we_obj_info: Pointer to struct we_obj_info.
> + * @result: Pointer to result of matching to white list.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +static int send_receive_we_obj_info(
> +		struct we_obj_info *we_obj_info, int *checkresult)
> +{
> +	int i;
> +	int rc;
> +	struct we_req_q req;
> +
> +	we_req_q_init(&req, we_obj_info);
> +
> +	if ((we_req_q_search(&(req.data))) == NULL) {
> +		rc = we_req_q_push(&req);
> +		if (rc < 0) {
> +			pr_err("error %d at %d in %s\n", rc,
> +					__LINE__, __FILE__);
> +			goto failure;
> +		}
> +	}
> +
> +	for (i = 0; i < MAXCOMRETRY; i++) {
> +		rc = send_we_obj_info(&req);
> +
> +		if (likely(req.finish_flag == START_EXEC)) {
> +			break;
> +		} else if (unlikely(rc == -ERESTARTSYS)) {
> +			pr_info("Signal detected (%d)\n", rc);
> +			break;
> +		}
> +	}
> +
> +	we_req_q_pop(&req);
> +
> +	if (unlikely(i >= MAXCOMRETRY) && req.finish_flag != START_EXEC) {
> +		rc = -EINVAL;
> +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> +	}
> +
> +	*checkresult = req.permit;
> +
> +failure:
> +	return rc;
> +}
> +
> +/**
> + * we_security_bprm_check_main - Target for security_bprm_check.
> + *
> + * @bprm: Pointer to struct linux_binprm.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int we_security_bprm_check_main(struct linux_binprm *bprm)
> +{
> +	if (unlikely(!from_task))
> +		return 0;
> +
> +	return we_check_main(bprm->file);
> +}
> +
> +/**
> + * we_security_mmap_check_main - Target for mmap_file.
> + *
> + * @file: Pointer to struct file to map.
> + * @reqprot: Protection requested by the application.
> + * @flags: Operational flags.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int we_security_mmap_check_main(struct file *file,
> +		unsigned long reqprot, unsigned long flags)
> +{
> +	if (unlikely(!from_task))
> +		return 0;
> +
> +	if (!(reqprot & PROT_EXEC))
> +		return 0;
> +
> +	if ((flags & MAP_EXECUTABLE))
> +		return 0;
> +
> +	if (!file)
> +		return 0;
> +
> +	if (!file->f_path.dentry)
> +		return 0;
> +
> +	return we_check_main(file);
> +}
> diff --git a/security/whiteegret/request.c b/security/whiteegret/request.c
> new file mode 100644
> index 000000000000..7d28e133ebd6
> --- /dev/null
> +++ b/security/whiteegret/request.c
> @@ -0,0 +1,151 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/rwlock_types.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include "request.h"
> +
> +struct we_req_q_head we_q_head;
> +
> +static int match_we_req_data(struct we_req_data *data1,
> +		struct we_req_data *data2);
> +
> +/**
> + * we_req_q_init - Initialize the global variable we_q_head.
> + *
> + * Returns 0.
> + */
> +int we_req_q_head_init(void)
> +{
> +	rwlock_init(&(we_q_head.lock));
> +	INIT_LIST_HEAD(&(we_q_head.head));
> +	init_waitqueue_head(&(we_q_head.waitq));
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_push - Add queue to tail of the list.
> + *
> + * @queue: Pointer to we_req_q to be added to the list.
> + *
> + * Returns 0.
> + */
> +int we_req_q_push(struct we_req_q *queue)
> +{
> +	write_lock(&(we_q_head.lock));
> +	list_add_tail(&(queue->queue), &we_q_head.head);
> +	write_unlock(&(we_q_head.lock));
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_search - Search data in the list.
> + *
> + * @data: Pointer to we_req_data to be searched in the list.
> + *
> + * Returns pointer to data if data is found in the list,
> + * NULL otherwise.
> + */
> +struct we_req_q *we_req_q_search(struct we_req_data *data)
> +{
> +	struct list_head *p;
> +	struct we_req_q *req;
> +
> +	read_lock(&(we_q_head.lock));
> +
> +	list_for_each(p, &(we_q_head.head)) {
> +		req = list_entry(p, struct we_req_q, queue);
> +
> +		if (match_we_req_data(data, &(req->data))) {
> +			read_unlock(&(we_q_head.lock));
> +			return req;
> +		}
> +	}
> +
> +	read_unlock(&(we_q_head.lock));
> +
> +	return NULL;
> +}
> +
> +/**
> + * we_req_q_init - Initialize queue.
> + *
> + * @req: Pointer to we_req_q to be initialized.
> + * @info: Pointer to we_obj_info.
> + *
> + * Returns 0.
> + */
> +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info)
> +{
> +	req->finish_flag = STOP_EXEC;
> +	req->data.we_obj_info = info;
> +	req->permit = -EACCES;
> +	init_waitqueue_head(&req->waitq);
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_pop - Delete queue in the list.
> + *
> + * Returns 0.
> + */
> +int we_req_q_pop(struct we_req_q *queue)
> +{
> +	write_lock(&(we_q_head.lock));
> +	list_del(&queue->queue);
> +	write_unlock(&(we_q_head.lock));
> +
> +	return 0;
> +}
> +
> +/**
> + * match_we_req_data - Compare two we_req_data data.
> + *
> + * @data1: Pointer to we_req_data
> + * @data2: Pointer to we_req_data
> + *
> + * Returns 1 if ppid of both we_req_data data are equal,
> + * 0 otherwise.
> + */
> +static int match_we_req_data(struct we_req_data *data1,
> +		struct we_req_data *data2)
> +{
> +	if (data1->we_obj_info->ppid == data2->we_obj_info->ppid)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +/**
> + * we_req_q_cleanup - Cleaning up queues.
> + *
> + * Returns 0.
> + */
> +int we_req_q_cleanup(void)
> +{
> +	struct list_head *p;
> +	struct we_req_q *req;
> +
> +	write_lock(&(we_q_head.lock));
> +	list_for_each(p, &we_q_head.head) {
> +		req = list_entry(p, struct we_req_q, queue);
> +		req->finish_flag = START_EXEC;
> +		req->permit = -EINVAL;
> +	}
> +	write_unlock(&(we_q_head.lock));
> +
> +	return 0;
> +}
> diff --git a/security/whiteegret/request.h b/security/whiteegret/request.h
> new file mode 100644
> index 000000000000..4a735fc70c63
> --- /dev/null
> +++ b/security/whiteegret/request.h
> @@ -0,0 +1,52 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _REQUEST_H
> +#define _REQUEST_H
> +
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +
> +#include "we.h"
> +
> +struct we_req_q_head {
> +	struct list_head head;
> +	rwlock_t lock;
> +	wait_queue_head_t waitq;
> +};
> +
> +
> +#define STOP_EXEC  0
> +#define START_EXEC 1
> +
> +extern struct we_req_q_head we_q_head;
> +
> +/* Structure for information of request from kernel space to user space */
> +struct we_req_data {
> +	struct we_obj_info *we_obj_info;
> +};
> +
> +struct we_req_q {
> +	struct list_head queue;
> +	int finish_flag;
> +	struct we_req_data data;
> +	int permit;
> +	wait_queue_head_t waitq;
> +};
> +
> +int we_req_q_pop(struct we_req_q *queue);
> +int we_req_q_cleanup(void);
> +
> +int we_req_q_head_init(void);
> +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info);
> +int we_req_q_push(struct we_req_q *queue);
> +struct we_req_q *we_req_q_search(struct we_req_data *data);
> +
> +#endif  /* _REQUEST_H */
> diff --git a/security/whiteegret/we.h b/security/whiteegret/we.h
> new file mode 100644
> index 000000000000..fc14e67d4f7d
> --- /dev/null
> +++ b/security/whiteegret/we.h
> @@ -0,0 +1,66 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _WE_H
> +#define _WE_H
> +
> +#include <linux/binfmts.h>
> +
> +/*
> + * Initial size in byte of memory allocation to store the path
> + * of an object file
> + */
> +#define EXPECTPATHSIZE 1023
> +
> +/*
> + * Default size in byte to expand block that stores the path
> + * of an object file when the memory block is too small
> + * to store the path
> + */
> +#define ADDEDEXPECTPATHSIZE 1023
> +
> +/* Maximum length in byte of path of object file */
> +#define MAXPATHSIZE 8184
> +
> +/* Maximum length in byte of name of executable file */
> +#define SHORTNAMELENGTH 256
> +
> +/*
> + * Maximum number of retry for sending the same message
> + * to user whitelisting application
> + */
> +#define MAXCOMRETRY 10
> +
> +/* Timeout value in millisecond to aquire the semaphore */
> +#define WERESULTTIMEOUT 1000
> +
> +/*
> + * Structure for an object to be tested whether it is contained
> + * in the whitelist or not
> + */
> +struct we_obj_info {
> +	unsigned long ino;                /* inode number */
> +	unsigned int dmajor;              /* major version of device number */
> +	unsigned int dminor;              /* minor version of device number */
> +	char shortname[SHORTNAMELENGTH];  /* short name for the object */
> +	int pathsize;
> +	char *path;                       /* full path to the object */
> +	pid_t pid;
> +	pid_t ppid;
> +};
> +
> +int we_security_bprm_check_main(struct linux_binprm *bprm);
> +int we_security_mmap_check_main(struct file *file,
> +		unsigned long reqprot, unsigned long flags);
> +
> +int we_specific_init(void);
> +int we_specific_exit(void);
> +
> +#endif  /* _WE_H */
> diff --git a/security/whiteegret/we_fs.c b/security/whiteegret/we_fs.c
> new file mode 100644
> index 000000000000..27b76f093814
> --- /dev/null
> +++ b/security/whiteegret/we_fs.c
> @@ -0,0 +1,280 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#define pr_fmt(fmt) "WhiteEgret: " fmt
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/security.h>
> +#include <linux/init.h>
> +#include <linux/fs.h>
> +#include <linux/wait.h>
> +#include <linux/sched.h>
> +#include <linux/uaccess.h>
> +#include <linux/cdev.h>
> +
> +#include "we_fs.h"
> +
> +#define static_assert(constexpr) \
> +	char dummy[(constexpr) ? 1 : -1] __attribute__((unused))
> +
> +#define WE_COPY_TO_USER(to, from, ret) \
> +	do { \
> +		static_assert(sizeof((to)) == sizeof((from))); \
> +		(ret) = copy_to_user(&(to), &(from), sizeof(to)); \
> +	} while (0)
> +
> +#define WE_COPY_FROM_USER(to, from, ret) \
> +	do { \
> +		static_assert(sizeof((to)) == sizeof((from))); \
> +		(ret) = copy_from_user(&(to), &(from), sizeof(to)); \
> +	} while (0)
> +
> +static struct we_req_q_head *root;
> +struct task_struct *from_task;
> +static DEFINE_RWLOCK(from_task_lock);
> +
> +static int check_we_pathsize(struct we_req_q *we_req, int size)
> +{
> +	if (size - sizeof(*we_req)
> +			> we_req->data.we_obj_info->pathsize)
> +		return 0;
> +	else
> +		return -1;
> +}
> +
> +static int set_we_req_info(struct we_req_user *user,
> +		struct we_obj_info *info)
> +{
> +	unsigned long ret;
> +
> +	WE_COPY_TO_USER(user->ino, info->ino, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->dmajor, info->dmajor, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->dminor, info->dminor, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->pid, info->pid, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->ppid, info->ppid, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->shortname, info->shortname, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_TO_USER(user->pathsize, info->pathsize, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	ret = copy_to_user(user->path, info->path, info->pathsize + 1);
> +	if (ret != 0)
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int set_we_ack(struct we_ack *to, struct we_ack *from)
> +{
> +	unsigned long ret;
> +
> +	WE_COPY_FROM_USER(to->pid, from->pid, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +	WE_COPY_FROM_USER(to->permit, from->permit, ret);
> +	if (ret != 0)
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static struct we_req_user *get_alive_we_req(struct we_req_q_head *root,
> +		void *buf, int size)
> +{
> +	int pathsize;
> +	struct list_head *p;
> +	struct we_req_q *req;
> +	struct we_req_user *user = NULL;
> +
> +	write_lock(&root->lock);
> +	list_for_each(p, &root->head) {
> +		req = list_entry(p, struct we_req_q, queue);
> +		if (req->finish_flag == STOP_EXEC) {
> +			if (unlikely(check_we_pathsize(req, size)))
> +				goto SIZE_ERROR;
> +			user = (struct we_req_user *)buf;
> +			set_we_req_info(user, req->data.we_obj_info);
> +			break;
> +		}
> +	}
> +	write_unlock(&root->lock);
> +
> +	return user;
> +SIZE_ERROR:
> +	pathsize = req->data.we_obj_info->pathsize;
> +	req->permit = -EACCES;
> +	req->finish_flag = START_EXEC;
> +	write_unlock(&root->lock);
> +	pr_err("Path length of exec is too long (%d).\n", pathsize);
> +	return NULL;
> +}
> +
> +static ssize_t send_ack(struct we_req_q_head *root, struct we_ack *ack)
> +{
> +	struct list_head *p;
> +	struct we_req_q *req = NULL, *temp;
> +
> +	write_lock(&root->lock);
> +	list_for_each(p, &root->head) {
> +		temp = list_entry(p, struct we_req_q, queue);
> +		if (temp->data.we_obj_info->pid == ack->pid) {
> +			req = temp;
> +			req->permit = ack->permit;
> +			wake_up_interruptible_sync(&req->waitq);
> +			req->finish_flag = START_EXEC;
> +		}
> +	}
> +	write_unlock(&root->lock);
> +
> +	if (unlikely(!req)) {
> +		pr_warn("%s: can not find we_req. pid(%d)\n",
> +			__func__, ack->pid);
> +		return -EACCES;
> +	}
> +	return sizeof(*ack);
> +}
> +
> +static ssize_t we_driver_read(struct file *file, char *buf,
> +		size_t size, loff_t *off)
> +{
> +	int ret;
> +	struct we_req_user *user;
> +
> +	while (1) {
> +		ret = wait_event_interruptible(root->waitq,
> +				(user = get_alive_we_req(root, buf, size)));
> +		if (unlikely(ret < 0)) {
> +			pr_info("%s: signal (%d)", __func__, ret);
> +			return 0;
> +		}
> +		if (likely(user))
> +			break;
> +	}
> +
> +	return sizeof(*user) + user->pathsize + 1;
> +}
> +
> +static ssize_t we_driver_write(struct file *file, const char *buf,
> +		size_t size, loff_t *off)
> +{
> +	int rc;
> +	ssize_t ret;
> +	struct we_ack ack;
> +
> +	rc = set_we_ack(&ack, (struct we_ack *)((void *)buf));
> +	if (rc < 0)
> +		return (ssize_t)rc;
> +	ret = send_ack(root, &ack);
> +
> +	return ret;
> +}
> +
> +static long we_driver_ioctl(struct file *file,
> +		unsigned int arg0, unsigned long arg1)
> +{
> +	return 0;
> +}
> +
> +static int we_driver_release(struct inode *inode, struct file *filp)
> +{
> +	int ret = 0;
> +
> +	write_lock(&from_task_lock);
> +	if (!from_task) {
> +		pr_warn("WhiteEgret has not started.\n");
> +		ret =  -EACCES;
> +		goto END;
> +	}
> +	if (from_task != current) {
> +		pr_warn("This task is not registered to WhiteEgret.\n");
> +		ret = -EACCES;
> +		goto END;
> +	}
> +	from_task = NULL;
> +	we_req_q_cleanup();
> +END:
> +	write_unlock(&from_task_lock);
> +	return ret;
> +}
> +
> +static int we_driver_open(struct inode *inode, struct file *filp)
> +{
> +	write_lock(&from_task_lock);
> +	if (from_task) {
> +		write_unlock(&(from_task_lock));
> +		pr_warn("WhiteEgret has already started.\n");
> +		return -EACCES;
> +	}
> +
> +	from_task = current;
> +	root = &we_q_head;
> +	write_unlock(&from_task_lock);
> +
> +	return 0;
> +}
> +
> +static const struct file_operations we_driver_fops = {
> +	.owner = THIS_MODULE,
> +	.read = we_driver_read,
> +	.write = we_driver_write,
> +	.unlocked_ioctl = we_driver_ioctl,
> +	.open =  we_driver_open,
> +	.release = we_driver_release,
> +};
> +
> +int we_fs_init(void)
> +{
> +	struct dentry *we_dir;
> +	struct dentry *wecom;
> +
> +	we_dir = securityfs_create_dir(WE_FS_DIR_NAME, NULL);
> +	if (IS_ERR(we_dir))
> +		return PTR_ERR(we_dir);
> +
> +	wecom = securityfs_create_file(WE_DEV_NAME, 0600, we_dir, NULL, &we_driver_fops);
> +	if (IS_ERR(wecom)) {
> +		securityfs_remove(we_dir);
> +		return PTR_ERR(wecom);
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * send_we_obj_info - Wait response from user's whitelisting application.
> + *
> + * @req: Pointer to struct we_req_q.
> + *
> + * Returns 0 if succeeded, < 0 otherwise.
> + */
> +int send_we_obj_info(struct we_req_q *req)
> +{
> +	/* If there exists queue waiting for this request req done,
> +	 * then wake it up.
> +	 */
> +	if (waitqueue_active(&(we_q_head.waitq)))
> +		wake_up(&(we_q_head.waitq));
> +
> +	return wait_event_interruptible_timeout(req->waitq,
> +			(req->finish_flag == START_EXEC),
> +			WERESULTTIMEOUT);
> +}
> diff --git a/security/whiteegret/we_fs.h b/security/whiteegret/we_fs.h
> new file mode 100644
> index 000000000000..9af245d7aca4
> --- /dev/null
> +++ b/security/whiteegret/we_fs.h
> @@ -0,0 +1,23 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _WE_FS_H
> +#define _WE_FS_H
> +
> +#include "request.h"
> +#include "we_fs_common.h"
> +
> +extern struct task_struct *from_task;
> +
> +int we_fs_init(void);
> +
> +int send_we_obj_info(struct we_req_q *req);
> +
> +#endif  /* _WE_FS_H */
> diff --git a/security/whiteegret/we_fs_common.h b/security/whiteegret/we_fs_common.h
> new file mode 100644
> index 000000000000..259f300d9738
> --- /dev/null
> +++ b/security/whiteegret/we_fs_common.h
> @@ -0,0 +1,36 @@
> +/*
> + * WhiteEgret Linux Security Module
> + *
> + * Copyright (C) 2017-2018 Toshiba Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation, version 2.
> + */
> +
> +#ifndef _WE_FS_COMMON_H
> +#define _WE_FS_COMMON_H
> +
> +#define WE_FS_DIR_NAME "whiteegret"
> +#define WE_DEV_NAME "wecom"
> +#define WE_DEV_PATH "/sys/kernel/security/"WE_FS_DIR_NAME"/"WE_DEV_NAME
> +
> +#define SHORTNAMELENGTH 256
> +
> +struct we_req_user {
> +	unsigned long ino;
> +	unsigned int dmajor;
> +	unsigned int dminor;
> +	pid_t pid;
> +	pid_t ppid;
> +	char shortname[SHORTNAMELENGTH];
> +	int pathsize;
> +	char path[0];
> +};
> +
> +struct we_ack {
> +	int permit;
> +	pid_t pid;
> +};
> +
> +#endif  /* _WE_FS_COMMON_H */

--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
  2018-03-01 15:43   ` Casey Schaufler
@ 2018-03-02  3:57     ` masanobu2.koike at toshiba.co.jp
  -1 siblings, 0 replies; 10+ messages in thread
From: masanobu2.koike @ 2018-03-02  3:57 UTC (permalink / raw)
  To: casey, jmorris, serge, linux-security-module, linux-kernel


On Friday, March 02, 2018 12:43 AM, Casey Schaufler wrote:
> On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> > This RFC provides implementation of WhiteEgret.
> >
> > Signed-off-by: Masanobu Koike <masanobu2.koike@toshiba.co.jp>
> > ---
> >  security/Kconfig                   |   6 +
> >  security/Makefile                  |   2 +
> >  security/whiteegret/Kconfig        |  11 ++
> >  security/whiteegret/Makefile       |   2 +
> >  security/whiteegret/init.c         |  75 ++++++++++
> >  security/whiteegret/main.c         | 251
> +++++++++++++++++++++++++++++++++
> >  security/whiteegret/request.c      | 151 ++++++++++++++++++++
> >  security/whiteegret/request.h      |  52 +++++++
> >  security/whiteegret/we.h           |  66 +++++++++
> >  security/whiteegret/we_fs.c        | 280
> +++++++++++++++++++++++++++++++++++++
> >  security/whiteegret/we_fs.h        |  23 +++
> >  security/whiteegret/we_fs_common.h |  36 +++++
> >  12 files changed, 955 insertions(+)
> >  create mode 100644 security/whiteegret/Kconfig
> >  create mode 100644 security/whiteegret/Makefile
> >  create mode 100644 security/whiteegret/init.c
> >  create mode 100644 security/whiteegret/main.c
> >  create mode 100644 security/whiteegret/request.c
> >  create mode 100644 security/whiteegret/request.h
> >  create mode 100644 security/whiteegret/we.h
> >  create mode 100644 security/whiteegret/we_fs.c
> >  create mode 100644 security/whiteegret/we_fs.h
> >  create mode 100644 security/whiteegret/we_fs_common.h
> >
> > diff --git a/security/Kconfig b/security/Kconfig
> > index c4302067a3ad..f17fefecaf84 100644
> > --- a/security/Kconfig
> > +++ b/security/Kconfig
> > @@ -237,6 +237,7 @@ source security/tomoyo/Kconfig
> >  source security/apparmor/Kconfig
> >  source security/loadpin/Kconfig
> >  source security/yama/Kconfig
> > +source security/whiteegret/Kconfig
> >
> >  source security/integrity/Kconfig
> >
> > @@ -246,6 +247,7 @@ choice
> >  	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
> >  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
> >  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> > +	default DEFAULT_SECURITY_WHITEEGRET if SECURITY_WHITEEGRET
> >  	default DEFAULT_SECURITY_DAC
> >
> >  	help
> > @@ -264,6 +266,9 @@ choice
> >  	config DEFAULT_SECURITY_APPARMOR
> >  		bool "AppArmor" if SECURITY_APPARMOR=y
> >
> > +	config DEFAULT_SECURITY_WHITEEGRET
> > +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> > +
> 
> I don't see this module using any security blobs. Is there
> a reason you're not making this a minor (like yama) module
> instead of a major (like AppArmor) module?

Thank you for your suggestion.
We are now developing WhiteEgret on the environment
it works certainly.

Masanobu Koike

> 
> >  	config DEFAULT_SECURITY_DAC
> >  		bool "Unix Discretionary Access Controls"
> >
> > @@ -275,6 +280,7 @@ config DEFAULT_SECURITY
> >  	default "smack" if DEFAULT_SECURITY_SMACK
> >  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
> >  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
> > +	default "whiteegret" if DEFAULT_SECURITY_WHITEEGRET
> >  	default "" if DEFAULT_SECURITY_DAC
> >
> >  endmenu
> > diff --git a/security/Makefile b/security/Makefile
> > index 4d2d3782ddef..3a8249c77288 100644
> > --- a/security/Makefile
> > +++ b/security/Makefile
> > @@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
> >  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
> >  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
> >  subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
> > +subdir-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret
> >
> >  # always enable default capabilities
> >  obj-y					+= commoncap.o
> > @@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)		+=
> tomoyo/
> >  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
> >  obj-$(CONFIG_SECURITY_YAMA)		+= yama/
> >  obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
> > +obj-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret/
> >  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
> >
> >  # Object integrity file lists
> > diff --git a/security/whiteegret/Kconfig b/security/whiteegret/Kconfig
> > new file mode 100644
> > index 000000000000..32845977745f
> > --- /dev/null
> > +++ b/security/whiteegret/Kconfig
> > @@ -0,0 +1,11 @@
> > +config SECURITY_WHITEEGRET
> > +        bool "WhiteEgret support"
> > +        depends on SECURITY
> > +        default n
> > +        help
> > +	  This enables the WhiteEgret security module.
> > +	  WhiteEgret provides a whitelisting execution control
> capability,
> > +	  which helps stop the execution of unauthorized software
> > +	  such as malware.
> > +	  You will also need a user application and an execution whitelist.
> > +          If you are unsure how to answer this question, answer N.
> > diff --git a/security/whiteegret/Makefile
> b/security/whiteegret/Makefile
> > new file mode 100644
> > index 000000000000..16bd3afd9324
> > --- /dev/null
> > +++ b/security/whiteegret/Makefile
> > @@ -0,0 +1,2 @@
> > +obj-$(CONFIG_SECURITY_WHITEEGRET) += whiteegret.o
> > +whiteegret-y := init.o main.o request.o we_fs.o
> > diff --git a/security/whiteegret/init.c b/security/whiteegret/init.c
> > new file mode 100644
> > index 000000000000..3691cca6bc27
> > --- /dev/null
> > +++ b/security/whiteegret/init.c
> > @@ -0,0 +1,75 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#define pr_fmt(fmt) "WhiteEgret: " fmt
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/sched.h>
> > +#include <linux/security.h>
> > +#include <linux/fs.h>
> > +#include "we.h"
> > +
> > +#include <linux/lsm_hooks.h>
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("WhiteEgret Linux Security Module");
> > +
> > +static int we_security_bprm_check(struct linux_binprm *bprm)
> > +{
> > +	if (we_security_bprm_check_main(bprm) == -EACCES)
> > +		return -EACCES;
> > +
> > +	return 0;
> > +}
> > +
> > +static int we_security_mmap_check(struct file *file, unsigned long
> reqprot,
> > +		unsigned long prot, unsigned long flags)
> > +{
> > +	if (we_security_mmap_check_main(file, reqprot, flags) == -EACCES)
> > +		return -EACCES;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct security_hook_list we_hooks[] = {
> > +	LSM_HOOK_INIT(bprm_check_security, we_security_bprm_check),
> > +	LSM_HOOK_INIT(mmap_file, we_security_mmap_check),
> > +};
> > +
> > +static int __init we_init(void)
> > +{
> > +	int rc;
> > +
> > +	if (!security_module_enable("whiteegret"))
> > +		return 0;
> > +
> > +	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks),
> "whiteegret");
> > +
> > +	rc = we_specific_init();
> > +	if (rc) {
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		return rc;
> > +	}
> > +
> > +	pr_warn("WhiteEgret (LSM) initialized.\n");
> > +
> > +	return 0;
> > +}
> > +
> > +static void __exit we_exit(void)
> > +{
> > +	we_specific_exit();
> > +
> > +	pr_warn("WhiteEgret (LSM) exited.\n");
> > +}
> > +
> > +module_init(we_init);
> > +module_exit(we_exit);
> > diff --git a/security/whiteegret/main.c b/security/whiteegret/main.c
> > new file mode 100644
> > index 000000000000..f60e1d325011
> > --- /dev/null
> > +++ b/security/whiteegret/main.c
> > @@ -0,0 +1,251 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#define pr_fmt(fmt) "WhiteEgret: " fmt
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/semaphore.h>
> > +#include <linux/binfmts.h>
> > +#include <linux/dcache.h>
> > +#include <linux/fs.h>
> > +#include <linux/mman.h>
> > +#include "we.h"
> > +#include "request.h"
> > +
> > +#include <linux/sched.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include "we_fs.h"
> > +
> > +
> > +static int send_receive_we_obj_info(
> > +		struct we_obj_info *we_obj_info, int *checkresult);
> > +
> > +/**
> > + * we_specific_init - Initialize fs.
> > + *
> > + * Returns 0.
> > + */
> > +int we_specific_init(void)
> > +{
> > +	int rc = 0;
> > +
> > +	rc = we_fs_init();
> > +	if (rc < 0) {
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		return rc;
> > +	}
> > +
> > +	we_req_q_head_init();
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_specific_exit - Nothing to do in the implementation.
> > + *
> > + * Returns 0.
> > + */
> > +int we_specific_exit(void)
> > +{
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_check_main - Common function for security_bprm_check and mmap_file.
> > + *
> > + * @file: Pointer to struct file.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int we_check_main(struct file *file)
> > +{
> > +	struct inode *inode;
> > +	struct we_obj_info we_obj_info;
> > +	char *pathnamebuf;
> > +	char *new_pathnamebuf;
> > +	char *pathname;
> > +	char *shortnamebuf;
> > +	int pathsize;
> > +	int rc;
> > +	int i;
> > +	int checkresult;
> > +
> > +	if (unlikely(file == NULL))
> > +		return 0;
> > +
> > +	pathsize = EXPECTPATHSIZE;
> > +	pathnamebuf = kmalloc(pathsize, GFP_KERNEL);
> > +	if (unlikely(!pathnamebuf)) {
> > +		rc = -ENOMEM;
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		goto failure;
> > +	}
> > +	while (pathsize <= MAXPATHSIZE) {
> > +		pathname = d_absolute_path(&file->f_path, pathnamebuf,
> > +				pathsize-1);
> > +		if (!IS_ERR(pathname))
> > +			break;
> > +
> > +		pathsize += ADDEDEXPECTPATHSIZE;
> > +		new_pathnamebuf = krealloc(pathnamebuf, pathsize,
> > +				GFP_KERNEL);
> > +		if (unlikely(!new_pathnamebuf)) {
> > +			rc = -ENOMEM;
> > +			pr_err("error %d at %d in %s\n", rc,
> > +					__LINE__, __FILE__);
> > +			goto failure;
> > +		}
> > +		pathnamebuf = new_pathnamebuf;
> > +	}
> > +	if (unlikely(pathsize >= MAXPATHSIZE)) {
> > +		rc = -ENOMEM;
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		goto failure;
> > +	}
> > +
> > +	shortnamebuf = pathname;
> > +	for (i = 0; i < pathsize; i++) {
> > +		if (pathname[i] == '\0')
> > +			break;
> > +		if (pathname[i] == '/')
> > +			shortnamebuf = pathname + (i + 1);
> > +	}
> > +	strncpy(we_obj_info.shortname, shortnamebuf, SHORTNAMELENGTH);
> > +	we_obj_info.path = pathname;
> > +	inode = file_inode(file);
> > +	we_obj_info.ino = inode->i_ino;
> > +	we_obj_info.dmajor = MAJOR(inode->i_sb->s_dev);
> > +	we_obj_info.dminor = MINOR(inode->i_sb->s_dev);
> > +	we_obj_info.pid = current->pid;
> > +	we_obj_info.pathsize = strlen(pathname);
> > +	we_obj_info.ppid = current->tgid;
> > +
> > +	rc = send_receive_we_obj_info(&we_obj_info, &checkresult);
> > +	if (rc < 0)
> > +		goto failure;
> > +
> > +	rc = checkresult;
> > +
> > +	if (rc == -EACCES)
> > +		pr_warn("block %s, ino=%ld, devno=0x%x.\n",
> > +			pathname, we_obj_info.ino,
> > +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> > +	else
> > +		pr_info("permit %s, ino=%ld, devno=0x%x.\n",
> > +			pathname, we_obj_info.ino,
> > +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> > +
> > +failure:
> > +	if (pathnamebuf != NULL) {
> > +		kfree(pathnamebuf);
> > +		pathnamebuf = NULL;
> > +	}
> > +
> > +	if ((rc != 0) && (rc != -EACCES))
> > +		pr_warn("Checking white list does not work.\n");
> > +
> > +	return rc;
> > +}
> > +
> > +/**
> > + * send_receive_we_obj_info - Send message and wait.
> > + *
> > + * @we_obj_info: Pointer to struct we_obj_info.
> > + * @result: Pointer to result of matching to white list.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +static int send_receive_we_obj_info(
> > +		struct we_obj_info *we_obj_info, int *checkresult)
> > +{
> > +	int i;
> > +	int rc;
> > +	struct we_req_q req;
> > +
> > +	we_req_q_init(&req, we_obj_info);
> > +
> > +	if ((we_req_q_search(&(req.data))) == NULL) {
> > +		rc = we_req_q_push(&req);
> > +		if (rc < 0) {
> > +			pr_err("error %d at %d in %s\n", rc,
> > +					__LINE__, __FILE__);
> > +			goto failure;
> > +		}
> > +	}
> > +
> > +	for (i = 0; i < MAXCOMRETRY; i++) {
> > +		rc = send_we_obj_info(&req);
> > +
> > +		if (likely(req.finish_flag == START_EXEC)) {
> > +			break;
> > +		} else if (unlikely(rc == -ERESTARTSYS)) {
> > +			pr_info("Signal detected (%d)\n", rc);
> > +			break;
> > +		}
> > +	}
> > +
> > +	we_req_q_pop(&req);
> > +
> > +	if (unlikely(i >= MAXCOMRETRY) && req.finish_flag != START_EXEC)
> {
> > +		rc = -EINVAL;
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +	}
> > +
> > +	*checkresult = req.permit;
> > +
> > +failure:
> > +	return rc;
> > +}
> > +
> > +/**
> > + * we_security_bprm_check_main - Target for security_bprm_check.
> > + *
> > + * @bprm: Pointer to struct linux_binprm.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int we_security_bprm_check_main(struct linux_binprm *bprm)
> > +{
> > +	if (unlikely(!from_task))
> > +		return 0;
> > +
> > +	return we_check_main(bprm->file);
> > +}
> > +
> > +/**
> > + * we_security_mmap_check_main - Target for mmap_file.
> > + *
> > + * @file: Pointer to struct file to map.
> > + * @reqprot: Protection requested by the application.
> > + * @flags: Operational flags.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int we_security_mmap_check_main(struct file *file,
> > +		unsigned long reqprot, unsigned long flags)
> > +{
> > +	if (unlikely(!from_task))
> > +		return 0;
> > +
> > +	if (!(reqprot & PROT_EXEC))
> > +		return 0;
> > +
> > +	if ((flags & MAP_EXECUTABLE))
> > +		return 0;
> > +
> > +	if (!file)
> > +		return 0;
> > +
> > +	if (!file->f_path.dentry)
> > +		return 0;
> > +
> > +	return we_check_main(file);
> > +}
> > diff --git a/security/whiteegret/request.c
> b/security/whiteegret/request.c
> > new file mode 100644
> > index 000000000000..7d28e133ebd6
> > --- /dev/null
> > +++ b/security/whiteegret/request.c
> > @@ -0,0 +1,151 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#include <linux/list.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/rwlock_types.h>
> > +#include <linux/slab.h>
> > +#include <linux/string.h>
> > +#include "request.h"
> > +
> > +struct we_req_q_head we_q_head;
> > +
> > +static int match_we_req_data(struct we_req_data *data1,
> > +		struct we_req_data *data2);
> > +
> > +/**
> > + * we_req_q_init - Initialize the global variable we_q_head.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_head_init(void)
> > +{
> > +	rwlock_init(&(we_q_head.lock));
> > +	INIT_LIST_HEAD(&(we_q_head.head));
> > +	init_waitqueue_head(&(we_q_head.waitq));
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_push - Add queue to tail of the list.
> > + *
> > + * @queue: Pointer to we_req_q to be added to the list.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_push(struct we_req_q *queue)
> > +{
> > +	write_lock(&(we_q_head.lock));
> > +	list_add_tail(&(queue->queue), &we_q_head.head);
> > +	write_unlock(&(we_q_head.lock));
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_search - Search data in the list.
> > + *
> > + * @data: Pointer to we_req_data to be searched in the list.
> > + *
> > + * Returns pointer to data if data is found in the list,
> > + * NULL otherwise.
> > + */
> > +struct we_req_q *we_req_q_search(struct we_req_data *data)
> > +{
> > +	struct list_head *p;
> > +	struct we_req_q *req;
> > +
> > +	read_lock(&(we_q_head.lock));
> > +
> > +	list_for_each(p, &(we_q_head.head)) {
> > +		req = list_entry(p, struct we_req_q, queue);
> > +
> > +		if (match_we_req_data(data, &(req->data))) {
> > +			read_unlock(&(we_q_head.lock));
> > +			return req;
> > +		}
> > +	}
> > +
> > +	read_unlock(&(we_q_head.lock));
> > +
> > +	return NULL;
> > +}
> > +
> > +/**
> > + * we_req_q_init - Initialize queue.
> > + *
> > + * @req: Pointer to we_req_q to be initialized.
> > + * @info: Pointer to we_obj_info.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info)
> > +{
> > +	req->finish_flag = STOP_EXEC;
> > +	req->data.we_obj_info = info;
> > +	req->permit = -EACCES;
> > +	init_waitqueue_head(&req->waitq);
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_pop - Delete queue in the list.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_pop(struct we_req_q *queue)
> > +{
> > +	write_lock(&(we_q_head.lock));
> > +	list_del(&queue->queue);
> > +	write_unlock(&(we_q_head.lock));
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * match_we_req_data - Compare two we_req_data data.
> > + *
> > + * @data1: Pointer to we_req_data
> > + * @data2: Pointer to we_req_data
> > + *
> > + * Returns 1 if ppid of both we_req_data data are equal,
> > + * 0 otherwise.
> > + */
> > +static int match_we_req_data(struct we_req_data *data1,
> > +		struct we_req_data *data2)
> > +{
> > +	if (data1->we_obj_info->ppid == data2->we_obj_info->ppid)
> > +		return 1;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_cleanup - Cleaning up queues.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_cleanup(void)
> > +{
> > +	struct list_head *p;
> > +	struct we_req_q *req;
> > +
> > +	write_lock(&(we_q_head.lock));
> > +	list_for_each(p, &we_q_head.head) {
> > +		req = list_entry(p, struct we_req_q, queue);
> > +		req->finish_flag = START_EXEC;
> > +		req->permit = -EINVAL;
> > +	}
> > +	write_unlock(&(we_q_head.lock));
> > +
> > +	return 0;
> > +}
> > diff --git a/security/whiteegret/request.h
> b/security/whiteegret/request.h
> > new file mode 100644
> > index 000000000000..4a735fc70c63
> > --- /dev/null
> > +++ b/security/whiteegret/request.h
> > @@ -0,0 +1,52 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _REQUEST_H
> > +#define _REQUEST_H
> > +
> > +#include <linux/sched.h>
> > +#include <linux/wait.h>
> > +
> > +#include "we.h"
> > +
> > +struct we_req_q_head {
> > +	struct list_head head;
> > +	rwlock_t lock;
> > +	wait_queue_head_t waitq;
> > +};
> > +
> > +
> > +#define STOP_EXEC  0
> > +#define START_EXEC 1
> > +
> > +extern struct we_req_q_head we_q_head;
> > +
> > +/* Structure for information of request from kernel space to user space
> */
> > +struct we_req_data {
> > +	struct we_obj_info *we_obj_info;
> > +};
> > +
> > +struct we_req_q {
> > +	struct list_head queue;
> > +	int finish_flag;
> > +	struct we_req_data data;
> > +	int permit;
> > +	wait_queue_head_t waitq;
> > +};
> > +
> > +int we_req_q_pop(struct we_req_q *queue);
> > +int we_req_q_cleanup(void);
> > +
> > +int we_req_q_head_init(void);
> > +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info);
> > +int we_req_q_push(struct we_req_q *queue);
> > +struct we_req_q *we_req_q_search(struct we_req_data *data);
> > +
> > +#endif  /* _REQUEST_H */
> > diff --git a/security/whiteegret/we.h b/security/whiteegret/we.h
> > new file mode 100644
> > index 000000000000..fc14e67d4f7d
> > --- /dev/null
> > +++ b/security/whiteegret/we.h
> > @@ -0,0 +1,66 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _WE_H
> > +#define _WE_H
> > +
> > +#include <linux/binfmts.h>
> > +
> > +/*
> > + * Initial size in byte of memory allocation to store the path
> > + * of an object file
> > + */
> > +#define EXPECTPATHSIZE 1023
> > +
> > +/*
> > + * Default size in byte to expand block that stores the path
> > + * of an object file when the memory block is too small
> > + * to store the path
> > + */
> > +#define ADDEDEXPECTPATHSIZE 1023
> > +
> > +/* Maximum length in byte of path of object file */
> > +#define MAXPATHSIZE 8184
> > +
> > +/* Maximum length in byte of name of executable file */
> > +#define SHORTNAMELENGTH 256
> > +
> > +/*
> > + * Maximum number of retry for sending the same message
> > + * to user whitelisting application
> > + */
> > +#define MAXCOMRETRY 10
> > +
> > +/* Timeout value in millisecond to aquire the semaphore */
> > +#define WERESULTTIMEOUT 1000
> > +
> > +/*
> > + * Structure for an object to be tested whether it is contained
> > + * in the whitelist or not
> > + */
> > +struct we_obj_info {
> > +	unsigned long ino;                /* inode number */
> > +	unsigned int dmajor;              /* major version of device
> number */
> > +	unsigned int dminor;              /* minor version of device
> number */
> > +	char shortname[SHORTNAMELENGTH];  /* short name for the object */
> > +	int pathsize;
> > +	char *path;                       /* full path to the object */
> > +	pid_t pid;
> > +	pid_t ppid;
> > +};
> > +
> > +int we_security_bprm_check_main(struct linux_binprm *bprm);
> > +int we_security_mmap_check_main(struct file *file,
> > +		unsigned long reqprot, unsigned long flags);
> > +
> > +int we_specific_init(void);
> > +int we_specific_exit(void);
> > +
> > +#endif  /* _WE_H */
> > diff --git a/security/whiteegret/we_fs.c b/security/whiteegret/we_fs.c
> > new file mode 100644
> > index 000000000000..27b76f093814
> > --- /dev/null
> > +++ b/security/whiteegret/we_fs.c
> > @@ -0,0 +1,280 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#define pr_fmt(fmt) "WhiteEgret: " fmt
> > +
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/security.h>
> > +#include <linux/init.h>
> > +#include <linux/fs.h>
> > +#include <linux/wait.h>
> > +#include <linux/sched.h>
> > +#include <linux/uaccess.h>
> > +#include <linux/cdev.h>
> > +
> > +#include "we_fs.h"
> > +
> > +#define static_assert(constexpr) \
> > +	char dummy[(constexpr) ? 1 : -1] __attribute__((unused))
> > +
> > +#define WE_COPY_TO_USER(to, from, ret) \
> > +	do { \
> > +		static_assert(sizeof((to)) == sizeof((from))); \
> > +		(ret) = copy_to_user(&(to), &(from), sizeof(to)); \
> > +	} while (0)
> > +
> > +#define WE_COPY_FROM_USER(to, from, ret) \
> > +	do { \
> > +		static_assert(sizeof((to)) == sizeof((from))); \
> > +		(ret) = copy_from_user(&(to), &(from), sizeof(to)); \
> > +	} while (0)
> > +
> > +static struct we_req_q_head *root;
> > +struct task_struct *from_task;
> > +static DEFINE_RWLOCK(from_task_lock);
> > +
> > +static int check_we_pathsize(struct we_req_q *we_req, int size)
> > +{
> > +	if (size - sizeof(*we_req)
> > +			> we_req->data.we_obj_info->pathsize)
> > +		return 0;
> > +	else
> > +		return -1;
> > +}
> > +
> > +static int set_we_req_info(struct we_req_user *user,
> > +		struct we_obj_info *info)
> > +{
> > +	unsigned long ret;
> > +
> > +	WE_COPY_TO_USER(user->ino, info->ino, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->dmajor, info->dmajor, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->dminor, info->dminor, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->pid, info->pid, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->ppid, info->ppid, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->shortname, info->shortname, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->pathsize, info->pathsize, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	ret = copy_to_user(user->path, info->path, info->pathsize + 1);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int set_we_ack(struct we_ack *to, struct we_ack *from)
> > +{
> > +	unsigned long ret;
> > +
> > +	WE_COPY_FROM_USER(to->pid, from->pid, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_FROM_USER(to->permit, from->permit, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct we_req_user *get_alive_we_req(struct we_req_q_head
> *root,
> > +		void *buf, int size)
> > +{
> > +	int pathsize;
> > +	struct list_head *p;
> > +	struct we_req_q *req;
> > +	struct we_req_user *user = NULL;
> > +
> > +	write_lock(&root->lock);
> > +	list_for_each(p, &root->head) {
> > +		req = list_entry(p, struct we_req_q, queue);
> > +		if (req->finish_flag == STOP_EXEC) {
> > +			if (unlikely(check_we_pathsize(req, size)))
> > +				goto SIZE_ERROR;
> > +			user = (struct we_req_user *)buf;
> > +			set_we_req_info(user, req->data.we_obj_info);
> > +			break;
> > +		}
> > +	}
> > +	write_unlock(&root->lock);
> > +
> > +	return user;
> > +SIZE_ERROR:
> > +	pathsize = req->data.we_obj_info->pathsize;
> > +	req->permit = -EACCES;
> > +	req->finish_flag = START_EXEC;
> > +	write_unlock(&root->lock);
> > +	pr_err("Path length of exec is too long (%d).\n", pathsize);
> > +	return NULL;
> > +}
> > +
> > +static ssize_t send_ack(struct we_req_q_head *root, struct we_ack *ack)
> > +{
> > +	struct list_head *p;
> > +	struct we_req_q *req = NULL, *temp;
> > +
> > +	write_lock(&root->lock);
> > +	list_for_each(p, &root->head) {
> > +		temp = list_entry(p, struct we_req_q, queue);
> > +		if (temp->data.we_obj_info->pid == ack->pid) {
> > +			req = temp;
> > +			req->permit = ack->permit;
> > +			wake_up_interruptible_sync(&req->waitq);
> > +			req->finish_flag = START_EXEC;
> > +		}
> > +	}
> > +	write_unlock(&root->lock);
> > +
> > +	if (unlikely(!req)) {
> > +		pr_warn("%s: can not find we_req. pid(%d)\n",
> > +			__func__, ack->pid);
> > +		return -EACCES;
> > +	}
> > +	return sizeof(*ack);
> > +}
> > +
> > +static ssize_t we_driver_read(struct file *file, char *buf,
> > +		size_t size, loff_t *off)
> > +{
> > +	int ret;
> > +	struct we_req_user *user;
> > +
> > +	while (1) {
> > +		ret = wait_event_interruptible(root->waitq,
> > +				(user = get_alive_we_req(root, buf,
> size)));
> > +		if (unlikely(ret < 0)) {
> > +			pr_info("%s: signal (%d)", __func__, ret);
> > +			return 0;
> > +		}
> > +		if (likely(user))
> > +			break;
> > +	}
> > +
> > +	return sizeof(*user) + user->pathsize + 1;
> > +}
> > +
> > +static ssize_t we_driver_write(struct file *file, const char *buf,
> > +		size_t size, loff_t *off)
> > +{
> > +	int rc;
> > +	ssize_t ret;
> > +	struct we_ack ack;
> > +
> > +	rc = set_we_ack(&ack, (struct we_ack *)((void *)buf));
> > +	if (rc < 0)
> > +		return (ssize_t)rc;
> > +	ret = send_ack(root, &ack);
> > +
> > +	return ret;
> > +}
> > +
> > +static long we_driver_ioctl(struct file *file,
> > +		unsigned int arg0, unsigned long arg1)
> > +{
> > +	return 0;
> > +}
> > +
> > +static int we_driver_release(struct inode *inode, struct file *filp)
> > +{
> > +	int ret = 0;
> > +
> > +	write_lock(&from_task_lock);
> > +	if (!from_task) {
> > +		pr_warn("WhiteEgret has not started.\n");
> > +		ret =  -EACCES;
> > +		goto END;
> > +	}
> > +	if (from_task != current) {
> > +		pr_warn("This task is not registered to WhiteEgret.\n");
> > +		ret = -EACCES;
> > +		goto END;
> > +	}
> > +	from_task = NULL;
> > +	we_req_q_cleanup();
> > +END:
> > +	write_unlock(&from_task_lock);
> > +	return ret;
> > +}
> > +
> > +static int we_driver_open(struct inode *inode, struct file *filp)
> > +{
> > +	write_lock(&from_task_lock);
> > +	if (from_task) {
> > +		write_unlock(&(from_task_lock));
> > +		pr_warn("WhiteEgret has already started.\n");
> > +		return -EACCES;
> > +	}
> > +
> > +	from_task = current;
> > +	root = &we_q_head;
> > +	write_unlock(&from_task_lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct file_operations we_driver_fops = {
> > +	.owner = THIS_MODULE,
> > +	.read = we_driver_read,
> > +	.write = we_driver_write,
> > +	.unlocked_ioctl = we_driver_ioctl,
> > +	.open =  we_driver_open,
> > +	.release = we_driver_release,
> > +};
> > +
> > +int we_fs_init(void)
> > +{
> > +	struct dentry *we_dir;
> > +	struct dentry *wecom;
> > +
> > +	we_dir = securityfs_create_dir(WE_FS_DIR_NAME, NULL);
> > +	if (IS_ERR(we_dir))
> > +		return PTR_ERR(we_dir);
> > +
> > +	wecom = securityfs_create_file(WE_DEV_NAME, 0600, we_dir, NULL,
> &we_driver_fops);
> > +	if (IS_ERR(wecom)) {
> > +		securityfs_remove(we_dir);
> > +		return PTR_ERR(wecom);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * send_we_obj_info - Wait response from user's whitelisting application.
> > + *
> > + * @req: Pointer to struct we_req_q.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int send_we_obj_info(struct we_req_q *req)
> > +{
> > +	/* If there exists queue waiting for this request req done,
> > +	 * then wake it up.
> > +	 */
> > +	if (waitqueue_active(&(we_q_head.waitq)))
> > +		wake_up(&(we_q_head.waitq));
> > +
> > +	return wait_event_interruptible_timeout(req->waitq,
> > +			(req->finish_flag == START_EXEC),
> > +			WERESULTTIMEOUT);
> > +}
> > diff --git a/security/whiteegret/we_fs.h b/security/whiteegret/we_fs.h
> > new file mode 100644
> > index 000000000000..9af245d7aca4
> > --- /dev/null
> > +++ b/security/whiteegret/we_fs.h
> > @@ -0,0 +1,23 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _WE_FS_H
> > +#define _WE_FS_H
> > +
> > +#include "request.h"
> > +#include "we_fs_common.h"
> > +
> > +extern struct task_struct *from_task;
> > +
> > +int we_fs_init(void);
> > +
> > +int send_we_obj_info(struct we_req_q *req);
> > +
> > +#endif  /* _WE_FS_H */
> > diff --git a/security/whiteegret/we_fs_common.h
> b/security/whiteegret/we_fs_common.h
> > new file mode 100644
> > index 000000000000..259f300d9738
> > --- /dev/null
> > +++ b/security/whiteegret/we_fs_common.h
> > @@ -0,0 +1,36 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _WE_FS_COMMON_H
> > +#define _WE_FS_COMMON_H
> > +
> > +#define WE_FS_DIR_NAME "whiteegret"
> > +#define WE_DEV_NAME "wecom"
> > +#define WE_DEV_PATH
> "/sys/kernel/security/"WE_FS_DIR_NAME"/"WE_DEV_NAME
> > +
> > +#define SHORTNAMELENGTH 256
> > +
> > +struct we_req_user {
> > +	unsigned long ino;
> > +	unsigned int dmajor;
> > +	unsigned int dminor;
> > +	pid_t pid;
> > +	pid_t ppid;
> > +	char shortname[SHORTNAMELENGTH];
> > +	int pathsize;
> > +	char path[0];
> > +};
> > +
> > +struct we_ack {
> > +	int permit;
> > +	pid_t pid;
> > +};
> > +
> > +#endif  /* _WE_FS_COMMON_H */
> 
> --
> 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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
@ 2018-03-02  3:57     ` masanobu2.koike at toshiba.co.jp
  0 siblings, 0 replies; 10+ messages in thread
From: masanobu2.koike at toshiba.co.jp @ 2018-03-02  3:57 UTC (permalink / raw)
  To: linux-security-module


On Friday, March 02, 2018 12:43 AM, Casey Schaufler wrote:
> On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> > This RFC provides implementation of WhiteEgret.
> >
> > Signed-off-by: Masanobu Koike <masanobu2.koike@toshiba.co.jp>
> > ---
> >  security/Kconfig                   |   6 +
> >  security/Makefile                  |   2 +
> >  security/whiteegret/Kconfig        |  11 ++
> >  security/whiteegret/Makefile       |   2 +
> >  security/whiteegret/init.c         |  75 ++++++++++
> >  security/whiteegret/main.c         | 251
> +++++++++++++++++++++++++++++++++
> >  security/whiteegret/request.c      | 151 ++++++++++++++++++++
> >  security/whiteegret/request.h      |  52 +++++++
> >  security/whiteegret/we.h           |  66 +++++++++
> >  security/whiteegret/we_fs.c        | 280
> +++++++++++++++++++++++++++++++++++++
> >  security/whiteegret/we_fs.h        |  23 +++
> >  security/whiteegret/we_fs_common.h |  36 +++++
> >  12 files changed, 955 insertions(+)
> >  create mode 100644 security/whiteegret/Kconfig
> >  create mode 100644 security/whiteegret/Makefile
> >  create mode 100644 security/whiteegret/init.c
> >  create mode 100644 security/whiteegret/main.c
> >  create mode 100644 security/whiteegret/request.c
> >  create mode 100644 security/whiteegret/request.h
> >  create mode 100644 security/whiteegret/we.h
> >  create mode 100644 security/whiteegret/we_fs.c
> >  create mode 100644 security/whiteegret/we_fs.h
> >  create mode 100644 security/whiteegret/we_fs_common.h
> >
> > diff --git a/security/Kconfig b/security/Kconfig
> > index c4302067a3ad..f17fefecaf84 100644
> > --- a/security/Kconfig
> > +++ b/security/Kconfig
> > @@ -237,6 +237,7 @@ source security/tomoyo/Kconfig
> >  source security/apparmor/Kconfig
> >  source security/loadpin/Kconfig
> >  source security/yama/Kconfig
> > +source security/whiteegret/Kconfig
> >
> >  source security/integrity/Kconfig
> >
> > @@ -246,6 +247,7 @@ choice
> >  	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
> >  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
> >  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
> > +	default DEFAULT_SECURITY_WHITEEGRET if SECURITY_WHITEEGRET
> >  	default DEFAULT_SECURITY_DAC
> >
> >  	help
> > @@ -264,6 +266,9 @@ choice
> >  	config DEFAULT_SECURITY_APPARMOR
> >  		bool "AppArmor" if SECURITY_APPARMOR=y
> >
> > +	config DEFAULT_SECURITY_WHITEEGRET
> > +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> > +
> 
> I don't see this module using any security blobs. Is there
> a reason you're not making this a minor (like yama) module
> instead of a major (like AppArmor) module?

Thank you for your suggestion.
We are now developing WhiteEgret on the environment
it works certainly.

Masanobu Koike

> 
> >  	config DEFAULT_SECURITY_DAC
> >  		bool "Unix Discretionary Access Controls"
> >
> > @@ -275,6 +280,7 @@ config DEFAULT_SECURITY
> >  	default "smack" if DEFAULT_SECURITY_SMACK
> >  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
> >  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
> > +	default "whiteegret" if DEFAULT_SECURITY_WHITEEGRET
> >  	default "" if DEFAULT_SECURITY_DAC
> >
> >  endmenu
> > diff --git a/security/Makefile b/security/Makefile
> > index 4d2d3782ddef..3a8249c77288 100644
> > --- a/security/Makefile
> > +++ b/security/Makefile
> > @@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
> >  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
> >  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
> >  subdir-$(CONFIG_SECURITY_LOADPIN)	+= loadpin
> > +subdir-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret
> >
> >  # always enable default capabilities
> >  obj-y					+= commoncap.o
> > @@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)		+=
> tomoyo/
> >  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
> >  obj-$(CONFIG_SECURITY_YAMA)		+= yama/
> >  obj-$(CONFIG_SECURITY_LOADPIN)		+= loadpin/
> > +obj-$(CONFIG_SECURITY_WHITEEGRET)	+= whiteegret/
> >  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
> >
> >  # Object integrity file lists
> > diff --git a/security/whiteegret/Kconfig b/security/whiteegret/Kconfig
> > new file mode 100644
> > index 000000000000..32845977745f
> > --- /dev/null
> > +++ b/security/whiteegret/Kconfig
> > @@ -0,0 +1,11 @@
> > +config SECURITY_WHITEEGRET
> > +        bool "WhiteEgret support"
> > +        depends on SECURITY
> > +        default n
> > +        help
> > +	  This enables the WhiteEgret security module.
> > +	  WhiteEgret provides a whitelisting execution control
> capability,
> > +	  which helps stop the execution of unauthorized software
> > +	  such as malware.
> > +	  You will also need a user application and an execution whitelist.
> > +          If you are unsure how to answer this question, answer N.
> > diff --git a/security/whiteegret/Makefile
> b/security/whiteegret/Makefile
> > new file mode 100644
> > index 000000000000..16bd3afd9324
> > --- /dev/null
> > +++ b/security/whiteegret/Makefile
> > @@ -0,0 +1,2 @@
> > +obj-$(CONFIG_SECURITY_WHITEEGRET) += whiteegret.o
> > +whiteegret-y := init.o main.o request.o we_fs.o
> > diff --git a/security/whiteegret/init.c b/security/whiteegret/init.c
> > new file mode 100644
> > index 000000000000..3691cca6bc27
> > --- /dev/null
> > +++ b/security/whiteegret/init.c
> > @@ -0,0 +1,75 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#define pr_fmt(fmt) "WhiteEgret: " fmt
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/sched.h>
> > +#include <linux/security.h>
> > +#include <linux/fs.h>
> > +#include "we.h"
> > +
> > +#include <linux/lsm_hooks.h>
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("WhiteEgret Linux Security Module");
> > +
> > +static int we_security_bprm_check(struct linux_binprm *bprm)
> > +{
> > +	if (we_security_bprm_check_main(bprm) == -EACCES)
> > +		return -EACCES;
> > +
> > +	return 0;
> > +}
> > +
> > +static int we_security_mmap_check(struct file *file, unsigned long
> reqprot,
> > +		unsigned long prot, unsigned long flags)
> > +{
> > +	if (we_security_mmap_check_main(file, reqprot, flags) == -EACCES)
> > +		return -EACCES;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct security_hook_list we_hooks[] = {
> > +	LSM_HOOK_INIT(bprm_check_security, we_security_bprm_check),
> > +	LSM_HOOK_INIT(mmap_file, we_security_mmap_check),
> > +};
> > +
> > +static int __init we_init(void)
> > +{
> > +	int rc;
> > +
> > +	if (!security_module_enable("whiteegret"))
> > +		return 0;
> > +
> > +	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks),
> "whiteegret");
> > +
> > +	rc = we_specific_init();
> > +	if (rc) {
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		return rc;
> > +	}
> > +
> > +	pr_warn("WhiteEgret (LSM) initialized.\n");
> > +
> > +	return 0;
> > +}
> > +
> > +static void __exit we_exit(void)
> > +{
> > +	we_specific_exit();
> > +
> > +	pr_warn("WhiteEgret (LSM) exited.\n");
> > +}
> > +
> > +module_init(we_init);
> > +module_exit(we_exit);
> > diff --git a/security/whiteegret/main.c b/security/whiteegret/main.c
> > new file mode 100644
> > index 000000000000..f60e1d325011
> > --- /dev/null
> > +++ b/security/whiteegret/main.c
> > @@ -0,0 +1,251 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#define pr_fmt(fmt) "WhiteEgret: " fmt
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/semaphore.h>
> > +#include <linux/binfmts.h>
> > +#include <linux/dcache.h>
> > +#include <linux/fs.h>
> > +#include <linux/mman.h>
> > +#include "we.h"
> > +#include "request.h"
> > +
> > +#include <linux/sched.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include "we_fs.h"
> > +
> > +
> > +static int send_receive_we_obj_info(
> > +		struct we_obj_info *we_obj_info, int *checkresult);
> > +
> > +/**
> > + * we_specific_init - Initialize fs.
> > + *
> > + * Returns 0.
> > + */
> > +int we_specific_init(void)
> > +{
> > +	int rc = 0;
> > +
> > +	rc = we_fs_init();
> > +	if (rc < 0) {
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		return rc;
> > +	}
> > +
> > +	we_req_q_head_init();
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_specific_exit - Nothing to do in the implementation.
> > + *
> > + * Returns 0.
> > + */
> > +int we_specific_exit(void)
> > +{
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_check_main - Common function for security_bprm_check and mmap_file.
> > + *
> > + * @file: Pointer to struct file.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int we_check_main(struct file *file)
> > +{
> > +	struct inode *inode;
> > +	struct we_obj_info we_obj_info;
> > +	char *pathnamebuf;
> > +	char *new_pathnamebuf;
> > +	char *pathname;
> > +	char *shortnamebuf;
> > +	int pathsize;
> > +	int rc;
> > +	int i;
> > +	int checkresult;
> > +
> > +	if (unlikely(file == NULL))
> > +		return 0;
> > +
> > +	pathsize = EXPECTPATHSIZE;
> > +	pathnamebuf = kmalloc(pathsize, GFP_KERNEL);
> > +	if (unlikely(!pathnamebuf)) {
> > +		rc = -ENOMEM;
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		goto failure;
> > +	}
> > +	while (pathsize <= MAXPATHSIZE) {
> > +		pathname = d_absolute_path(&file->f_path, pathnamebuf,
> > +				pathsize-1);
> > +		if (!IS_ERR(pathname))
> > +			break;
> > +
> > +		pathsize += ADDEDEXPECTPATHSIZE;
> > +		new_pathnamebuf = krealloc(pathnamebuf, pathsize,
> > +				GFP_KERNEL);
> > +		if (unlikely(!new_pathnamebuf)) {
> > +			rc = -ENOMEM;
> > +			pr_err("error %d at %d in %s\n", rc,
> > +					__LINE__, __FILE__);
> > +			goto failure;
> > +		}
> > +		pathnamebuf = new_pathnamebuf;
> > +	}
> > +	if (unlikely(pathsize >= MAXPATHSIZE)) {
> > +		rc = -ENOMEM;
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +		goto failure;
> > +	}
> > +
> > +	shortnamebuf = pathname;
> > +	for (i = 0; i < pathsize; i++) {
> > +		if (pathname[i] == '\0')
> > +			break;
> > +		if (pathname[i] == '/')
> > +			shortnamebuf = pathname + (i + 1);
> > +	}
> > +	strncpy(we_obj_info.shortname, shortnamebuf, SHORTNAMELENGTH);
> > +	we_obj_info.path = pathname;
> > +	inode = file_inode(file);
> > +	we_obj_info.ino = inode->i_ino;
> > +	we_obj_info.dmajor = MAJOR(inode->i_sb->s_dev);
> > +	we_obj_info.dminor = MINOR(inode->i_sb->s_dev);
> > +	we_obj_info.pid = current->pid;
> > +	we_obj_info.pathsize = strlen(pathname);
> > +	we_obj_info.ppid = current->tgid;
> > +
> > +	rc = send_receive_we_obj_info(&we_obj_info, &checkresult);
> > +	if (rc < 0)
> > +		goto failure;
> > +
> > +	rc = checkresult;
> > +
> > +	if (rc == -EACCES)
> > +		pr_warn("block %s, ino=%ld, devno=0x%x.\n",
> > +			pathname, we_obj_info.ino,
> > +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> > +	else
> > +		pr_info("permit %s, ino=%ld, devno=0x%x.\n",
> > +			pathname, we_obj_info.ino,
> > +			MKDEV(we_obj_info.dmajor, we_obj_info.dminor));
> > +
> > +failure:
> > +	if (pathnamebuf != NULL) {
> > +		kfree(pathnamebuf);
> > +		pathnamebuf = NULL;
> > +	}
> > +
> > +	if ((rc != 0) && (rc != -EACCES))
> > +		pr_warn("Checking white list does not work.\n");
> > +
> > +	return rc;
> > +}
> > +
> > +/**
> > + * send_receive_we_obj_info - Send message and wait.
> > + *
> > + * @we_obj_info: Pointer to struct we_obj_info.
> > + * @result: Pointer to result of matching to white list.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +static int send_receive_we_obj_info(
> > +		struct we_obj_info *we_obj_info, int *checkresult)
> > +{
> > +	int i;
> > +	int rc;
> > +	struct we_req_q req;
> > +
> > +	we_req_q_init(&req, we_obj_info);
> > +
> > +	if ((we_req_q_search(&(req.data))) == NULL) {
> > +		rc = we_req_q_push(&req);
> > +		if (rc < 0) {
> > +			pr_err("error %d at %d in %s\n", rc,
> > +					__LINE__, __FILE__);
> > +			goto failure;
> > +		}
> > +	}
> > +
> > +	for (i = 0; i < MAXCOMRETRY; i++) {
> > +		rc = send_we_obj_info(&req);
> > +
> > +		if (likely(req.finish_flag == START_EXEC)) {
> > +			break;
> > +		} else if (unlikely(rc == -ERESTARTSYS)) {
> > +			pr_info("Signal detected (%d)\n", rc);
> > +			break;
> > +		}
> > +	}
> > +
> > +	we_req_q_pop(&req);
> > +
> > +	if (unlikely(i >= MAXCOMRETRY) && req.finish_flag != START_EXEC)
> {
> > +		rc = -EINVAL;
> > +		pr_err("error %d at %d in %s\n", rc, __LINE__, __FILE__);
> > +	}
> > +
> > +	*checkresult = req.permit;
> > +
> > +failure:
> > +	return rc;
> > +}
> > +
> > +/**
> > + * we_security_bprm_check_main - Target for security_bprm_check.
> > + *
> > + * @bprm: Pointer to struct linux_binprm.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int we_security_bprm_check_main(struct linux_binprm *bprm)
> > +{
> > +	if (unlikely(!from_task))
> > +		return 0;
> > +
> > +	return we_check_main(bprm->file);
> > +}
> > +
> > +/**
> > + * we_security_mmap_check_main - Target for mmap_file.
> > + *
> > + * @file: Pointer to struct file to map.
> > + * @reqprot: Protection requested by the application.
> > + * @flags: Operational flags.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int we_security_mmap_check_main(struct file *file,
> > +		unsigned long reqprot, unsigned long flags)
> > +{
> > +	if (unlikely(!from_task))
> > +		return 0;
> > +
> > +	if (!(reqprot & PROT_EXEC))
> > +		return 0;
> > +
> > +	if ((flags & MAP_EXECUTABLE))
> > +		return 0;
> > +
> > +	if (!file)
> > +		return 0;
> > +
> > +	if (!file->f_path.dentry)
> > +		return 0;
> > +
> > +	return we_check_main(file);
> > +}
> > diff --git a/security/whiteegret/request.c
> b/security/whiteegret/request.c
> > new file mode 100644
> > index 000000000000..7d28e133ebd6
> > --- /dev/null
> > +++ b/security/whiteegret/request.c
> > @@ -0,0 +1,151 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#include <linux/list.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/rwlock_types.h>
> > +#include <linux/slab.h>
> > +#include <linux/string.h>
> > +#include "request.h"
> > +
> > +struct we_req_q_head we_q_head;
> > +
> > +static int match_we_req_data(struct we_req_data *data1,
> > +		struct we_req_data *data2);
> > +
> > +/**
> > + * we_req_q_init - Initialize the global variable we_q_head.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_head_init(void)
> > +{
> > +	rwlock_init(&(we_q_head.lock));
> > +	INIT_LIST_HEAD(&(we_q_head.head));
> > +	init_waitqueue_head(&(we_q_head.waitq));
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_push - Add queue to tail of the list.
> > + *
> > + * @queue: Pointer to we_req_q to be added to the list.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_push(struct we_req_q *queue)
> > +{
> > +	write_lock(&(we_q_head.lock));
> > +	list_add_tail(&(queue->queue), &we_q_head.head);
> > +	write_unlock(&(we_q_head.lock));
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_search - Search data in the list.
> > + *
> > + * @data: Pointer to we_req_data to be searched in the list.
> > + *
> > + * Returns pointer to data if data is found in the list,
> > + * NULL otherwise.
> > + */
> > +struct we_req_q *we_req_q_search(struct we_req_data *data)
> > +{
> > +	struct list_head *p;
> > +	struct we_req_q *req;
> > +
> > +	read_lock(&(we_q_head.lock));
> > +
> > +	list_for_each(p, &(we_q_head.head)) {
> > +		req = list_entry(p, struct we_req_q, queue);
> > +
> > +		if (match_we_req_data(data, &(req->data))) {
> > +			read_unlock(&(we_q_head.lock));
> > +			return req;
> > +		}
> > +	}
> > +
> > +	read_unlock(&(we_q_head.lock));
> > +
> > +	return NULL;
> > +}
> > +
> > +/**
> > + * we_req_q_init - Initialize queue.
> > + *
> > + * @req: Pointer to we_req_q to be initialized.
> > + * @info: Pointer to we_obj_info.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info)
> > +{
> > +	req->finish_flag = STOP_EXEC;
> > +	req->data.we_obj_info = info;
> > +	req->permit = -EACCES;
> > +	init_waitqueue_head(&req->waitq);
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_pop - Delete queue in the list.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_pop(struct we_req_q *queue)
> > +{
> > +	write_lock(&(we_q_head.lock));
> > +	list_del(&queue->queue);
> > +	write_unlock(&(we_q_head.lock));
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * match_we_req_data - Compare two we_req_data data.
> > + *
> > + * @data1: Pointer to we_req_data
> > + * @data2: Pointer to we_req_data
> > + *
> > + * Returns 1 if ppid of both we_req_data data are equal,
> > + * 0 otherwise.
> > + */
> > +static int match_we_req_data(struct we_req_data *data1,
> > +		struct we_req_data *data2)
> > +{
> > +	if (data1->we_obj_info->ppid == data2->we_obj_info->ppid)
> > +		return 1;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * we_req_q_cleanup - Cleaning up queues.
> > + *
> > + * Returns 0.
> > + */
> > +int we_req_q_cleanup(void)
> > +{
> > +	struct list_head *p;
> > +	struct we_req_q *req;
> > +
> > +	write_lock(&(we_q_head.lock));
> > +	list_for_each(p, &we_q_head.head) {
> > +		req = list_entry(p, struct we_req_q, queue);
> > +		req->finish_flag = START_EXEC;
> > +		req->permit = -EINVAL;
> > +	}
> > +	write_unlock(&(we_q_head.lock));
> > +
> > +	return 0;
> > +}
> > diff --git a/security/whiteegret/request.h
> b/security/whiteegret/request.h
> > new file mode 100644
> > index 000000000000..4a735fc70c63
> > --- /dev/null
> > +++ b/security/whiteegret/request.h
> > @@ -0,0 +1,52 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _REQUEST_H
> > +#define _REQUEST_H
> > +
> > +#include <linux/sched.h>
> > +#include <linux/wait.h>
> > +
> > +#include "we.h"
> > +
> > +struct we_req_q_head {
> > +	struct list_head head;
> > +	rwlock_t lock;
> > +	wait_queue_head_t waitq;
> > +};
> > +
> > +
> > +#define STOP_EXEC  0
> > +#define START_EXEC 1
> > +
> > +extern struct we_req_q_head we_q_head;
> > +
> > +/* Structure for information of request from kernel space to user space
> */
> > +struct we_req_data {
> > +	struct we_obj_info *we_obj_info;
> > +};
> > +
> > +struct we_req_q {
> > +	struct list_head queue;
> > +	int finish_flag;
> > +	struct we_req_data data;
> > +	int permit;
> > +	wait_queue_head_t waitq;
> > +};
> > +
> > +int we_req_q_pop(struct we_req_q *queue);
> > +int we_req_q_cleanup(void);
> > +
> > +int we_req_q_head_init(void);
> > +int we_req_q_init(struct we_req_q *req, struct we_obj_info *info);
> > +int we_req_q_push(struct we_req_q *queue);
> > +struct we_req_q *we_req_q_search(struct we_req_data *data);
> > +
> > +#endif  /* _REQUEST_H */
> > diff --git a/security/whiteegret/we.h b/security/whiteegret/we.h
> > new file mode 100644
> > index 000000000000..fc14e67d4f7d
> > --- /dev/null
> > +++ b/security/whiteegret/we.h
> > @@ -0,0 +1,66 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _WE_H
> > +#define _WE_H
> > +
> > +#include <linux/binfmts.h>
> > +
> > +/*
> > + * Initial size in byte of memory allocation to store the path
> > + * of an object file
> > + */
> > +#define EXPECTPATHSIZE 1023
> > +
> > +/*
> > + * Default size in byte to expand block that stores the path
> > + * of an object file when the memory block is too small
> > + * to store the path
> > + */
> > +#define ADDEDEXPECTPATHSIZE 1023
> > +
> > +/* Maximum length in byte of path of object file */
> > +#define MAXPATHSIZE 8184
> > +
> > +/* Maximum length in byte of name of executable file */
> > +#define SHORTNAMELENGTH 256
> > +
> > +/*
> > + * Maximum number of retry for sending the same message
> > + * to user whitelisting application
> > + */
> > +#define MAXCOMRETRY 10
> > +
> > +/* Timeout value in millisecond to aquire the semaphore */
> > +#define WERESULTTIMEOUT 1000
> > +
> > +/*
> > + * Structure for an object to be tested whether it is contained
> > + * in the whitelist or not
> > + */
> > +struct we_obj_info {
> > +	unsigned long ino;                /* inode number */
> > +	unsigned int dmajor;              /* major version of device
> number */
> > +	unsigned int dminor;              /* minor version of device
> number */
> > +	char shortname[SHORTNAMELENGTH];  /* short name for the object */
> > +	int pathsize;
> > +	char *path;                       /* full path to the object */
> > +	pid_t pid;
> > +	pid_t ppid;
> > +};
> > +
> > +int we_security_bprm_check_main(struct linux_binprm *bprm);
> > +int we_security_mmap_check_main(struct file *file,
> > +		unsigned long reqprot, unsigned long flags);
> > +
> > +int we_specific_init(void);
> > +int we_specific_exit(void);
> > +
> > +#endif  /* _WE_H */
> > diff --git a/security/whiteegret/we_fs.c b/security/whiteegret/we_fs.c
> > new file mode 100644
> > index 000000000000..27b76f093814
> > --- /dev/null
> > +++ b/security/whiteegret/we_fs.c
> > @@ -0,0 +1,280 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#define pr_fmt(fmt) "WhiteEgret: " fmt
> > +
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/security.h>
> > +#include <linux/init.h>
> > +#include <linux/fs.h>
> > +#include <linux/wait.h>
> > +#include <linux/sched.h>
> > +#include <linux/uaccess.h>
> > +#include <linux/cdev.h>
> > +
> > +#include "we_fs.h"
> > +
> > +#define static_assert(constexpr) \
> > +	char dummy[(constexpr) ? 1 : -1] __attribute__((unused))
> > +
> > +#define WE_COPY_TO_USER(to, from, ret) \
> > +	do { \
> > +		static_assert(sizeof((to)) == sizeof((from))); \
> > +		(ret) = copy_to_user(&(to), &(from), sizeof(to)); \
> > +	} while (0)
> > +
> > +#define WE_COPY_FROM_USER(to, from, ret) \
> > +	do { \
> > +		static_assert(sizeof((to)) == sizeof((from))); \
> > +		(ret) = copy_from_user(&(to), &(from), sizeof(to)); \
> > +	} while (0)
> > +
> > +static struct we_req_q_head *root;
> > +struct task_struct *from_task;
> > +static DEFINE_RWLOCK(from_task_lock);
> > +
> > +static int check_we_pathsize(struct we_req_q *we_req, int size)
> > +{
> > +	if (size - sizeof(*we_req)
> > +			> we_req->data.we_obj_info->pathsize)
> > +		return 0;
> > +	else
> > +		return -1;
> > +}
> > +
> > +static int set_we_req_info(struct we_req_user *user,
> > +		struct we_obj_info *info)
> > +{
> > +	unsigned long ret;
> > +
> > +	WE_COPY_TO_USER(user->ino, info->ino, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->dmajor, info->dmajor, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->dminor, info->dminor, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->pid, info->pid, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->ppid, info->ppid, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->shortname, info->shortname, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_TO_USER(user->pathsize, info->pathsize, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	ret = copy_to_user(user->path, info->path, info->pathsize + 1);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static int set_we_ack(struct we_ack *to, struct we_ack *from)
> > +{
> > +	unsigned long ret;
> > +
> > +	WE_COPY_FROM_USER(to->pid, from->pid, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +	WE_COPY_FROM_USER(to->permit, from->permit, ret);
> > +	if (ret != 0)
> > +		return -EFAULT;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct we_req_user *get_alive_we_req(struct we_req_q_head
> *root,
> > +		void *buf, int size)
> > +{
> > +	int pathsize;
> > +	struct list_head *p;
> > +	struct we_req_q *req;
> > +	struct we_req_user *user = NULL;
> > +
> > +	write_lock(&root->lock);
> > +	list_for_each(p, &root->head) {
> > +		req = list_entry(p, struct we_req_q, queue);
> > +		if (req->finish_flag == STOP_EXEC) {
> > +			if (unlikely(check_we_pathsize(req, size)))
> > +				goto SIZE_ERROR;
> > +			user = (struct we_req_user *)buf;
> > +			set_we_req_info(user, req->data.we_obj_info);
> > +			break;
> > +		}
> > +	}
> > +	write_unlock(&root->lock);
> > +
> > +	return user;
> > +SIZE_ERROR:
> > +	pathsize = req->data.we_obj_info->pathsize;
> > +	req->permit = -EACCES;
> > +	req->finish_flag = START_EXEC;
> > +	write_unlock(&root->lock);
> > +	pr_err("Path length of exec is too long (%d).\n", pathsize);
> > +	return NULL;
> > +}
> > +
> > +static ssize_t send_ack(struct we_req_q_head *root, struct we_ack *ack)
> > +{
> > +	struct list_head *p;
> > +	struct we_req_q *req = NULL, *temp;
> > +
> > +	write_lock(&root->lock);
> > +	list_for_each(p, &root->head) {
> > +		temp = list_entry(p, struct we_req_q, queue);
> > +		if (temp->data.we_obj_info->pid == ack->pid) {
> > +			req = temp;
> > +			req->permit = ack->permit;
> > +			wake_up_interruptible_sync(&req->waitq);
> > +			req->finish_flag = START_EXEC;
> > +		}
> > +	}
> > +	write_unlock(&root->lock);
> > +
> > +	if (unlikely(!req)) {
> > +		pr_warn("%s: can not find we_req. pid(%d)\n",
> > +			__func__, ack->pid);
> > +		return -EACCES;
> > +	}
> > +	return sizeof(*ack);
> > +}
> > +
> > +static ssize_t we_driver_read(struct file *file, char *buf,
> > +		size_t size, loff_t *off)
> > +{
> > +	int ret;
> > +	struct we_req_user *user;
> > +
> > +	while (1) {
> > +		ret = wait_event_interruptible(root->waitq,
> > +				(user = get_alive_we_req(root, buf,
> size)));
> > +		if (unlikely(ret < 0)) {
> > +			pr_info("%s: signal (%d)", __func__, ret);
> > +			return 0;
> > +		}
> > +		if (likely(user))
> > +			break;
> > +	}
> > +
> > +	return sizeof(*user) + user->pathsize + 1;
> > +}
> > +
> > +static ssize_t we_driver_write(struct file *file, const char *buf,
> > +		size_t size, loff_t *off)
> > +{
> > +	int rc;
> > +	ssize_t ret;
> > +	struct we_ack ack;
> > +
> > +	rc = set_we_ack(&ack, (struct we_ack *)((void *)buf));
> > +	if (rc < 0)
> > +		return (ssize_t)rc;
> > +	ret = send_ack(root, &ack);
> > +
> > +	return ret;
> > +}
> > +
> > +static long we_driver_ioctl(struct file *file,
> > +		unsigned int arg0, unsigned long arg1)
> > +{
> > +	return 0;
> > +}
> > +
> > +static int we_driver_release(struct inode *inode, struct file *filp)
> > +{
> > +	int ret = 0;
> > +
> > +	write_lock(&from_task_lock);
> > +	if (!from_task) {
> > +		pr_warn("WhiteEgret has not started.\n");
> > +		ret =  -EACCES;
> > +		goto END;
> > +	}
> > +	if (from_task != current) {
> > +		pr_warn("This task is not registered to WhiteEgret.\n");
> > +		ret = -EACCES;
> > +		goto END;
> > +	}
> > +	from_task = NULL;
> > +	we_req_q_cleanup();
> > +END:
> > +	write_unlock(&from_task_lock);
> > +	return ret;
> > +}
> > +
> > +static int we_driver_open(struct inode *inode, struct file *filp)
> > +{
> > +	write_lock(&from_task_lock);
> > +	if (from_task) {
> > +		write_unlock(&(from_task_lock));
> > +		pr_warn("WhiteEgret has already started.\n");
> > +		return -EACCES;
> > +	}
> > +
> > +	from_task = current;
> > +	root = &we_q_head;
> > +	write_unlock(&from_task_lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct file_operations we_driver_fops = {
> > +	.owner = THIS_MODULE,
> > +	.read = we_driver_read,
> > +	.write = we_driver_write,
> > +	.unlocked_ioctl = we_driver_ioctl,
> > +	.open =  we_driver_open,
> > +	.release = we_driver_release,
> > +};
> > +
> > +int we_fs_init(void)
> > +{
> > +	struct dentry *we_dir;
> > +	struct dentry *wecom;
> > +
> > +	we_dir = securityfs_create_dir(WE_FS_DIR_NAME, NULL);
> > +	if (IS_ERR(we_dir))
> > +		return PTR_ERR(we_dir);
> > +
> > +	wecom = securityfs_create_file(WE_DEV_NAME, 0600, we_dir, NULL,
> &we_driver_fops);
> > +	if (IS_ERR(wecom)) {
> > +		securityfs_remove(we_dir);
> > +		return PTR_ERR(wecom);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * send_we_obj_info - Wait response from user's whitelisting application.
> > + *
> > + * @req: Pointer to struct we_req_q.
> > + *
> > + * Returns 0 if succeeded, < 0 otherwise.
> > + */
> > +int send_we_obj_info(struct we_req_q *req)
> > +{
> > +	/* If there exists queue waiting for this request req done,
> > +	 * then wake it up.
> > +	 */
> > +	if (waitqueue_active(&(we_q_head.waitq)))
> > +		wake_up(&(we_q_head.waitq));
> > +
> > +	return wait_event_interruptible_timeout(req->waitq,
> > +			(req->finish_flag == START_EXEC),
> > +			WERESULTTIMEOUT);
> > +}
> > diff --git a/security/whiteegret/we_fs.h b/security/whiteegret/we_fs.h
> > new file mode 100644
> > index 000000000000..9af245d7aca4
> > --- /dev/null
> > +++ b/security/whiteegret/we_fs.h
> > @@ -0,0 +1,23 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _WE_FS_H
> > +#define _WE_FS_H
> > +
> > +#include "request.h"
> > +#include "we_fs_common.h"
> > +
> > +extern struct task_struct *from_task;
> > +
> > +int we_fs_init(void);
> > +
> > +int send_we_obj_info(struct we_req_q *req);
> > +
> > +#endif  /* _WE_FS_H */
> > diff --git a/security/whiteegret/we_fs_common.h
> b/security/whiteegret/we_fs_common.h
> > new file mode 100644
> > index 000000000000..259f300d9738
> > --- /dev/null
> > +++ b/security/whiteegret/we_fs_common.h
> > @@ -0,0 +1,36 @@
> > +/*
> > + * WhiteEgret Linux Security Module
> > + *
> > + * Copyright (C) 2017-2018 Toshiba Corporation
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation, version 2.
> > + */
> > +
> > +#ifndef _WE_FS_COMMON_H
> > +#define _WE_FS_COMMON_H
> > +
> > +#define WE_FS_DIR_NAME "whiteegret"
> > +#define WE_DEV_NAME "wecom"
> > +#define WE_DEV_PATH
> "/sys/kernel/security/"WE_FS_DIR_NAME"/"WE_DEV_NAME
> > +
> > +#define SHORTNAMELENGTH 256
> > +
> > +struct we_req_user {
> > +	unsigned long ino;
> > +	unsigned int dmajor;
> > +	unsigned int dminor;
> > +	pid_t pid;
> > +	pid_t ppid;
> > +	char shortname[SHORTNAMELENGTH];
> > +	int pathsize;
> > +	char path[0];
> > +};
> > +
> > +struct we_ack {
> > +	int permit;
> > +	pid_t pid;
> > +};
> > +
> > +#endif  /* _WE_FS_COMMON_H */
> 
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

????{.n?+???????+%???????\x17??w??{.n?+????{??????????v?^?)????w*\x1fjg???\x1e???????j??\a??G??????\f???j:+v???w?j?m?????\x1e??\x1e?w?????f???h?????????

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
  2018-03-02  3:57     ` masanobu2.koike at toshiba.co.jp
@ 2018-03-03  8:22       ` Tetsuo Handa
  -1 siblings, 0 replies; 10+ messages in thread
From: Tetsuo Handa @ 2018-03-03  8:22 UTC (permalink / raw)
  To: masanobu2.koike, casey
  Cc: jmorris, serge, linux-security-module, linux-kernel

Masanobu Koike wrote:
> On Friday, March 02, 2018 12:43 AM, Casey Schaufler wrote:
> > On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> > > @@ -264,6 +266,9 @@ choice
> > >  	config DEFAULT_SECURITY_APPARMOR
> > >  		bool "AppArmor" if SECURITY_APPARMOR=y
> > >
> > > +	config DEFAULT_SECURITY_WHITEEGRET
> > > +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> > > +
> > 
> > I don't see this module using any security blobs. Is there
> > a reason you're not making this a minor (like yama) module
> > instead of a major (like AppArmor) module?
> 
> Thank you for your suggestion.
> We are now developing WhiteEgret on the environment
> it works certainly.
> 

??? What Casey suggested is effectively

----------
--- a/security/whiteegret/init.c
+++ b/security/whiteegret/init.c
@@ -48,9 +48,6 @@ static int __init we_init(void)
 {
 	int rc;
 
-	if (!security_module_enable("whiteegret"))
-		return 0;
-
 	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks), "whiteegret");
 
 	rc = we_specific_init();
----------

, isn't it? Unlike Yama, adding whiteegret_add_hooks() to security_init()
is not useful, for security_init() is called too early to create securityfs
entries for WhiteEgret.

Current version uses security= parameter as a switch for enabling/disabling
WhiteEgret, doesn't it? If WhiteEgret does not use security= as a switch,
is some other switch (e.g. __setup()) expected?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
@ 2018-03-03  8:22       ` Tetsuo Handa
  0 siblings, 0 replies; 10+ messages in thread
From: Tetsuo Handa @ 2018-03-03  8:22 UTC (permalink / raw)
  To: linux-security-module

Masanobu Koike wrote:
> On Friday, March 02, 2018 12:43 AM, Casey Schaufler wrote:
> > On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> > > @@ -264,6 +266,9 @@ choice
> > >  	config DEFAULT_SECURITY_APPARMOR
> > >  		bool "AppArmor" if SECURITY_APPARMOR=y
> > >
> > > +	config DEFAULT_SECURITY_WHITEEGRET
> > > +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> > > +
> > 
> > I don't see this module using any security blobs. Is there
> > a reason you're not making this a minor (like yama) module
> > instead of a major (like AppArmor) module?
> 
> Thank you for your suggestion.
> We are now developing WhiteEgret on the environment
> it works certainly.
> 

??? What Casey suggested is effectively

----------
--- a/security/whiteegret/init.c
+++ b/security/whiteegret/init.c
@@ -48,9 +48,6 @@ static int __init we_init(void)
 {
 	int rc;
 
-	if (!security_module_enable("whiteegret"))
-		return 0;
-
 	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks), "whiteegret");
 
 	rc = we_specific_init();
----------

, isn't it? Unlike Yama, adding whiteegret_add_hooks() to security_init()
is not useful, for security_init() is called too early to create securityfs
entries for WhiteEgret.

Current version uses security= parameter as a switch for enabling/disabling
WhiteEgret, doesn't it? If WhiteEgret does not use security= as a switch,
is some other switch (e.g. __setup()) expected?
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
  2018-03-03  8:22       ` Tetsuo Handa
@ 2018-03-08  6:23         ` masanobu2.koike at toshiba.co.jp
  -1 siblings, 0 replies; 10+ messages in thread
From: masanobu2.koike @ 2018-03-08  6:23 UTC (permalink / raw)
  To: penguin-kernel, casey; +Cc: jmorris, serge, linux-security-module, linux-kernel


On Saturday, March 03, 2018 5:22 PM, Tetsuo Handa wrote:
> Masanobu Koike wrote:
> > On Friday, March 02, 2018 12:43 AM, Casey Schaufler wrote:
> > > On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> > > > @@ -264,6 +266,9 @@ choice
> > > >  	config DEFAULT_SECURITY_APPARMOR
> > > >  		bool "AppArmor" if SECURITY_APPARMOR=y
> > > >
> > > > +	config DEFAULT_SECURITY_WHITEEGRET
> > > > +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> > > > +
> > >
> > > I don't see this module using any security blobs. Is there
> > > a reason you're not making this a minor (like yama) module
> > > instead of a major (like AppArmor) module?
> >
> > Thank you for your suggestion.
> > We are now developing WhiteEgret on the environment
> > it works certainly.
> >
> 
> ??? What Casey suggested is effectively
> 
> ----------
> --- a/security/whiteegret/init.c
> +++ b/security/whiteegret/init.c
> @@ -48,9 +48,6 @@ static int __init we_init(void)
>  {
>  	int rc;
> 
> -	if (!security_module_enable("whiteegret"))
> -		return 0;
> -
>  	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks),
> "whiteegret");
> 
>  	rc = we_specific_init();
> ----------
> 
> , isn't it? Unlike Yama, adding whiteegret_add_hooks() to security_init()
> is not useful, for security_init() is called too early to create securityfs
> entries for WhiteEgret.
> 
> Current version uses security= parameter as a switch for enabling/disabling
> WhiteEgret, doesn't it? If WhiteEgret does not use security= as a switch,
> is some other switch (e.g. __setup()) expected?

Sorry for the delay.
Thank you for your comment and suggestion.
I'll make this module a minor one in the
next version.

Masanobu Koike

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
@ 2018-03-08  6:23         ` masanobu2.koike at toshiba.co.jp
  0 siblings, 0 replies; 10+ messages in thread
From: masanobu2.koike at toshiba.co.jp @ 2018-03-08  6:23 UTC (permalink / raw)
  To: linux-security-module


On Saturday, March 03, 2018 5:22 PM, Tetsuo Handa wrote:
> Masanobu Koike wrote:
> > On Friday, March 02, 2018 12:43 AM, Casey Schaufler wrote:
> > > On 2/28/2018 11:38 PM, Masanobu Koike wrote:
> > > > @@ -264,6 +266,9 @@ choice
> > > >  	config DEFAULT_SECURITY_APPARMOR
> > > >  		bool "AppArmor" if SECURITY_APPARMOR=y
> > > >
> > > > +	config DEFAULT_SECURITY_WHITEEGRET
> > > > +		bool "WhiteEgret" if SECURITY_WHITEEGRET=y
> > > > +
> > >
> > > I don't see this module using any security blobs. Is there
> > > a reason you're not making this a minor (like yama) module
> > > instead of a major (like AppArmor) module?
> >
> > Thank you for your suggestion.
> > We are now developing WhiteEgret on the environment
> > it works certainly.
> >
> 
> ??? What Casey suggested is effectively
> 
> ----------
> --- a/security/whiteegret/init.c
> +++ b/security/whiteegret/init.c
> @@ -48,9 +48,6 @@ static int __init we_init(void)
>  {
>  	int rc;
> 
> -	if (!security_module_enable("whiteegret"))
> -		return 0;
> -
>  	security_add_hooks(we_hooks, ARRAY_SIZE(we_hooks),
> "whiteegret");
> 
>  	rc = we_specific_init();
> ----------
> 
> , isn't it? Unlike Yama, adding whiteegret_add_hooks() to security_init()
> is not useful, for security_init() is called too early to create securityfs
> entries for WhiteEgret.
> 
> Current version uses security= parameter as a switch for enabling/disabling
> WhiteEgret, doesn't it? If WhiteEgret does not use security= as a switch,
> is some other switch (e.g. __setup()) expected?

Sorry for the delay.
Thank you for your comment and suggestion.
I'll make this module a minor one in the
next version.

Masanobu Koike


--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-03-08  6:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-01  7:38 [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions Masanobu Koike
2018-03-01  7:38 ` Masanobu Koike
2018-03-01 15:43 ` Casey Schaufler
2018-03-01 15:43   ` Casey Schaufler
2018-03-02  3:57   ` masanobu2.koike
2018-03-02  3:57     ` masanobu2.koike at toshiba.co.jp
2018-03-03  8:22     ` Tetsuo Handa
2018-03-03  8:22       ` Tetsuo Handa
2018-03-08  6:23       ` masanobu2.koike
2018-03-08  6:23         ` masanobu2.koike at toshiba.co.jp

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.