lkml.org 
[lkml]   [2018]   [Mar]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    From
    SubjectRE: [RFC v2 1/2] WhiteEgret: Add WhiteEgret core functions.
    Date

    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

    \
     
     \ /
      Last update: 2018-03-02 04:59    [W:6.985 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site