A user application is required to use WhiteEgret.
This RFC provides a sample user application program.

Usage
  sample-we-user <exe> <interpreter exe> <script>

This sample user application always returns "not permit"
for the executable specified by the argument <exe>,
otherwise always returns "permit". Set the absolute path
of an executable to be blocked for <exe>.

If the process of <interpreter exe> opening <script>, WhiteEgret
denies the execution request of the script. If the process opens
the other file, WhiteEgret allows the execution request.

Example
  sample-we-user /bin/df /bin/perl /tmp/test.pl

Then every executions of /bin/df are blocked.
The other commands can be issued normally.

If the process family of /bin/perl requests to open
/tmp/test.pl, WhiteEgret denies the request. If the
process family requests to open other file, it is
permitted.

How to build
To build this sample user application, please set option
CONFIG_SAMPLE_WHITEEGRET=y. To enable to control for script
execution, also set SECURITY_WHITEEGRET_INTERPRETER=y,
CONFIG_SECURITY_WHITEEGRET_HOOK_READ_OPEN=y and
CONFIG_SECURITY_WHITEEGRET_CHECK_LIVING_TASK=y.

Remark
This sample user application does not use a whitelist.
The reason why this sample user application adopts
blacklist-like approach is to avoid a host to become
uncontrollable. Namely, if this sample provides a sample
whitelist and it misses indispensable executable components
for a host, the host cannot run or stop normally.
Because indispensable executable components depend on
each environment, we decide not to provide a whitelisting-type
sample user application.

Signed-off-by: Shinya Takumi <shinya1.tak...@toshiba.co.jp>
---
 samples/Kconfig              |   6 ++
 samples/Makefile             |   2 +-
 samples/whiteegret/Makefile  |  14 +++
 samples/whiteegret/checkwl.c | 215 +++++++++++++++++++++++++++++++++++++++++++
 samples/whiteegret/checkwl.h |  33 +++++++
 samples/whiteegret/main.c    | 119 ++++++++++++++++++++++++
 6 files changed, 388 insertions(+), 1 deletion(-)
 create mode 100644 samples/whiteegret/Makefile
 create mode 100644 samples/whiteegret/checkwl.c
 create mode 100644 samples/whiteegret/checkwl.h
 create mode 100644 samples/whiteegret/main.c

diff --git a/samples/Kconfig b/samples/Kconfig
index ad1ec701..03a89c0 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -153,4 +153,10 @@ config SAMPLE_STATX
        help
          Build example userspace program to use the new extended-stat syscall.
 
+config SAMPLE_WHITEEGRET
+       bool "Build WhiteEgret sample user application"
+       depends on SECURITY_WHITEEGRET
+       help
+         Build sample userspace application for WhiteEgret LSM module.
+
 endif # SAMPLES
diff --git a/samples/Makefile b/samples/Makefile
index bd601c0..d0c53d3 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -3,4 +3,4 @@
 obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ trace_events/ livepatch/ \
                           hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
                           configfs/ connector/ v4l/ trace_printk/ \
-                          vfio-mdev/ statx/ qmi/
+                          vfio-mdev/ statx/ qmi/ whiteegret/
diff --git a/samples/whiteegret/Makefile b/samples/whiteegret/Makefile
new file mode 100644
index 0000000..77a0164
--- /dev/null
+++ b/samples/whiteegret/Makefile
@@ -0,0 +1,14 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-$(CONFIG_SAMPLE_WHITEEGRET) := sample-we-user
+
+sample-we-user-objs := main.o checkwl.o
+
+HOSTCFLAGS += -Wall
+HOSTCFLAGS += -I/usr/local/include
+HOSTCFLAGS += -I$(srctree)/security/whiteegret
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
diff --git a/samples/whiteegret/checkwl.c b/samples/whiteegret/checkwl.c
new file mode 100644
index 0000000..806f2f0
--- /dev/null
+++ b/samples/whiteegret/checkwl.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Sample program of user's whitelisting application
+ *
+ * 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 <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "checkwl.h"
+
+/*
+ * The function check_whitelist_exec() set -EACCES to result
+ * only when path to be examined equals to @a not_permit_exe.
+ */
+char not_permit_exe[NOTPERMITEXENAMELENGTH];
+
+/*
+ * The function check_whitelist_exec() store monitoring interpreter
+ * only when path to be examined equals to @a monitor_interpreter.
+ */
+char monitor_interpreter[NOTPERMITEXENAMELENGTH];
+
+/*
+ * The function check_whitelist_terp() set -EACCES to result
+ * only when path to be examined equals to @a not_permit_script.
+ */
+char not_permit_script[NOTPERMITEXENAMELENGTH];
+
+/*
+ * The struct records interpreter process tgid.
+ * This tgid recorded in @a root_terp_proc.
+ */
+struct terp_proc {
+       struct terp_proc *next;
+       pid_t tgid;
+};
+static struct terp_proc *root_terp_proc;
+
+void init_terp_proc(void)
+{
+       root_terp_proc = NULL;
+}
+
+static void register_terp_proc(pid_t tgid)
+{
+       struct terp_proc *proc;
+
+       proc = calloc(1, sizeof(*proc));
+       if (!proc)
+               return;
+
+       proc->tgid = tgid;
+       proc->next = root_terp_proc;
+       root_terp_proc = proc;
+}
+
+static void unregister_terp_proc(pid_t tgid)
+{
+       struct terp_proc *now, *back;
+
+       if (!root_terp_proc)
+               return;
+
+       if (root_terp_proc->tgid == tgid) {
+               root_terp_proc = root_terp_proc->next;
+               return;
+       }
+       for (back = root_terp_proc, now = back->next; now != NULL;
+            back = now, now = now->next) {
+               if (now->tgid == tgid) {
+                       back->next = now->next;
+                       free(now);
+                       break;
+               }
+       }
+}
+
+static struct terp_proc *get_terp_proc(pid_t tgid)
+{
+       struct terp_proc *now;
+
+       for (now = root_terp_proc; now != NULL; now = now->next) {
+               if (now->tgid == tgid)
+                       return now;
+       }
+       return NULL;
+}
+
+/**
+ * check_whitelist_exec - Examine whether the executable input to this function
+ *                       is included in whitelist or not.
+ *
+ * @result: Result of the examination.
+ *         0       if the executble is included in whitelist
+ *         -EACCES otherwise ("not included")
+ *
+ * Returns 0 for success, -1 otherwise.
+ */
+int check_whitelist_exec(int *result, struct we_req_user *user)
+{
+       char *path;
+
+       if (result == NULL)
+               return -1;
+
+       *result = WE_EXEC_OK;
+
+       if (user == NULL)
+               return -1;
+
+       path = user->info.path;
+
+       /*
+        * Referring a whitelist is expected at this location.
+        * However, this sample uses not whitelist but blacklist
+        * because of avoiding a host to become uncontrollable.
+        * (not_permit_exe is a blacklist containing only one item.)
+        */
+       if (strncmp(not_permit_exe, path, NOTPERMITEXENAMELENGTH) == 0)
+               *result = -EACCES;
+       /*
+        * Referring a list is monitered a interpreter at this location.
+        * This location registers a tgid of monitering interpreter.
+        * Monitering interpreter is limited reading script.
+        */
+       else if (strncmp(monitor_interpreter, path,
+                        NOTPERMITEXENAMELENGTH) == 0)
+               register_terp_proc(user->tgid);
+       return 0;
+}
+
+/**
+ * check_whitelist_terp - Examine whether the script input to this function
+ *                       is included in whitelist or not, if the process
+ *                       input to this function is registered in
+ *                       @root_terp_proc.
+ *
+ * @result: Result of the examination.
+ *         0       if the script is included in whitelist,
+ *                 or not registered process
+ *         -EACCES otherwise ("not included")
+ *
+ * Returns 0 for success, -1 otherwise.
+ */
+int check_whitelist_terp(int *result, struct we_req_user *user)
+{
+       if (result == NULL)
+               return -1;
+
+       *result = WE_EXEC_OK;
+
+       /*
+        * if process reading a file is registered, referring a whitelist
+        * is expected at this location.
+        * However, this sample uses not whitelist but blacklist
+        * because of avoiding a host to become uncontrollable.
+        * (not_permit_script is a blacklist containing only one item.)
+        */
+       if (get_terp_proc(user->tgid)) {
+               if (strncmp(not_permit_script, user->info.path,
+                           NOTPERMITEXENAMELENGTH) == 0)
+                       *result = -EACCES;
+       }
+       return 0;
+}
+
+/**
+ * check_fork_terp - Register the child process to @root_terp_proc,
+ *                  if the parent process already has registerd to
+ *                  @root_terp_proc.
+ *
+ * Returns Allways 0.
+ */
+int check_fork_terp(int *result, struct we_req_user *user)
+{
+       if (result == NULL)
+               return -1;
+
+       *result = WE_EXEC_OK;
+       /*
+        * A child process of a interpreter has possibilities interpreter.
+        * This location registers a tgid of child process case of
+        * interpreter.
+        */
+       if (get_terp_proc(user->ppid))
+               register_terp_proc(user->tgid);
+       return 0;
+}
+
+/**
+ * check_exit_terp - Unregister the process form @root_terp_proc,
+ *                  case of matching @root_terp_proc.
+ *
+ * @result: Allways 0.
+ */
+int check_exit_terp(int *result, struct we_req_user *user)
+{
+       if (result == NULL)
+               return -1;
+
+       *result = WE_EXEC_OK;
+       /*
+        * This location unregisters exit process with interpreter.
+        */
+       unregister_terp_proc(user->tgid);
+       return 0;
+}
diff --git a/samples/whiteegret/checkwl.h b/samples/whiteegret/checkwl.h
new file mode 100644
index 0000000..14e1509
--- /dev/null
+++ b/samples/whiteegret/checkwl.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Sample program of user's whitelisting application
+ *
+ * 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 _CHECKWL_H
+#define _CHECKWL_H
+
+#include <sys/types.h>
+#include "we_fs_common.h"
+
+/* byte length of absolute path of file not to permit execution */
+#define NOTPERMITEXENAMELENGTH 1024
+
+extern char not_permit_exe[NOTPERMITEXENAMELENGTH];
+extern char monitor_interpreter[NOTPERMITEXENAMELENGTH];
+extern char not_permit_script[NOTPERMITEXENAMELENGTH];
+
+void init_terp_proc(void);
+int check_whitelist_exec(int *result, struct we_req_user *user);
+int check_whitelist_terp(int *result, struct we_req_user *user);
+int check_fork_terp(int *result, struct we_req_user *user);
+int check_exit_terp(int *result, struct we_req_user *user);
+
+#endif
diff --git a/samples/whiteegret/main.c b/samples/whiteegret/main.c
new file mode 100644
index 0000000..20880df
--- /dev/null
+++ b/samples/whiteegret/main.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WhiteEgret Linux Security Module
+ *
+ * Sample program of user's whitelisting application
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "checkwl.h"
+
+#include <stdlib.h>
+#include "we_fs_common.h"
+
+#define MAXWAITFROMKER 10
+
+static void sigint_catch(int sig)
+{
+}
+
+static void print_usage(void)
+{
+       fprintf(stderr, "Usage: sample-we-user <executable file name> ");
+       fprintf(stderr, "<interpreter file name> <script file name>\n");
+       fprintf(stderr, "executable file name: absolute path of executable ");
+       fprintf(stderr, "not to permit execution.\n");
+       fprintf(stderr, "interpreter file name: absolute path of");
+       fprintf(stderr, "interpreter monitoring script read.\n");
+       fprintf(stderr, "script file name: absolute path of script file");
+       fprintf(stderr, "not to permit reading(execution).\n");
+       fprintf(stderr, "If you want to use controling script file, ");
+       fprintf(stderr, "you enable WhiteEgret Kernel option ");
+       fprintf(stderr, "CONFIG_SECURITY_WHITEEGRET_INTERPRETER.\n");
+}
+
+static int check_whitelist(int *result, struct we_req_user *user)
+{
+       int ret;
+
+       switch (user->cmd) {
+       case CONTROL_EXEC:
+               ret = check_whitelist_exec(result, user);
+               break;
+       case CONTROL_READ:
+               ret = check_whitelist_terp(result, user);
+               break;
+       case CONTROL_FORK:
+               ret = check_fork_terp(result, user);
+               break;
+       case CONTROL_EXIT:
+               ret = check_exit_terp(result, user);
+               break;
+       }
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       int fd;
+       struct we_req_user *user;
+       struct we_ack ack;
+       char buf[1024];
+       int ret;
+
+       if (argc < 4) {
+               print_usage();
+               return -1;
+       }
+
+       init_terp_proc();
+       snprintf(not_permit_exe, NOTPERMITEXENAMELENGTH, "%s", argv[1]);
+       snprintf(monitor_interpreter, NOTPERMITEXENAMELENGTH, "%s", argv[2]);
+       snprintf(not_permit_script, NOTPERMITEXENAMELENGTH, "%s", argv[3]);
+
+       signal(SIGINT, sigint_catch);
+
+       if (daemon(0, 0) < 0) {
+               perror("daemon");
+               exit(EXIT_FAILURE);
+       }
+
+       fd = open(WE_DEV_PATH, O_RDWR, 0);
+       if (fd < 0) {
+               perror(WE_DEV_PATH);
+               exit(EXIT_FAILURE);
+       }
+       user = (struct we_req_user *)((void *)buf);
+
+       while (1) {
+               ret = read(fd, (char *)user, 1024);
+               if (ret < 0) {
+                       perror("read");
+                       continue;
+               }
+
+               ack.tgid = user->tgid;
+               check_whitelist(&ack.permit, user);
+
+               ret = write(fd, (char *)&ack, sizeof(ack));
+       }
+
+       close(fd);
+
+       return 0;
+}
-- 
2.7.4

Reply via email to