[LWN Logo]
[LWN.net]
From:	 "Lachlan McIlroy" <lachlan@adacel.com.au>
To:	 <linux-security-module@wirex.com>
Subject: Possible system call interface for LSM
Date:	 Thu, 9 Aug 2001 14:01:30 +1000


There was some minor discussion recently about modules
needing to modify the system call table to create module
specific system calls.  It prompted me to investigate a
fixed system call for LSM that will multiplex the variety
of system calls required for each different security
scheme.  I've attached a patch of the proposed idea for
people to comment on.

The basis of the patch is to create a new system call
(sys_security) that accepts generic arguments (much like
ioctl) and performs the copy_from_user() and
copy_to_user() so the module doesn't have to worry about
it.  This method requires that the application (or an
associated library) know the format of the data that the
module is expecting.  For that reason, it could be
problematic if library A executed the system call of
module B.  I've added a module id field to the
security_ops structure that is set by the module when
loaded and is checked against the module id provided by
the application (or library) when the system call is
executed.

I'd appreciate any thoughts on this approach.

---
Lachlan McIlroy                    Phone: +61 3 9596 4155
Trusted Linux                        Fax: +61 3 9596 2960
Adacel Technologies Ltd                    www.adacel.com


diff -Naur linux_2.4.7_lsm/arch/i386/kernel/entry.S linux_2.4.7_lsm_syscall/arch/i386/kernel/entry.S
--- linux_2.4.7_lsm/arch/i386/kernel/entry.S	Mon Aug  6 13:02:16 2001
+++ linux_2.4.7_lsm_syscall/arch/i386/kernel/entry.S	Thu Aug  9 10:18:19 2001
@@ -620,7 +620,7 @@
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
 	.long SYMBOL_NAME(sys_fcntl64)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for TUX */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for LSM? */
+	.long SYMBOL_NAME(sys_security)		/* reserved for LSM? */
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
diff -Naur linux_2.4.7_lsm/include/linux/security.h linux_2.4.7_lsm_syscall/include/linux/security.h
--- linux_2.4.7_lsm/include/linux/security.h	Mon Aug  6 16:09:43 2001
+++ linux_2.4.7_lsm_syscall/include/linux/security.h	Thu Aug  9 13:50:46 2001
@@ -39,6 +39,10 @@
 /* Security plug operations */
 #define SECURITY_INTERFACE_VERSION	0x00000101	/* change this every time the security_operations structure changes */
 
+/* These could be made up of vendor/module version */
+#define SECURITY_DUMMY_ID	0x00000001
+#define SECURITY_CAP_PLUG_ID	0x00000002
+
 struct binprm_security_ops {
 	int (* alloc_security)		(struct linux_binprm *bprm);	/* create per binprm security stuff */
 	void (* free_security)		(struct linux_binprm *bprm);	/* free it */
@@ -220,8 +224,10 @@
 
 struct security_operations {
 	int	version;
+	int	module_id;
 	
 	/* syscalls that are checked for permissions */
+	int  (* syscall)		(int cmd, char *data, int length);
 	int  (* sethostname)		(char *hostname);		
 	int  (* setdomainname)		(char *domainname);
 	int  (* reboot)			(unsigned int cmd, void *arg);	
diff -Naur linux_2.4.7_lsm/kernel/capability_plug.c linux_2.4.7_lsm_syscall/kernel/capability_plug.c
--- linux_2.4.7_lsm/kernel/capability_plug.c	Mon Aug  6 16:10:08 2001
+++ linux_2.4.7_lsm_syscall/kernel/capability_plug.c	Thu Aug  9 13:35:46 2001
@@ -26,6 +26,7 @@
 /* flag to keep track of how we were registered */
 static int secondary;
 
+static int cap_syscall		(int cmd, char *data, int length)	{return 0;}
 static int cap_sethostname	(char *hostname)	{return 0;}
 static int cap_setdomainname	(char *domainname)	{return 0;}
 static int cap_reboot		(unsigned int cmd, void *arg)	{return 0;}
@@ -562,7 +563,9 @@
 
 static struct security_operations capability_ops = {
         version:                SECURITY_INTERFACE_VERSION,
+        module_id:              SECURITY_CAP_PLUG_ID,
 
+	syscall:		cap_syscall,
 	sethostname:		cap_sethostname,
 	setdomainname:		cap_setdomainname,
 	reboot:			cap_reboot,
diff -Naur linux_2.4.7_lsm/kernel/security.c linux_2.4.7_lsm_syscall/kernel/security.c
--- linux_2.4.7_lsm/kernel/security.c	Mon Aug  6 16:09:57 2001
+++ linux_2.4.7_lsm_syscall/kernel/security.c	Thu Aug  9 13:35:27 2001
@@ -31,12 +31,14 @@
 #include <linux/sysctl.h>
 #include <linux/netfilter.h>
 #include <linux/netdevice.h>
+#include <asm/uaccess.h>
 
 
 struct security_operations *security_ops;	/* Initialized to NULL */
 
 
 /* Stub functions for the default security function pointers in case no security model is loaded */
+static int dummy_syscall	(int cmd, char *data, int length)	{return 0;}
 static int dummy_sethostname	(char *hostname)	{return 0;}
 static int dummy_setdomainname	(char *domainname)	{return 0;}
 static int dummy_reboot		(unsigned int cmd, void *arg)	{return 0;}
@@ -394,7 +396,9 @@
 
 static struct security_operations dummy_security_ops = {
         version:                SECURITY_INTERFACE_VERSION,
+	module_id:		SECURITY_DUMMY_ID,
 
+	syscall:		dummy_syscall,
 	sethostname:		dummy_sethostname,
 	setdomainname:		dummy_setdomainname,
 	reboot:			dummy_reboot,
@@ -469,7 +473,8 @@
 	}
 	
 	/* Perform a little sanity checking on our inputs */
-	if (!ops->sethostname ||
+	if (!ops->syscall ||
+	    !ops->sethostname ||
 	    !ops->setdomainname ||
 	    !ops->reboot ||
 	    !ops->mount ||
@@ -662,6 +667,44 @@
 	return 1;
 }
 
+int sys_security (int module_id, int cmd, char *user_data, int length)
+{
+	char *kern_data = NULL;
+	int error = 0;
+
+	/* Make sure application is calling the right module */
+	if (module_id != security_ops->module_id)
+		return -ENOPKG;
+
+	if (length) {
+		kern_data = kmalloc(length, GFP_KERNEL);
+		if (!kern_data) {
+			error = -ENOMEM;
+			goto out;
+		}
+
+		if (copy_from_user(kern_data, user_data, length)) {
+			error = -EFAULT;
+			goto out;
+		}
+	}
+
+	error = security_ops->syscall(cmd, kern_data, length);
+	if (error)
+		goto out;
+
+	if (length) {
+		if (copy_to_user(user_data, kern_data, length)) {
+			error = -EFAULT;
+			goto out;
+		}
+	}
+out:
+	if (kern_data)
+		kfree(kern_data);
+
+	return error;
+}
 
 EXPORT_SYMBOL(register_security);
 EXPORT_SYMBOL(unregister_security);