[PATCH] Trusted Path Execution LSM 0.2 (20050108)
From: Lorenzo Hernández García-Hierro
Date: Sat Jan 08 2005 - 13:17:50 EST
Hi,
Serge E. Hallyn contributed a patch for fix a few problems of the
kernel-configuration level support for the trusted group (outside the
groups acl support).
As suggested by Stephen D. Smalley, I've updated the file_mmap hook
checks logic, as some of statements are not needed if the initial struct
is present.
The new patch is attached, but again, extra information and
documentation can be found at http://selinux.tuxedo-es.org/tpe-lsm/ .
References (for initial release information):
[1]: http://lkml.org/lkml/2005/1/5/307 (original thread)
Please apply.
Cheers, -- Lorenzo Hernández García-Hierro <lorenzo@xxxxxxx>
[1024D/6F2B2DEC] [2048g/9AE91A22] Hardened Debian head developer &
project manager
diff -Nur ../linux-2.6.10/Documentation/tpe-lsm.txt linux-2.6.10-tpe/Documentation/tpe-lsm.txt
--- ../linux-2.6.10/Documentation/tpe-lsm.txt 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-tpe/Documentation/tpe-lsm.txt 2005-01-07 01:36:35.000000000 +0100
@@ -0,0 +1,103 @@
+Trusted Path Execution Linux Security Module
+Copyright (C) 2003 IBM Corp. <narahimi@xxxxxxxxxx>
+Copyright (C) 2005 Lorenzo Hernandez Garcia-Hierro <lorenzo@xxxxxxx>
+Author: Lorenzo Hernandez Garcia-Hierro (Original: Niki Rahimi)
+This file is distributed according to the GNU General Public License.
+This module was tested on the Linux kernel 2.6.9 and 2.6.10.
+
+The purpose of the Trusted Path Execution Linux Security Module is to enable a
+check in the Linux kernel to limit the running of executables in trusted paths
+so that the potential for malicious code to be run on the system is reduced.
+A trusted path is one in which the parent directory of a file is owned by root
+and is neither group nor other writeable.
+The module relies on a kernel hook which checks to see if the given path is
+trusted or not and who is the user (or group member) that caused the event (execution).
+This check takes place directly upon an attempt to execute the code by using the
+file_mmap and file_mprotect hooks which control how mmap() can do the memory mapping
+for an executable, preventing the engine to be bypassed by using tricks like the
+ld-linux.so.2 one or any other shared-library-wrapping trick.Also, the file_mprotect
+hook prevents mprotect() of being abused for bypass the TPE engine.
+Old bprm_check_security behavior is not anymore used and is dropped in the source.
+
+Limitations:
+Right now, the engine does not use the bprm_secureexec hook to
+prevent use of sensitive LD_{PRELOAD,DEBUG} variables by untrusted users or groups, but
+making these checks relying in kernel space has been demonstrated being less efficient
+than simply checking and having a well-configured user space.
+Also, script or source interpreters like sh for shell scripts, python, etc could still
+execute code as they run normally from trusted paths, the solution relies on having them
+in non trusted paths or even implementing an user space control tool, use SELinux or
+an advanced method for memory mappings execution.
+This features could be developed, but it's not a critical, blocking issue and in my opinion,
+they shouldn't rely on the kernel space.
+
+The module also creates two Trusted Path access control lists which can be accessed
+by a sysfs mountpoint, inside the ./tpefs/ subdir (ie: /sys/tpefs), writeable by root,
+who can add and delete uids (user id's) and a entire range of users using the (new) native
+support for per-gid (group id) basis access control lists. A user on the list is
+considered trusted.
+Also, it creates a procfs entry called "tpe" (ie: /proc/tpe) which provides
+version information, total amount of trusted users, total amount of trusted groups and
+other information, depending on the code revision), and those who want extra garbage
+from the kernel will like to enabled debugging by passing debug=1 to the module parameters.
+By default, root is hard coded onto this list with also a trusted gid
+which gets automatically added when selecting the "GID for trusted users" option in kernel
+configuration (SECURITY_TPE_TRUSTED_GID).
+
+Thus if user A attempts to run an executable in path A, the following scenarios
+can play out:
+
+1. Trusted user,trusted path = User is able to run the executable.
+2. Trusted user,trusted path,trusted group = User is able to run the executable.
+3. Trusted user,untrusted path = User is able to run the executable.
+4. Trusted user,untrusted path,trusted group = User is able to run the executable.
+5. Trusted user,untrusted path,untrusted group = User is able to run the executable.
+6. Untrusted user,trusted path = User is able to run the executable.
+7. Untrusted user,trusted path,trusted group = User is able to run the executable.
+8. Untrusted user,trusted path,untrusted group = User is able to run the executable.
+9. Untrusted user,untrusted path = User is not able to run the executable.#
+10. Untrusted user,untrusted path,trusted group = User is able to run the executable.
+11. Untrusted user,untrusted path,untrusted group= User is not able to run the executable.#
+
+In execution terms, untrusted users under untrusted groups and paths wouldn't
+be able to change or alter the memory layout nor mmap() executables in memory,
+preventing any type of untrusted execution.
+
+In short, if the path and user are both untrusted (and if the group is untrusted),
+execution will be denied sending a message with the uid,gid,euid,egid,pid and full path
+to binary that caused the event.
+
+In order to actually modify the access control list for TPE, the module uses
+a sysfs subsystem called tpefs. The tpefs contains four files; add, del, add-group
+and del-group.
+Performing read and write operations on the aforementioned files creates a user
+to system interface that will alter the TPE access control list. See
+"Modifying the TPE Access Control Lists" below for the methods of altering the list
+using these files.
+Note: The original two file approach was utilized rather than a single file in order to
+keep the code and administration of the module simple for both the kernel and
+the user, and it was when only uid-based access control lists were supported, now
+i've followed the same style to provide backwards compatibility.
+
+Installation:
+1. Recompile the kernel to include LSM and TPE as a module (or even get a
+ kernel-independent packaged TPE module.
+2. mount -t sysfs sysfs <mountpoint>
+3. modprobe tpe debug=1/0 (if you want to use debugging set to 1)
+4. See "Modifying the TPE Access Control Lists" below for instructions on how to
+add/delete users and groups to/from the list.
+
+Modifying the TPE Access Control Lists:
+
+- Adding a user : echo <uid> > <mountpoint>/tpefs/add
+- Deleting a user : echo <uid> > <mountpoint>/tpefs/del
+- Adding a group : echo <gid> > <mountpoint>/tpefs/add-group
+- Deleting a group : echo <gid> > <mountpoint>/tpefs/del-group
+- Show uid list to userspace: cat <mountpoint>/tpefs/add
+- Show gid list to userspace: cat <mountpoint>/tpefs/add-group
+- Show version and statistics information: cat /proc/tpe
+
+Note: Advanced users would be interested in writing a script or something
+to modify the access control lists in a fine-grained manner, but this is out
+of the goals of the TPE development, anyway, feel free to send your contributions
+to lorenzo@xxxxxxxx
diff -Nur ../linux-2.6.10/security/ffdd linux-2.6.10-tpe/security/ffdd
--- ../linux-2.6.10/security/ffdd 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-tpe/security/ffdd 2005-01-08 17:25:45.000000000 +0100
@@ -0,0 +1,160 @@
+/*
+ * Trusted Path Execution Security Module
+ *
+ * This module provides a Trusted Path Execution (TPE) engine to the
+ * Linux kernel. TPE originated as a kernel patch to OpenBSD 2.4 by
+ * route|daemon9 and Mike Schifman (see Phrack 54). IBM originally modified
+ * the original project to fit within the constraints of the LSM framework
+ * and so it should be noted that this is not the same project. Also,
+ * the module makes use of the sysfs filesystem.
+ * This module is a rewrite of the IBM's original code in order to add
+ * debugging, better information outputting, support for per-User-Groups
+ * access control lists at runtime and kernel-configuration level, a procfs
+ * interface for general information gathering from the TPE subsystem and the
+ * protection engine which in the original IBM's code was relying in bprm_set_security
+ * is now based in executables memory mappings, which makes it secure against
+ * shared libraries that can wrap untrusted executables and bypass the TPE
+ * subsystem, also adding a secondary protection against possible attempts to
+ * bypass the mmap()'ing checks by using PROT_READ instead of PROT_EXEC in
+ * mprotect() calls.
+ *
+ * Copyright (C) 2003 IBM Corp. <narahimi@xxxxxxxxxx>
+ * Copyright (C) 2005 Lorenzo Hernandez Garcia-Hierro <lorenzo@xxxxxxx>
+ * All rights reversed.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __TPE_H
+#define __TPE_H
+
+#include <linux/types.h>
+#include <asm/uaccess.h>
+
+/* Vermagic and /proc entry name */
+
+#define VERSION "0.2-20050107"
+#define LSM_VERSION NULL /* unused */
+#define TPE_PROC_ENTRY_NAME "tpe" /* /proc entry name */
+
+/* Per-user group basis protection stuff */
+
+#ifdef CONFIG_SECURITY_TPE_TRUSTED_GID
+static int tpe_trusted_gid = CONFIG_SECURITY_TPE_TRUSTED_GID;
+#else
+static int tpe_trusted_gid = 0;
+#endif
+
+/*
+ * syscall stuff
+ */
+#define TPE_ACL_SIZE 82 /* Maximum number of users in the list
+ * plus two. This was an original
+ * component of TPE. This will be
+ * fixed later on.
+ */
+
+#define TPE_INITIALIZER -1 /* A UID that isn't used */
+
+#define ACK 1 /* positive acknowledgement */
+#define NACK -1 /* negative acknowledgement */
+#define DUP 3 /* duplicate id return for tpe_add */
+
+/*
+ * Verify the path.
+ */
+#define TRUSTED_PATH(mode, uid) \
+(!(mode & (S_IWGRP | S_IWOTH)) && (uid == 0))
+
+static uid_t tpe_acl[TPE_ACL_SIZE]; /* trusted users list */
+static gid_t tpe_group_acl[TPE_ACL_SIZE]; /* trusted user groups list */
+static int tpe_acl_candidates; /* number of users on the list */
+static int tpe_acl_group_candidates; /* number of user groups on the list */
+
+/*
+ * Verify the user. This macro is passed the user's ID from the
+ * tpe_bprm_set_security hook.
+ */
+
+#define TRUSTED_USER(UID) (tpe_verify(UID) == ACK)
+
+/*
+ * Verify the user group. This macro is passed the user's group ID from the
+ * tpe_bprm_set_security hook.
+ */
+
+#define TRUSTED_GROUP(GID) (tpe_group_verify(GID) == ACK)
+
+/* Initialize the array with default values (TPE_INITIALIZER). */
+
+/* Debugging and outputting functions */
+
+static inline void tpe_init(void)
+{
+ memset(tpe_acl, TPE_INITIALIZER, sizeof(uid_t) * TPE_ACL_SIZE);
+ printk(KERN_INFO "TPE: Access Control List created.\n");
+ tpe_acl_candidates = 1;
+ if (!(tpe_trusted_gid == 0)) {
+ tpe_acl_group_candidates = 2;
+ } else {
+ tpe_acl_group_candidates = 1;
+ }
+ tpe_acl[0] = 0;
+ if (!(tpe_trusted_gid == 0)) {
+ tpe_group_acl[0] = 0;
+
+ tpe_group_acl[1] = tpe_trusted_gid;
+ } else {
+ tpe_group_acl[0] = 0;
+ }
+}
+
+/* Locate a uid in the list */
+static inline int tpe_search(uid_t candidate)
+{
+ int i;
+ for (i = 0; i < tpe_acl_candidates; i++) {
+ if (candidate == tpe_acl[i]) {
+ return i;
+ }
+ }
+ return NACK;
+}
+
+/* Verify a candidate user. */
+static inline int tpe_verify(uid_t candidate)
+{
+ if ((tpe_search(candidate)) != NACK) {
+ return (ACK);
+ }
+ return (NACK);
+}
+
+/* Verify a candidate user group. */
+static inline int tpe_search_group(gid_t group_candidate)
+{
+ int i;
+ for (i = 0; i < tpe_acl_group_candidates; i++) {
+ if (group_candidate == tpe_group_acl[i]) {
+ return i;
+ }
+ }
+ return NACK;
+}
+static inline int tpe_group_verify(gid_t group_candidate)
+{
+ if ((tpe_search_group(group_candidate)) != NACK) {
+ return (ACK);
+ }
+ return (NACK);
+}
+
+#endif /* __TPE_H */
diff -Nur ../linux-2.6.10/security/Kconfig linux-2.6.10-tpe/security/Kconfig
--- ../linux-2.6.10/security/Kconfig 2005-01-03 19:43:05.000000000 +0100
+++ linux-2.6.10-tpe/security/Kconfig 2005-01-07 00:48:29.000000000 +0100
@@ -84,6 +84,36 @@
If you are unsure how to answer this question, answer N.
+config SECURITY_TPE
+ tristate "Trusted Path Execution (EXPERIMENTAL)"
+ depends on SECURITY && EXPERIMENTAL
+ help
+ The TPE module enforces a check on the running of executables.
+ It will not allow execution if the program is located in a
+ "trusted path" and the current user is "untrusted". A trusted
+ path is one which is root owned and neither group nor other
+ writeable. A user is considered trusted if their uid is added
+ to a trusted list in memory, also, user groups can be trusted
+ in kernel compile-time and runtime by adding them to the gid-basis
+ access control list.Root is trusted, by default.A proc interface
+ /proc/tpe is created when module loads, it shows version and ACL
+ information to use third-party checkers or scripts.
+
+ (c) 2005, Lorenzo Hernandez Garcia-Hierro <lorenzo@xxxxxxx>.
+
+ If you are unsure how to answer this question, answer N.
+
+config SECURITY_TPE_TRUSTED_GID
+ int "GID for trusted users"
+ depends on SECURITY_TPE
+ default 1337
+ help
+ Here you can choose the GID to disable trusted path protection for.
+ Users relying under the group with id specified here will have TPE
+ disabled by default, so, they could represent a security risk for
+ the rest of users.Please, be sure that you can really trust in the
+ members of this group.
+
source security/selinux/Kconfig
endmenu
diff -Nur ../linux-2.6.10/security/Makefile linux-2.6.10-tpe/security/Makefile
--- ../linux-2.6.10/security/Makefile 2005-01-03 19:43:05.000000000 +0100
+++ linux-2.6.10-tpe/security/Makefile 2005-01-04 02:10:45.000000000 +0100
@@ -17,3 +17,4 @@
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
+obj-$(CONFIG_SECURITY_TPE) += tpe.o
diff -Nur ../linux-2.6.10/security/tpe.c linux-2.6.10-tpe/security/tpe.c
--- ../linux-2.6.10/security/tpe.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-tpe/security/tpe.c 2005-01-08 17:29:17.000000000 +0100
@@ -0,0 +1,731 @@
+/*
+ * Trusted Path Execution Security Module
+ *
+ * This module provides a Trusted Path Execution (TPE) engine to the
+ * Linux kernel. TPE originated as a kernel patch to OpenBSD 2.4 by
+ * route|daemon9 and Mike Schifman (see Phrack 54). IBM originally modified
+ * the original project to fit within the constraints of the LSM framework
+ * and so it should be noted that this is not the same project. Also,
+ * the module makes use of the sysfs filesystem.
+ * This module is a rewrite of the IBM's original code in order to add
+ * debugging, better information outputting, support for per-User-Groups
+ * access control lists at runtime and kernel-configuration level, a procfs
+ * interface for general information gathering from the TPE subsystem and the
+ * protection engine which in the original IBM's code was relying in bprm_set_security
+ * is now based in executables memory mappings, which makes it secure against
+ * shared libraries that can wrap untrusted executables and bypass the TPE
+ * subsystem, also adding a secondary protection against possible attempts to
+ * bypass the mmap()'ing checks by using PROT_READ instead of PROT_EXEC in
+ * mprotect() calls.
+ *
+ * Copyright (C) 1998 route|daemon9 and Mike D. Schiffman
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman <gregkh@xxxxxxxxxx>
+ * Copyright (C) 2003 IBM Corp. <narahimi@xxxxxxxxxx>
+ * Copyright (C) 2005 Lorenzo Hernandez Garcia-Hierro <lorenzo@xxxxxxx>
+ * All rights reversed.
+ *
+ * The following people contributed to this:
+ * - Stephen D. Smalley <sds@xxxxxxxxxxxxxx> (ideas, suggestions...)
+ * - Chris Wright <chrisw@xxxxxxxx> (help on vma structs)
+ * - Brad Spengler <spender@xxxxxxxxxxxxxx>(code safety reviews)
+ * - Seth Arnold <sarnold@xxxxxxxxxxx> (memory use related fixes)
+ * - Serge E. Hallyn <serue@xxxxxxxxxx> (fixes,comments)
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <linux/pagemap.h>
+#include <linux/namei.h>
+#include <linux/vfs.h>
+#include <linux/mount.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/elf.h>
+#include <linux/file.h>
+#include "tpe.h"
+
+static int secondary;
+static spinlock_t tpe_acl_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t tpe_group_acl_lock = SPIN_LOCK_UNLOCKED;
+
+/* debugging */
+static int debug = 0;
+
+/* get debug=1/0 param */
+module_param(debug, bool, 0600);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+#if defined(CONFIG_SECURITY_TPE_MODULE)
+#define LEGACY_NAME THIS_MODULE->name
+#else
+#define LEGACY_NAME "tpe"
+#endif
+#define MY_NAME "TPE"
+
+/* Module information */
+#define DESCRIPTION "Trusted Path Execution LSM Implementation"
+#define AUTHOR "Lorenzo Hernandez Garcia-Hierro <lorenzo@xxxxxxx>"
+#define LICENSE "GPL"
+
+/* TPE /proc entry */
+struct proc_dir_entry *TPE_pentry;
+
+/* Outputting and debugging functions */
+/* Debug should be explicitly enabled (debug=1) to give output back from dbg() */
+#define dbg(fmt, arg...) \
+ do { \
+ if (1 && debug) { \
+ printk(KERN_DEBUG "%s: " fmt , MY_NAME, ## arg); \
+ } \
+ } while (0)
+
+/* KERN_INFO messages use kinfo() rather than printk() for better outputting layout */
+#define kinfo(fmt, arg...) \
+ do { \
+ if (1) { \
+ printk(KERN_INFO "%s: " fmt , MY_NAME, ## arg); \
+ } \
+ } while (0)
+
+/* Insertion sort the list. */
+static void tpe_sort(int low, int high)
+{ /* (list low element, list high element) */
+ int i, j, n;
+ /* Standard insertion sort. */
+ for (i = low + 1; i <= high; i++) {
+ if (tpe_acl[i] < tpe_acl[low]) {
+ tpe_acl[low] ^= tpe_acl[i];
+ tpe_acl[i] ^= tpe_acl[low];
+ tpe_acl[low] ^= tpe_acl[i];
+ }
+ }
+ /* tpe_acl */
+ for (i = low + 2; i <= high; i++) {
+ j = i;
+ n = tpe_acl[i];
+ while (n < tpe_acl[j - 1]) {
+ tpe_acl[j] = tpe_acl[j - 1];
+ j--;
+ }
+ tpe_acl[j] = n;
+ }
+}
+static void tpe_group_sort(int low, int high)
+{ /* (list low element, list high element) */
+ int i, j, n;
+ /* Standard insertion sort for tpe_group_acl. */
+ for (i = low + 1; i <= high; i++) {
+ if (tpe_group_acl[i] < tpe_group_acl[low]) {
+ tpe_group_acl[low] ^= tpe_group_acl[i];
+ tpe_group_acl[i] ^= tpe_group_acl[low];
+ tpe_group_acl[low] ^= tpe_group_acl[i];
+ }
+ }
+ /* tpe_group_acl */
+ for (i = low + 2; i <= high; i++) {
+ j = i;
+ n = tpe_group_acl[i];
+ while (n < tpe_group_acl[j - 1]) {
+ tpe_group_acl[j] = tpe_group_acl[j - 1];
+ j--;
+ }
+ tpe_group_acl[j] = n;
+ }
+}
+
+/* Attempt to add an UID candidate to the list. */
+static int tpe_add(uid_t add_candidate)
+{
+ int retval = -EINVAL;
+
+ /* Full list. */
+ if (tpe_acl_candidates == (TPE_ACL_SIZE - 2)) {
+ kinfo("Unable to add user %d. List is full.\n", add_candidate);
+ goto out;
+ }
+
+ if (add_candidate == 0) {
+ kinfo("Invalid user id. Cannot add.\n");
+ goto out;
+ }
+
+ /* Don't add duplicates */
+ if ((tpe_search(add_candidate)) == NACK) {
+ /* Add to the end of the list, then sort. */
+ tpe_acl_candidates++;
+ tpe_acl[tpe_acl_candidates] = add_candidate;
+ tpe_acl[tpe_acl_candidates + 1] = '\0'; /* terminate array */
+ tpe_sort(0, tpe_acl_candidates);
+ kinfo("UID %d added as trusted to access control list\n",
+ add_candidate);
+ } else {
+ kinfo("Duplicate UID %d not added\n", add_candidate);
+ goto out;
+ }
+ retval = 0;
+ out:
+ return retval;
+}
+
+/* Attempt to add an GID candidate to the list. */
+static int tpe_group_add(gid_t add_candidate)
+{
+ int retval = -EINVAL;
+
+ /* Full list. */
+ if (tpe_acl_group_candidates == (TPE_ACL_SIZE - 2)) {
+ kinfo("Unable to add user %d. List is full.\n", add_candidate);
+ goto out;
+ }
+
+ if (add_candidate == 0) {
+ kinfo("Invalid userid. Cannot add.\n");
+ goto out;
+ }
+
+ /* Don't add duplicates */
+ if ((tpe_search_group(add_candidate)) == NACK) {
+ /* Add to the end of the list, then sort. */
+ tpe_acl_group_candidates++;
+ tpe_group_acl[tpe_acl_group_candidates] = add_candidate;
+ tpe_group_acl[tpe_acl_group_candidates + 1] = '\0'; /* terminate array */
+ tpe_group_sort(0, tpe_acl_group_candidates);
+ kinfo("GID %d added as trusted to access control list\n",
+ add_candidate);
+ } else {
+ kinfo("Duplicate GID %d not added\n", add_candidate);
+ goto out;
+ }
+ retval = 0;
+ out:
+ return retval;
+}
+
+/* Attempt to remove a candidate from the list. Only fails if the entry is */
+/* not there. */
+static int tpe_remove(uid_t rem_candidate)
+{
+ int n;
+ int retval = -EINVAL;
+ if (tpe_acl_candidates == 0) {
+ /* Empty list */
+ goto out;
+ }
+ if (rem_candidate == 0) {
+ kinfo("Invalid userid. Cannot remove.\n");
+ goto out;
+ }
+
+ n = tpe_search(rem_candidate);
+ if (n != NACK) {
+ /* Remove candidate (mark slot as unused), resort the list. */
+ tpe_acl[n] = TPE_INITIALIZER;
+ tpe_acl_candidates--;
+ tpe_sort(0, tpe_acl_candidates);
+ kinfo("UID %d removed from trust list\n", rem_candidate);
+ retval = 0;
+ goto out;
+ }
+ /* Not found. */
+ kinfo("UID %d not found in trust list\n", rem_candidate);
+ out:
+ return retval;
+}
+
+/* GID removing */
+static int tpe_group_remove(gid_t rem_candidate)
+{
+ int n;
+ int retval = -EINVAL;
+ if (tpe_acl_group_candidates == 0) {
+ /* Empty groups list */
+ goto out;
+ }
+ if (rem_candidate == 0) {
+ kinfo("Invalid GID. Cannot remove.\n");
+ goto out;
+ }
+
+ n = tpe_search_group(rem_candidate);
+ if (n != NACK) {
+ /* Remove candidate (mark slot as unused), resort the list. */
+ tpe_group_acl[n] = TPE_INITIALIZER;
+ tpe_acl_group_candidates--;
+ tpe_group_sort(0, tpe_acl_group_candidates);
+ kinfo("GID %d removed from trust list\n", rem_candidate);
+ retval = 0;
+ goto out;
+ }
+ /* Not found. */
+ kinfo("GID %d not found in trust list\n", rem_candidate);
+ out:
+ return retval;
+}
+
+/* Beginning of a sysfs subsystem for tpe */
+static struct subsystem tpefs_subsys;
+
+struct tpe_list {
+ char *name;
+
+ struct list_head slot_list;
+ struct kobject kobj;
+};
+
+struct tpefs_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct tpe_list *, char *);
+ ssize_t(*store) (struct tpe_list *, const char *, size_t);
+};
+
+static ssize_t tpefs_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct tpe_list *list = container_of(kobj, struct tpe_list, kobj);
+ struct tpefs_attribute *attribute = container_of(attr, struct
+ tpefs_attribute, attr);
+ return attribute->show ? attribute->show(list, buf) : 0;
+}
+
+static ssize_t tpefs_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct tpe_list *list = container_of(kobj, struct tpe_list, kobj);
+ struct tpefs_attribute *attribute = container_of(attr, struct
+ tpefs_attribute, attr);
+ return attribute->store ? attribute->store(list, buf, len) : 0;
+}
+
+static struct sysfs_ops tpefs_sysfs_ops = {
+ .show = tpefs_attr_show,
+ .store = tpefs_attr_store,
+};
+
+static struct kobj_type tpefs_ktype = {
+ .sysfs_ops = &tpefs_sysfs_ops
+};
+
+static decl_subsys(tpefs, &tpefs_ktype, NULL);
+
+static ssize_t trustedlistadd_read_file(struct tpe_list *list, char *buf)
+{
+ int i;
+ int retval = 0;
+ char *user = NULL;
+ char *buffer = kmalloc(400, GFP_KERNEL);
+
+ user = (char *)__get_free_page(GFP_KERNEL);
+ if (!user)
+ return -ENOMEM;
+
+ if (!buffer)
+ return -ENOMEM;
+
+ if (tpe_acl == NULL) {
+ kinfo("Empty Access Control List\n");
+ free_page((unsigned long)user);
+ return -ENODATA;
+ }
+
+ buffer[0] = '\0';
+ kinfo("%d trusted user(s): \n", tpe_acl_candidates);
+ spin_lock(&tpe_acl_lock);
+ for (i = 0; i < tpe_acl_candidates; i++) {
+ printk(KERN_INFO "%d ", tpe_acl[i]);
+ retval = sprintf(user, "%d\n", tpe_acl[i]);
+ strcat(buffer, user);
+ }
+ /* leave printk() calls alone, not kinfo() */
+ printk(KERN_INFO "\n");
+ spin_unlock(&tpe_acl_lock);
+
+ retval = snprintf(buf, 400, "%s\n", buffer);
+
+ kfree(buffer); /* we kfree() the kmalloc()'ed buffer */
+ free_page((unsigned long)user);
+ return retval;
+}
+
+static ssize_t trustedlistadd_write_file(struct tpe_list *list, const char *buf,
+ size_t count)
+{
+ int retval;
+ unsigned long add_candidate;
+
+ add_candidate = simple_strtoul(buf, NULL, 10);
+
+ dbg("value of add_candidate is %d.\n", (int)add_candidate);
+ spin_lock(&tpe_acl_lock);
+ retval = tpe_add(add_candidate);
+ spin_unlock(&tpe_acl_lock);
+ if (retval) {
+ return retval;
+ }
+ return count;
+
+}
+
+/* per-GID basis ACL support */
+
+static ssize_t trustedlistadd_group_write_file(struct tpe_list *list,
+ const char *buf, size_t count)
+{
+ int retval;
+ unsigned long add_group_candidate;
+
+ add_group_candidate = simple_strtoul(buf, NULL, 10);
+
+ dbg("value of add_group_candidate is %d.\n", (int)add_group_candidate);
+ spin_lock(&tpe_group_acl_lock);
+ retval = tpe_group_add(add_group_candidate); /* tpe_group_add() ninja monkey */
+ spin_unlock(&tpe_group_acl_lock);
+ if (retval) {
+ return retval;
+ }
+ return count;
+
+}
+static ssize_t trustedlistadd_group_read_file(struct tpe_list *list, char *buf)
+{
+ int i;
+ int retval = 0;
+ char *group = NULL;
+ char *buffer = kmalloc(400, GFP_KERNEL);
+
+ group = (char *)__get_free_page(GFP_KERNEL);
+ if (!group)
+ return -ENOMEM;
+
+ if (!buffer)
+ return -ENOMEM;
+
+ if (tpe_group_acl == NULL) {
+ kinfo("Empty user groups Access Control List\n");
+ free_page((unsigned long)group);
+ return -ENODATA;
+ }
+
+ buffer[0] = '\0';
+ kinfo("%d trusted group(s): \n", tpe_acl_group_candidates);
+ spin_lock(&tpe_group_acl_lock);
+ for (i = 0; i < tpe_acl_group_candidates; i++) {
+ printk(KERN_INFO "%d ", tpe_group_acl[i]);
+ retval = sprintf(group, "%d\n", tpe_group_acl[i]);
+ strcat(buffer, group);
+ }
+ /* leave printk() calls alone, not kinfo() */
+ printk(KERN_INFO "\n");
+ spin_unlock(&tpe_group_acl_lock);
+
+ retval = snprintf(buf, 400, "%s\n", buffer);
+
+ kfree(buffer); /* we kfree() the kmalloc()'ed buffer */
+ free_page((unsigned long)group);
+ return retval;
+}
+
+/* ends sysfs tpefs group acl management */
+
+struct tpefs_attribute tpefs_listadd_attr = {
+ .attr = {.name = "add",.mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .show = trustedlistadd_read_file,
+ .store = trustedlistadd_write_file
+};
+
+/* listadd_group per-GID basis ACL */
+struct tpefs_attribute tpefs_listadd_group_attr = {
+ .attr = {.name = "add-group",.mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .show = trustedlistadd_group_read_file,
+ .store = trustedlistadd_group_write_file
+};
+
+/* trusted UIDs deletion */
+static ssize_t trustedlistdel_write_file(struct tpe_list *list, const char *buf,
+ size_t count)
+{
+ int retval;
+ unsigned long rem_candidate;
+
+ rem_candidate = simple_strtoul(buf, NULL, 10);
+
+ dbg("value of rem_candidate is %d.\n", (int)rem_candidate);
+ spin_lock(&tpe_acl_lock);
+ retval = tpe_remove(rem_candidate);
+ spin_unlock(&tpe_acl_lock);
+ if (retval) {
+ return retval;
+ }
+ return count;
+
+}
+
+/* trusted GIDs deletion */
+static ssize_t trustedlistdel_group_write_file(struct tpe_list *list,
+ const char *buf, size_t count)
+{
+ int retval;
+ unsigned long rem_group_candidate;
+
+ rem_group_candidate = simple_strtoul(buf, NULL, 10);
+
+ dbg("value of rem_candidate is %d.\n", (int)rem_group_candidate);
+ spin_lock(&tpe_group_acl_lock);
+ retval = tpe_group_remove(rem_group_candidate);
+ spin_unlock(&tpe_group_acl_lock);
+ if (retval) {
+ return retval;
+ }
+ return count;
+
+}
+
+struct tpefs_attribute tpefs_listdel_attr = {
+ .attr = {.name = "del",.mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .store = trustedlistdel_write_file
+};
+
+/* sysfs/tpefs/del-group */
+struct tpefs_attribute tpefs_listdel_group_attr = {
+ .attr = {.name = "del-group",.mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .store = trustedlistdel_group_write_file
+};
+
+/* TPE /proc entry managing */
+ssize_t
+procfile_read(char *buffer,
+ char **buffer_location,
+ off_t offset, int buffer_length, int *eof, void *data)
+{
+ int len = 0; /* The number of bytes actually used */
+ char *vermagic = VERSION;
+ if (offset > 0) {
+ dbg("Offset %d : /proc/tpe : procfile_read, \
+ wrote %d bytes\n", (int)(offset), len);
+ *eof = 1;
+ return len;
+ }
+ /* We write the data to the procfs entry */
+ len = sprintf(buffer,
+ "Version: %s\nTrusted users: %d\nTrusted groups: %d\n",
+ vermagic, tpe_acl_candidates, tpe_acl_group_candidates);
+ /* Voila! */
+ dbg("Leaving /proc/tpe : procfile_read, wrote %d Bytes\n", len);
+ return len;
+}
+
+/* Module code */
+
+/* prevent SIGKILL in execve() */
+
+/*
+ Stephen D. Smalley suggested this type of checks, the following checks will prevent
+ for example untrusted executables being abused within the execution context of ld-linux
+ shared library, and also they are a replacement of the original,limited,
+ tpe_bprm_set_security hook.
+ */
+/*
+ * file_mmap hook -> tpe_file_mmap
+ */
+static int tpe_file_mmap(struct file *file, unsigned long prot,
+ unsigned long flags)
+{
+ if ((file) && (current->uid) && (current->gid)
+ && (prot & PROT_EXEC)) {
+ /* Get the executable execution uid and mode */
+ uid_t mpuid = file->f_dentry->d_parent->d_inode->i_uid;
+ mode_t mpmode = file->f_dentry->d_parent->d_inode->i_mode;
+
+ /* Check the executable properties */
+ /* attempt to make a file mapping executable, run TPE trusting test */
+ if ((!TRUSTED_PATH(mpmode, mpuid))
+ && (!TRUSTED_USER(current->uid))
+ && (!TRUSTED_GROUP(current->gid))) {
+
+ /* get a free page and allocate executable real path */
+ char *fptmp =
+ (char *)__get_free_page(GFP_KERNEL), *exfpath;
+
+ /* "Are we out of memory? I can't remember" -ENOMEM in Halloween Panic meeting. */
+ if (!(fptmp))
+ return -ENOMEM;
+
+ exfpath =
+ d_path(file->f_dentry, file->f_vfsmnt, fptmp,
+ PAGE_SIZE);
+
+ /* You can still believe in Ninja Code Monkeys... */
+ printk(KERN_ALERT "TPE: Untrusted execution: %s "
+ "uid/euid=%d/%d gid/egid=%d/%d suid/sgid=%d/%d pid=%d"
+ "\n", exfpath, current->uid, current->euid,
+ current->gid, current->egid, current->suid,
+ current->sgid, current->pid);
+
+ free_page((unsigned long)fptmp); /* free the fptmp page */
+
+ return -EACCES; /* due to elf_map() this will cause a SIGKILL */
+ }
+ }
+ return 0;
+}
+
+/*
+ * file_mprotect hook -> tpe_file_mprotect
+ */
+static int tpe_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
+{
+ if ((vma->vm_file) && (prot & PROT_EXEC)) {
+ /* Get the executable execution uid and mode */
+ uid_t mpuid = vma->vm_file->f_dentry->d_parent->d_inode->i_uid;
+ mode_t mpmode =
+ vma->vm_file->f_dentry->d_parent->d_inode->i_mode;
+
+ if ((!TRUSTED_PATH(mpmode, mpuid))
+ && (!TRUSTED_USER(current->uid))
+ && (!TRUSTED_GROUP(current->gid))) {
+ /* get a free page and allocate executable real path */
+ char *fptmp =
+ (char *)__get_free_page(GFP_KERNEL), *exfpath;
+
+ if (!(fptmp))
+ return -ENOMEM;
+
+ exfpath =
+ d_path(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt, fptmp, PAGE_SIZE);
+
+ /* ...but they don't trust in mprotect() */
+ printk(KERN_ALERT
+ "TPE: Untrusted execution by mprotect(): %s "
+ "uid/euid=%d/%d gid/egid=%d/%d suid/sgid=%d/%d pid=%d"
+ "\n", exfpath, current->uid, current->euid,
+ current->gid, current->egid, current->suid,
+ current->sgid, current->pid);
+
+ free_page((unsigned long)fptmp); /* free the fptmp page */
+
+ return -EACCES;
+ }
+ }
+ return 0;
+}
+
+/*
+ TPE security hooks
+*/
+struct security_operations tpe_security_ops = {
+ file_mmap:tpe_file_mmap,
+ file_mprotect:tpe_file_mprotect,
+};
+
+static int __init tpe_module_init(void)
+{
+ int retval;
+ int cfoo = 0;
+ /* register ourselves with the security framework */
+ if (register_security(&tpe_security_ops)) {
+ printk(KERN_INFO
+ "Failure registering tpe module with the kernel\n");
+ /* try registering with primary module */
+ if (mod_reg_security(LEGACY_NAME, &tpe_security_ops)) {
+ printk(KERN_INFO "Failure registering tpe module "
+ "with primary security module.\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ /* register tpe subsystem */
+ kinfo("Registering TPE subsystem.\n");
+ retval = subsystem_register(&tpefs_subsys);
+ if (retval) {
+ kinfo("subsystem_register failed with %d\n", retval);
+ return retval;
+ }
+ kinfo("Registering tpefs support for sysfs.\n");
+ sysfs_create_file(&tpefs_subsys.kset.kobj, &tpefs_listadd_attr.attr);
+ sysfs_create_file(&tpefs_subsys.kset.kobj, &tpefs_listdel_attr.attr);
+ /* create the group/gid acl sysfs tpefs files */
+ sysfs_create_file(&tpefs_subsys.kset.kobj,
+ &tpefs_listadd_group_attr.attr);
+ sysfs_create_file(&tpefs_subsys.kset.kobj,
+ &tpefs_listdel_group_attr.attr);
+
+ kinfo("Registering with LSM subsystem.\n");
+ tpe_init();
+ /* TPE /proc/ "bilbo" entry begins :) */
+ TPE_pentry = create_proc_entry(TPE_PROC_ENTRY_NAME, 0644, NULL);
+ TPE_pentry->read_proc = procfile_read;
+ TPE_pentry->owner = THIS_MODULE;
+ TPE_pentry->mode = S_IFREG | S_IRUGO;
+ TPE_pentry->uid = 0;
+ TPE_pentry->gid = 0;
+ TPE_pentry->size = 20;
+ if (TPE_pentry == NULL) {
+ cfoo = -ENOMEM;
+ /**/ remove_proc_entry(TPE_PROC_ENTRY_NAME, &proc_root);
+ kinfo("Error: Could not initialize /proc/tpe\n");
+ } else {
+ kinfo("/proc entry initialized.\n");
+ }
+ kinfo("Trusted Path Execution engine initialized.\n");
+ return cfoo;
+}
+
+static void __exit tpe_exit(void)
+{
+ remove_proc_entry(TPE_PROC_ENTRY_NAME, &proc_root); /* remove TPE /proc entry */
+ sysfs_remove_file(&tpefs_subsys.kset.kobj, &tpefs_listadd_attr.attr);
+ sysfs_remove_file(&tpefs_subsys.kset.kobj, &tpefs_listdel_attr.attr);
+ /* remove sysfs/tpefs/add-group and del-group */
+ sysfs_remove_file(&tpefs_subsys.kset.kobj,
+ &tpefs_listadd_group_attr.attr);
+ sysfs_remove_file(&tpefs_subsys.kset.kobj,
+ &tpefs_listdel_group_attr.attr);
+ subsystem_unregister(&tpefs_subsys);
+
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(LEGACY_NAME, &tpe_security_ops))
+ printk(KERN_INFO "Failure unregistering tpe module "
+ "with primary module.\n");
+ return;
+ }
+
+ if (unregister_security(&tpe_security_ops)) {
+ printk(KERN_INFO
+ "Failure unregistering tpe module with the kernel\n");
+ }
+ kinfo("Trusted Path Execution subsystem unloaded.\n");
+
+}
+
+module_init(tpe_module_init);
+module_exit(tpe_exit);
+
+/* Modinfo perls */
+MODULE_DESCRIPTION(DESCRIPTION);
+MODULE_AUTHOR(AUTHOR);
+MODULE_LICENSE(LICENSE);
diff -Nur ../linux-2.6.10/security/tpe.h linux-2.6.10-tpe/security/tpe.h
--- ../linux-2.6.10/security/tpe.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10-tpe/security/tpe.h 2005-01-08 19:01:24.786820280 +0100
@@ -0,0 +1,160 @@
+/*
+ * Trusted Path Execution Security Module
+ *
+ * This module provides a Trusted Path Execution (TPE) engine to the
+ * Linux kernel. TPE originated as a kernel patch to OpenBSD 2.4 by
+ * route|daemon9 and Mike Schifman (see Phrack 54). IBM originally modified
+ * the original project to fit within the constraints of the LSM framework
+ * and so it should be noted that this is not the same project. Also,
+ * the module makes use of the sysfs filesystem.
+ * This module is a rewrite of the IBM's original code in order to add
+ * debugging, better information outputting, support for per-User-Groups
+ * access control lists at runtime and kernel-configuration level, a procfs
+ * interface for general information gathering from the TPE subsystem and the
+ * protection engine which in the original IBM's code was relying in bprm_set_security
+ * is now based in executables memory mappings, which makes it secure against
+ * shared libraries that can wrap untrusted executables and bypass the TPE
+ * subsystem, also adding a secondary protection against possible attempts to
+ * bypass the mmap()'ing checks by using PROT_READ instead of PROT_EXEC in
+ * mprotect() calls.
+ *
+ * Copyright (C) 2003 IBM Corp. <narahimi@xxxxxxxxxx>
+ * Copyright (C) 2005 Lorenzo Hernandez Garcia-Hierro <lorenzo@xxxxxxx>
+ * All rights reversed.
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __TPE_H
+#define __TPE_H
+
+#include <linux/types.h>
+#include <asm/uaccess.h>
+
+/* Vermagic and /proc entry name */
+
+#define VERSION "0.2-20050108"
+#define LSM_VERSION NULL /* unused */
+#define TPE_PROC_ENTRY_NAME "tpe" /* /proc entry name */
+
+/* Per-user group basis protection stuff */
+
+#ifdef CONFIG_SECURITY_TPE_TRUSTED_GID
+static int tpe_trusted_gid = CONFIG_SECURITY_TPE_TRUSTED_GID;
+#else
+static int tpe_trusted_gid = 0;
+#endif
+
+/*
+ * syscall stuff
+ */
+#define TPE_ACL_SIZE 82 /* Maximum number of users in the list
+ * plus two. This was an original
+ * component of TPE. This will be
+ * fixed later on.
+ */
+
+#define TPE_INITIALIZER -1 /* A UID that isn't used */
+
+#define ACK 1 /* positive acknowledgement */
+#define NACK -1 /* negative acknowledgement */
+#define DUP 3 /* duplicate id return for tpe_add */
+
+/*
+ * Verify the path.
+ */
+#define TRUSTED_PATH(mode, uid) \
+(!(mode & (S_IWGRP | S_IWOTH)) && (uid == 0))
+
+static uid_t tpe_acl[TPE_ACL_SIZE]; /* trusted users list */
+static gid_t tpe_group_acl[TPE_ACL_SIZE]; /* trusted user groups list */
+static int tpe_acl_candidates; /* number of users on the list */
+static int tpe_acl_group_candidates; /* number of user groups on the list */
+
+/*
+ * Verify the user. This macro is passed the user's ID from the
+ * tpe_bprm_set_security hook.
+ */
+
+#define TRUSTED_USER(UID) (tpe_verify(UID) == ACK)
+
+/*
+ * Verify the user group. This macro is passed the user's group ID from the
+ * tpe_bprm_set_security hook.
+ */
+
+#define TRUSTED_GROUP(GID) (tpe_group_verify(GID) == ACK)
+
+/* Initialize the array with default values (TPE_INITIALIZER). */
+
+/* Debugging and outputting functions */
+
+static inline void tpe_init(void)
+{
+ memset(tpe_acl, TPE_INITIALIZER, sizeof(uid_t) * TPE_ACL_SIZE);
+ printk(KERN_INFO "TPE: Access Control List created.\n");
+ tpe_acl_candidates = 1;
+ if (!(tpe_trusted_gid == 0)) {
+ tpe_acl_group_candidates = 2;
+ } else {
+ tpe_acl_group_candidates = 1;
+ }
+ tpe_acl[0] = 0;
+ if (!(tpe_trusted_gid == 0)) {
+ tpe_group_acl[0] = 0;
+
+ tpe_group_acl[1] = tpe_trusted_gid;
+ } else {
+ tpe_group_acl[0] = 0;
+ }
+}
+
+/* Locate a uid in the list */
+static inline int tpe_search(uid_t candidate)
+{
+ int i;
+ for (i = 0; i < tpe_acl_candidates; i++) {
+ if (candidate == tpe_acl[i]) {
+ return i;
+ }
+ }
+ return NACK;
+}
+
+/* Verify a candidate user. */
+static inline int tpe_verify(uid_t candidate)
+{
+ if ((tpe_search(candidate)) != NACK) {
+ return (ACK);
+ }
+ return (NACK);
+}
+
+/* Verify a candidate user group. */
+static inline int tpe_search_group(gid_t group_candidate)
+{
+ int i;
+ for (i = 0; i < tpe_acl_group_candidates; i++) {
+ if (group_candidate == tpe_group_acl[i]) {
+ return i;
+ }
+ }
+ return NACK;
+}
+static inline int tpe_group_verify(gid_t group_candidate)
+{
+ if ((tpe_search_group(group_candidate)) != NACK) {
+ return (ACK);
+ }
+ return (NACK);
+}
+
+#endif /* __TPE_H */
Attachment:
signature.asc
Description: Esta parte del mensaje =?ISO-8859-1?Q?est=E1?= firmadadigitalmente