linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][RFC] dynamic syscalls revisited
@ 2004-11-29 15:11 Steven Rostedt
  2004-11-29 15:17 ` Christoph Hellwig
  0 siblings, 1 reply; 22+ messages in thread
From: Steven Rostedt @ 2004-11-29 15:11 UTC (permalink / raw)
  To: LKML

Before you just ignore me and throw me to the dogs, hear me out. Please!

I've seen previous attempts to get dynamic system calls into the kernel
and they just get dumped, but usually with good reason.  They require a
change to all architectures quite drastically and is usually a problem
implementing them for the module to use them.

The approach I take here is to only add one static system call
(sys_dsyscall) and move all processing into architecture independent
code.  This interface is not meant to replace other interfaces or system
calls in general, but gives the developer an easy way to test their work
and maybe use this when other solutions don't make sense.  I don't want
to make kernel developers lazy and use this when other ways are better,
but I've found myself wishing for an easy interface into the driver
without recompiling the kernel that I'm using.

This method requires a driver to register their system call with the
following line:

dsyscall_register("syscall_name",args,DSYSCALL_FUNC(dsys_syscall_func));

This call checks to see if syscall_name is in use, and fails if it is.
It then adds the system call to a list of dynamic system calls for user
programs to use.  This is all protected with semaphores to prevent
problems with race conditions of multiple modules using the same name.
The system call is now associated with an unique number (that has
nothing to do with the numbers used by static system calls).

When the user wants to use this, the following is done:

This code is best for a library and user header file:

#include <linux/dsyscall.h>

_syscall3(int,dsyscall,int,type,char *,user_name, struct dsyscall *, dcall);
_dsyscall2(int,mysyscall,long,arg1,char *,arg2);  /* system call with 2 arguments */

The driver would have used something like:

static dsys_mysyscall(long arg1, char * arg2) { ... }

int driver_init(void) { 
  if (dsyscall_register("mysyscall",2,DSYSCALL_FUNC(dsys_mysyscall)) < 0) {
    printk("mysyscall already in use!\n");
    return -1;
  }
}

Back in the code where you want to call this in user land:

int main(int argc, char **argv) {
   ... 
   if (mysyscall(2,"hello world") < 0) {
      perror("mysyscall");
      exit(0);
   }
   ...
}


The user header file only needed two lines (one for the dsyscall system
call and the other for each dynamic system call. If glibc added
dsyscall, then only one line per dynamic syscall is needed. In my
dreams).  So you can see that this code is very easy to use and that it
doesn't intrude on the current kernel.  All that is needed (per
architecture) is the addition of the sys_dsyscall system call, and once
that is done, then you have dynamic system calls available for that
architecture.

Some notes of design:

The system call dsyscall takes three parameters: a command (get or
call), the syscall name, and finally a pointer to a descriptor.

With the get command, the descriptor is filled with a handle to get to
the system call. The name is used to find that system call, and if is
not found, and error is returned.  

The call command calls the system call using the same descriptor.  This
descriptor has two long numbers to make sure that the dynamic system
call is unique. The two long numbers should never repeat as long as the
machine is up. Once a dynamic syscall is used, it's numbers will never
repeat (hopefully, unless the machine is up for a really really long
time!) and the system call is called by that number. So even if the user
wrapper (shown later) gets the system call, then the module is removed
and the associated system call is also removed, then the user program
calls that system call, a -ENODEV is returned and no harm is done. Even
if another module in that same time registered that system call. Which
shouldn't happen!

Dynamic system calls are only allowed to have up to 6 arguments.  I have
written wrapper macros to help in using these calls, with _dsyscall0 to
_dsyscall6 to handle each type of argument.  Here's a simple view of
what _dsyscall3 does:


#define _dsyscall_call(name,args,arg) \
{ \
 long __res;  \
 static int has_init = 0; \
 static struct dsyscall ds; \
 if (!has_init) { \
	 __res = dsyscall(DSYSCALL_GET,#name,&ds); \
	 if (!__res) \
		 has_init = 1; \
	 else \
		 return __res; \
 } \
 ds.argc = args; \
 ds.argv = arg; \
 __res = dsyscall(DSYSCALL_CALL,#name,&ds); \
 if (__res < 0 && errno == ENODEV) { \
	 has_init = 0; \
 } \
 return __res; \
}

#define _dsyscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1, type2 arg2, type3 arg3) \
{ \
 long argv[3]; \
 argv[0] = (long)arg1; \
 argv[1] = (long)arg2; \
 argv[2] = (long)arg3; \
 _dsyscall_call(name,3,argv); \
 return 0; /* not reached */ \
}

_dsyscall_call is used by all the _dsyscall macros. _dsyscall3 first
assigns each of the argument to an array that will be passed to the
system call as the actual arguments.

You can see that _dsyscall_call handles the getting and calling of the
system call, so the user does not have to.  I still need to make these
wrappers thread safe but that will come later.

I've added a config option, so that if you don't want to use this, just
turn it off and it wont be available for drivers.

For sample programs, and updates to the patch you can goto
http://home.stny.rr.com/rostedt/dynamic

Even if this doesn't get into the kernel, I hope that this can help some
developers out for testing.

-- Steve


diff -Nur -X diff.ignore rt_2.6.10-rc2-mm2/arch/i386/kernel/entry.S rt_2.6.10-rc2-mm2_dynamic/arch/i386/kernel/entry.S
--- rt_2.6.10-rc2-mm2/arch/i386/kernel/entry.S	2004-11-18 13:33:18.000000000 -0500
+++ rt_2.6.10-rc2-mm2_dynamic/arch/i386/kernel/entry.S	2004-11-28 20:12:38.000000000 -0500
@@ -906,5 +906,10 @@
 	.long sys_vperfctr_unlink
 	.long sys_vperfctr_iresume
 	.long sys_vperfctr_read
+#ifdef CONFIG_DSYSCALL
+	.long sys_dsyscall		/* 295 */
+#else
+	.long sys_ni_syscall		/* 295 */
+#endif
 
 syscall_table_size=(.-sys_call_table)
diff -Nur -X diff.ignore rt_2.6.10-rc2-mm2/include/asm-i386/unistd.h rt_2.6.10-rc2-mm2_dynamic/include/asm-i386/unistd.h
--- rt_2.6.10-rc2-mm2/include/asm-i386/unistd.h	2004-11-18 13:33:22.000000000 -0500
+++ rt_2.6.10-rc2-mm2_dynamic/include/asm-i386/unistd.h	2004-11-28 19:30:49.000000000 -0500
@@ -300,8 +300,9 @@
 #define __NR_vperfctr_unlink	(__NR_perfctr_info+3)
 #define __NR_vperfctr_iresume	(__NR_perfctr_info+4)
 #define __NR_vperfctr_read	(__NR_perfctr_info+5)
+#define __NR_dsyscall		295
 
-#define NR_syscalls 295
+#define NR_syscalls 296
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
diff -Nur -X diff.ignore rt_2.6.10-rc2-mm2/include/linux/dsyscall.h rt_2.6.10-rc2-mm2_dynamic/include/linux/dsyscall.h
--- rt_2.6.10-rc2-mm2/include/linux/dsyscall.h	1969-12-31 19:00:00.000000000 -0500
+++ rt_2.6.10-rc2-mm2_dynamic/include/linux/dsyscall.h	2004-11-29 08:00:39.000000000 -0500
@@ -0,0 +1,174 @@
+/*
+ * dsyscall.h
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _LINUX_DSYSCALL_H
+#define _LINUX_DSYSCALL_H
+
+#define DSYSCALL_NAME_SZ 128
+#define DSYSCALL_MAX_ARGS 6
+
+enum dsyscall_cmd {
+	DSYSCALL_GET = 1,
+	DSYSCALL_CALL,
+};
+
+struct dsyscall {
+	char name[DSYSCALL_NAME_SZ];	/* Name of system call */
+	long id;			/* unique id of available dynamic syscalls */
+	long iteration;			/* incase this box runs longer than we have been on earth
+					   count the iterations of id's. If interation overflows,
+					   then we are simply out of luck! */
+	int argc;			/* Number of arguments that this system call takes. */
+	long *argv;			/* pointer to the argument list */
+};
+
+#define DSYSCALL_FUNC(func) ((int(*)(long,...))func)
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+
+struct dsyscall_struct {
+	struct list_head next;		/* list of all dynamic syscalls */
+	struct list_head link;		/* used in the hash */
+	char name[DSYSCALL_NAME_SZ];	/* name of the dynamic syscall */	
+	int args;			/* number of arguments for this syscall */
+	int (*func)(long,...);		/* The actual dynamic system call */
+	long id;
+	long iteration;
+
+};
+
+int dsyscall_register(char *name, int args, int (*func)(long,...));
+int dsyscall_unregister(char *name);
+
+#else /* !__KERNEL__ */
+
+/* OK, this should probably be in another file for users */
+#include <asm/unistd.h>
+
+#define _dsyscall_call(name,args,arg) \
+{ \
+ long __res;  \
+ static int has_init = 0; \
+ static struct dsyscall ds; \
+ if (!has_init) { \
+	 __res = dsyscall(DSYSCALL_GET,#name,&ds); \
+	 if (!__res) \
+		 has_init = 1; \
+	 else \
+		 return __res; \
+ } \
+ ds.argc = args; \
+ ds.argv = arg; \
+ __res = dsyscall(DSYSCALL_CALL,#name,&ds); \
+ if (__res < 0 && errno == ENODEV) { \
+	 has_init = 0; \
+ } \
+ return __res; \
+}
+
+#define _dsyscall0(type,name) \
+type name(void) \
+{ \
+ long argv[0]; \
+ _dsyscall_call(name,0,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+ long argv[1]; \
+ argv[0] = (long)arg1; \
+ _dsyscall_call(name,1,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1, type2 arg2) \
+{ \
+ long argv[2]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ _dsyscall_call(name,2,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1, type2 arg2, type3 arg3) \
+{ \
+ long argv[3]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ _dsyscall_call(name,3,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall4(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+ long argv[4]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ _dsyscall_call(name,4,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall5(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+          type5 arg5) \
+{ \
+ long argv[5]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ _dsyscall_call(name,5,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall6(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4,type5,arg5,type6,arg6) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+          type5 arg5, type6 arg6) \
+{ \
+ long argv[6]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ argv[5] = (long)arg6; \
+ _dsyscall_call(name,6,argv); \
+ return 0; /* not reached */ \
+}
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DSYSCALL_H */
diff -Nur -X diff.ignore rt_2.6.10-rc2-mm2/init/Kconfig rt_2.6.10-rc2-mm2_dynamic/init/Kconfig
--- rt_2.6.10-rc2-mm2/init/Kconfig	2004-11-18 13:33:31.000000000 -0500
+++ rt_2.6.10-rc2-mm2_dynamic/init/Kconfig	2004-11-28 15:57:29.000000000 -0500
@@ -249,6 +249,14 @@
 	  through /proc/config.gz.
 

+config DSYSCALL
+	bool "Enable dynamic system calls"
+	default y
+	help
+	  This option enables usage of dynamic system calls by drivers.
+	  This allows drivers to register system calls that are not
+	  already defined by the compiled kernel.
+
 menuconfig EMBEDDED
 	bool "Configure standard kernel features (for small systems)"
 	help
diff -Nur -X diff.ignore rt_2.6.10-rc2-mm2/kernel/dsyscall.c rt_2.6.10-rc2-mm2_dynamic/kernel/dsyscall.c
--- rt_2.6.10-rc2-mm2/kernel/dsyscall.c	1969-12-31 19:00:00.000000000 -0500
+++ rt_2.6.10-rc2-mm2_dynamic/kernel/dsyscall.c	2004-11-29 07:03:15.000000000 -0500
@@ -0,0 +1,286 @@
+/*
+ * dsyscall.c
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/dsyscall.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+
+#include <asm/uaccess.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...) do { } while(0)
+#endif
+
+#define DSYSCALL_HASH_SIZE 32
+
+DECLARE_RWSEM(dsyscall_sem);
+
+static long dsyscall_next_id = 0;
+static long dsyscall_iterations = 0;
+static kmem_cache_t *dsyscall_cache;
+static struct list_head dsyscall_hash[DSYSCALL_HASH_SIZE];
+static LIST_HEAD(dsyscall_syscalls);
+
+static int dsyscall_hash_add(struct dsyscall_struct *ds)
+{
+	list_add(&ds->link,&dsyscall_hash[ds->id & (DSYSCALL_HASH_SIZE - 1)]);
+	return 0;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_name(char *name)
+{
+	struct list_head *li;
+	struct dsyscall_struct *ds, *ret = NULL;
+
+	/* slow, but this should not be called often. */
+	list_for_each(li,&dsyscall_syscalls) {
+		ds = list_entry(li, struct dsyscall_struct, next);
+		if (strcmp(ds->name,name) == 0) {
+			ret = ds;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_id(struct dsyscall *d)
+{
+	struct list_head *li;
+	struct dsyscall_struct *ds, *ret = NULL;
+
+	/* For now it's a little faster. We can optimize this if we need to */
+	list_for_each(li,&dsyscall_hash[d->id & (DSYSCALL_HASH_SIZE - 1)]) {
+		ds = list_entry(li, struct dsyscall_struct, link);
+		if (ds->id == d->id) {
+			if (likely(ds->iteration == d->iteration)) 
+				ret = ds;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+int sys_dsyscall(int type, char *user_name, struct dsyscall *dcall)
+{
+	int ret;
+	struct dsyscall_struct *ds;
+	struct dsyscall d;
+	long argv[DSYSCALL_MAX_ARGS];
+
+	/*
+	 * OK, this is pretty long to hold a semaphore, even if
+	 * if is just for reading. But if you want speed, don't use
+	 * dynamic system calls!
+	 */
+	down_read(&dsyscall_sem);
+	switch (type) {
+	case DSYSCALL_GET:
+		dprintk("sys_dsyscall: DSYSCALL_GET, ");
+		memset (&d,0,sizeof(d));
+		ret = -EFAULT;
+		if (strncpy_from_user(d.name,user_name,DSYSCALL_NAME_SZ-1) < 0) {
+			dprintk(">>>BAD NAME<<<\n");
+			goto out;
+		}
+		dprintk("%s: ", d.name);
+
+		/* just in case */
+		d.name[DSYSCALL_NAME_SZ-1] = 0;
+
+		ds = find_dsyscall_by_name(d.name);
+
+		if (!ds) {
+			dprintk("not found\n");
+			ret = -ENODEV;
+			goto out;
+		}
+
+		dprintk("found\n");
+		d.id = ds->id;
+		d.iteration = ds->iteration;
+		d.argc = ds->args;
+
+		ret = 0;
+		if (copy_to_user(dcall,&d,sizeof(d)) != 0) { 
+			ret = -EFAULT;
+		}
+		break;
+
+	case DSYSCALL_CALL:
+		ret = -EFAULT;
+		if (copy_from_user(&d,dcall,sizeof(d)) != 0) {
+			goto out;
+		}
+
+		ds = find_dsyscall_by_id(&d);
+		if (!ds) {
+			ret = -ENODEV;
+			goto out;
+		}
+		/* Comparing to ds->args which can not be bigger than DSYSCALL_MAX_ARGS */
+		if (d.argc != ds->args) {
+			ret = -EINVAL;
+			goto out;
+		}
+		
+		if (d.argc > 0) {
+			if (copy_from_user(argv,d.argv,sizeof(char*)*d.argc) != 0) {
+				ret = -EFAULT;
+				goto out;
+			}
+		}
+
+		switch (d.argc) {
+		case 0:
+			ret = ds->func(0); /* The argument should be ignored */
+			break;
+		case 1:
+			ret = ds->func(argv[0]);
+			break;
+		case 2:
+			ret = ds->func(argv[0],argv[1]);
+			break;
+		case 3:
+			ret = ds->func(argv[0],argv[1],argv[2]);
+			break;
+		case 4:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3]);
+			break;
+		case 5:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4]);
+			break;
+		case 6:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]);
+			break;
+		}	
+		goto out;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+ out:
+	up_read(&dsyscall_sem);
+
+	return ret;
+}
+
+int dsyscall_register(char *name, int args, int (*func)(long,...))
+{
+	int ret = -1;
+	struct dsyscall_struct *ds;
+
+	dprintk("dsyscall_register: %s args: %d func=%p\n",name,args,func);
+
+	if (strlen(name) >= DSYSCALL_NAME_SZ) {
+		printk(KERN_INFO "dsyscall: name %s is too large.", name);
+		return -1;
+	}
+	if (args > DSYSCALL_MAX_ARGS) {
+		printk(KERN_INFO "dsyscall: args is too big.");
+		return -1;
+	}
+	
+	down_write(&dsyscall_sem);
+	if ((ds = find_dsyscall_by_name(name)) != NULL) {
+		printk(KERN_INFO "dsyscall: name %s is already in use.",name);
+		goto out;
+	}
+
+	ds = kmem_cache_alloc(dsyscall_cache,GFP_KERNEL);
+	if (!ds) {
+		printk(KERN_INFO "dsyscall: could not allocate dsyscall_struct");
+		goto out;
+	}
+
+	ds->args = args;
+	ds->func = func;
+	ds->id = dsyscall_next_id++;
+	ds->iteration = dsyscall_iterations;
+	if (!dsyscall_next_id) {
+		if (!++dsyscall_iterations) {
+			printk(KERN_WARNING "dsyscall: iterations has overflowed???");
+		}
+	}
+	strcpy(ds->name,name);
+	
+	list_add(&ds->next,&dsyscall_syscalls);
+	dsyscall_hash_add(ds);
+
+	ret = 0;
+ out:
+	up_write(&dsyscall_sem);
+	return ret;
+}
+
+int dsyscall_unregister(char *name)
+{
+	struct dsyscall_struct *ds;
+
+	down_write(&dsyscall_sem);
+	if ((ds = find_dsyscall_by_name(name)) == NULL) {
+		printk("dsyscall: name %s is not registered\n",name);
+		up_write(&dsyscall_sem);
+		return -1;
+	}
+
+	list_del(&ds->next);
+	list_del(&ds->link);
+
+	up_write(&dsyscall_sem);
+
+	kmem_cache_free(dsyscall_cache,ds);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(dsyscall_register);
+EXPORT_SYMBOL(dsyscall_unregister);
+
+int __init dsyscall_init(void)
+{
+	int i;
+
+	dsyscall_cache = kmem_cache_create("dsyscalls", sizeof(struct dsyscall_struct),
+					   0, 0, NULL, NULL);
+	if (!dsyscall_cache)
+		panic ("Can't allocate dsyscall cache!");  /* Too much? something else is wrong if
+							      we fail here. */
+	
+	for (i=0; i < DSYSCALL_HASH_SIZE; i++) {
+		INIT_LIST_HEAD(&dsyscall_hash[i]);
+	}
+
+	return 0;
+}
+__initcall(dsyscall_init);
diff -Nur -X diff.ignore rt_2.6.10-rc2-mm2/kernel/Makefile rt_2.6.10-rc2-mm2_dynamic/kernel/Makefile
--- rt_2.6.10-rc2-mm2/kernel/Makefile	2004-11-18 13:33:30.000000000 -0500
+++ rt_2.6.10-rc2-mm2_dynamic/kernel/Makefile	2004-11-28 18:25:13.000000000 -0500
@@ -29,6 +29,7 @@
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_CRASH_DUMP) += crash.o
+obj-$(CONFIG_DSYSCALL) += dsyscall.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is


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

* Re: [PATCH][RFC] dynamic syscalls revisited
  2004-11-29 15:11 [PATCH][RFC] dynamic syscalls revisited Steven Rostedt
@ 2004-11-29 15:17 ` Christoph Hellwig
  2004-11-29 15:36   ` Steven Rostedt
  2004-11-29 16:41   ` [RFC] " Jan Engelhardt
  0 siblings, 2 replies; 22+ messages in thread
From: Christoph Hellwig @ 2004-11-29 15:17 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: LKML

On Mon, Nov 29, 2004 at 10:11:58AM -0500, Steven Rostedt wrote:
> Before you just ignore me and throw me to the dogs, hear me out. Please!
> 
> I've seen previous attempts to get dynamic system calls into the kernel
> and they just get dumped, but usually with good reason.  They require a
> change to all architectures quite drastically and is usually a problem
> implementing them for the module to use them.

Actually they were dumped because dynamically syscalls are a really bad
idea, not because of implementation issues.


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

* Re: [PATCH][RFC] dynamic syscalls revisited
  2004-11-29 15:17 ` Christoph Hellwig
@ 2004-11-29 15:36   ` Steven Rostedt
  2004-11-30 19:30     ` Kristian Sørensen
  2004-11-29 16:41   ` [RFC] " Jan Engelhardt
  1 sibling, 1 reply; 22+ messages in thread
From: Steven Rostedt @ 2004-11-29 15:36 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: LKML

On Mon, 2004-11-29 at 15:17 +0000, Christoph Hellwig wrote:
> 
> Actually they were dumped because dynamically syscalls are a really bad
> idea, not because of implementation issues.
> 

Yes, for most cases they are.  But the implementation for them seemed to
be too intrusive for the special case. This solution is not so
intrusive, and can easily be compiled out. As I said, they are nice to
have for a quick debugging, and may have other uses as well. The times I
wished for them, was usually debugging a module and I didn't want to
recompile the kernel and reboot. So instead I made awful hacks into the
proc system or some make believe device to interface with.

I'm just putting this out for others to use. If it doesn't get into the
kernel, then so be it, but since this is not so intrusive, and can
easily be used on all architectures, then the patch can surely help
others.

-- Steve


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

* Re: [RFC] dynamic syscalls revisited
  2004-11-29 15:17 ` Christoph Hellwig
  2004-11-29 15:36   ` Steven Rostedt
@ 2004-11-29 16:41   ` Jan Engelhardt
  2004-11-29 17:10     ` Steven Rostedt
  2004-12-06 21:14     ` H. Peter Anvin
  1 sibling, 2 replies; 22+ messages in thread
From: Jan Engelhardt @ 2004-11-29 16:41 UTC (permalink / raw)
  Cc: LKML

>> I've seen previous attempts to get dynamic system calls into the kernel
>> and they just get dumped, but usually with good reason.  They require a
>> change to all architectures quite drastically and is usually a problem
>> implementing them for the module to use them.
>
>Actually they were dumped because dynamically syscalls are a really bad
>idea, not because of implementation issues.

I do not see how dsyscalls could be better than static ones, so they are
one-on-one. Maybe someone could elaborate why they are "a really bad idea"?



Jan Engelhardt
-- 
Gesellschaft für Wissenschaftliche Datenverarbeitung
Am Fassberg, 37077 Göttingen, www.gwdg.de

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

* Re: [RFC] dynamic syscalls revisited
  2004-11-29 16:41   ` [RFC] " Jan Engelhardt
@ 2004-11-29 17:10     ` Steven Rostedt
  2004-12-05 23:46       ` Adrian Bunk
  2004-12-06 21:14     ` H. Peter Anvin
  1 sibling, 1 reply; 22+ messages in thread
From: Steven Rostedt @ 2004-11-29 17:10 UTC (permalink / raw)
  To: Jan Engelhardt; +Cc: LKML

On Mon, 2004-11-29 at 17:41 +0100, Jan Engelhardt wrote:
> I do not see how dsyscalls could be better than static ones, so they are
> one-on-one. Maybe someone could elaborate why they are "a really bad idea"?

The one argument against them, that I agree with, is Linus' hooks to
avoid the GPL.  A binary only module could easily add their own hooks
into the kernel.

I've made this patch with the option to turn this off. I should have put
the option in Kernel debugging with the default off (the default is
currently on so that if you apply the patch, you have it automatically).
This way binary only modules can't take advantage of the dynamic
syscalls without recompiling the kernel.  If the user needed to compile
the kernel, then a patch can easily be added, so this is just as good of
a defense. 

-- Steve



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

* Re: [PATCH][RFC] dynamic syscalls revisited
  2004-11-29 15:36   ` Steven Rostedt
@ 2004-11-30 19:30     ` Kristian Sørensen
  0 siblings, 0 replies; 22+ messages in thread
From: Kristian Sørensen @ 2004-11-30 19:30 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: Christoph Hellwig, LKML, The Umbrella Team

Steven Rostedt wrote:

>On Mon, 2004-11-29 at 15:17 +0000, Christoph Hellwig wrote:
>  
>
>>Actually they were dumped because dynamically syscalls are a really bad
>>idea, not because of implementation issues.
>>
>>    
>>
>
>Yes, for most cases they are.  But the implementation for them seemed to
>be too intrusive for the special case. This solution is not so
>intrusive, and can easily be compiled out. As I said, they are nice to
>have for a quick debugging, and may have other uses as well. The times I
>wished for them, was usually debugging a module and I didn't want to
>recompile the kernel and reboot. So instead I made awful hacks into the
>proc system or some make believe device to interface with.
>
>I'm just putting this out for others to use. If it doesn't get into the
>kernel, then so be it, but since this is not so intrusive, and can
>easily be used on all architectures, then the patch can surely help
>others.
>  
>
In our project (The Umbrella Project) we are maintaining a system call 
for making a "restricted fork" (which could e.g. be that the child 
created will have no access to the network)... it is a very annoying job 
to keep the patch up to date with the new kernel versions because the 
syscall files are changed often. The rest of the Umbrella module is 
independent because it is based on LSM ... so having dynamic syscalls is 
definitly a wish of ours!


Best, Kristian Sørensen.

-- 
Kristian Sørensen
- The Umbrella Project  --  Security for Consumer Electronics
  http://umbrella.sourceforge.net

E-mail: ipqw@users.sf.net, Phone: +45 29723816


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

* Re: [RFC] dynamic syscalls revisited
  2004-11-29 17:10     ` Steven Rostedt
@ 2004-12-05 23:46       ` Adrian Bunk
  2004-12-06 16:07         ` Steven Rostedt
  0 siblings, 1 reply; 22+ messages in thread
From: Adrian Bunk @ 2004-12-05 23:46 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: Jan Engelhardt, LKML

On Mon, Nov 29, 2004 at 12:10:58PM -0500, Steven Rostedt wrote:
> On Mon, 2004-11-29 at 17:41 +0100, Jan Engelhardt wrote:
> > I do not see how dsyscalls could be better than static ones, so they are
> > one-on-one. Maybe someone could elaborate why they are "a really bad idea"?
> 
> The one argument against them, that I agree with, is Linus' hooks to
> avoid the GPL.  A binary only module could easily add their own hooks
> into the kernel.
> 
> I've made this patch with the option to turn this off. I should have put
> the option in Kernel debugging with the default off (the default is
> currently on so that if you apply the patch, you have it automatically).
> This way binary only modules can't take advantage of the dynamic
> syscalls without recompiling the kernel.  If the user needed to compile
> the kernel, then a patch can easily be added, so this is just as good of
> a defense. 

Why don't you EXPORT_SYMBOL_GPL dsyscall_{,un}register?

This should at least fix the binary only module concerns.

> -- Steve

cu
Adrian

-- 

       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed


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

* Re: [RFC] dynamic syscalls revisited
  2004-12-05 23:46       ` Adrian Bunk
@ 2004-12-06 16:07         ` Steven Rostedt
  2004-12-06 17:16           ` Steven Rostedt
  2004-12-07  0:20           ` Michael Buesch
  0 siblings, 2 replies; 22+ messages in thread
From: Steven Rostedt @ 2004-12-06 16:07 UTC (permalink / raw)
  To: Adrian Bunk; +Cc: Jan Engelhardt, LKML

On Mon, 2004-12-06 at 00:46 +0100, Adrian Bunk wrote:
> 
> Why don't you EXPORT_SYMBOL_GPL dsyscall_{,un}register?
> 
> This should at least fix the binary only module concerns.

Done!

Updated on http://home.stny.rr.com/rostedt/dynamic as well as included
in this email for ease.  

Now, I guess you can still get around this if the "Bad Vendor" were to
write a GPL module with their added system calls, and have that module
include hooks to their binary module.  So, until we can fix that, I
guess Linus won't allow for this module to be included in the main line.

-- Steve


Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 15)
+++ kernel/Makefile	(working copy)
@@ -29,6 +29,7 @@
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_CRASH_DUMP) += crash.o
+obj-$(CONFIG_DSYSCALL) += dsyscall.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: kernel/dsyscall.c
===================================================================
--- kernel/dsyscall.c	(revision 0)
+++ kernel/dsyscall.c	(revision 0)
@@ -0,0 +1,286 @@
+/*
+ * dsyscall.c
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/dsyscall.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+
+#include <asm/uaccess.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...) do { } while(0)
+#endif
+
+#define DSYSCALL_HASH_SIZE 32
+
+DECLARE_RWSEM(dsyscall_sem);
+
+static long dsyscall_next_id = 0;
+static long dsyscall_iterations = 0;
+static kmem_cache_t *dsyscall_cache;
+static struct list_head dsyscall_hash[DSYSCALL_HASH_SIZE];
+static LIST_HEAD(dsyscall_syscalls);
+
+static int dsyscall_hash_add(struct dsyscall_struct *ds)
+{
+	list_add(&ds->link,&dsyscall_hash[ds->id & (DSYSCALL_HASH_SIZE - 1)]);
+	return 0;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_name(char *name)
+{
+	struct list_head *li;
+	struct dsyscall_struct *ds, *ret = NULL;
+
+	/* slow, but this should not be called often. */
+	list_for_each(li,&dsyscall_syscalls) {
+		ds = list_entry(li, struct dsyscall_struct, next);
+		if (strcmp(ds->name,name) == 0) {
+			ret = ds;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_id(struct dsyscall *d)
+{
+	struct list_head *li;
+	struct dsyscall_struct *ds, *ret = NULL;
+
+	/* For now it's a little faster. We can optimize this if we need to */
+	list_for_each(li,&dsyscall_hash[d->id & (DSYSCALL_HASH_SIZE - 1)]) {
+		ds = list_entry(li, struct dsyscall_struct, link);
+		if (ds->id == d->id) {
+			if (likely(ds->iteration == d->iteration)) 
+				ret = ds;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+int sys_dsyscall(int type, char *user_name, struct dsyscall *dcall)
+{
+	int ret;
+	struct dsyscall_struct *ds;
+	struct dsyscall d;
+	long argv[DSYSCALL_MAX_ARGS];
+
+	/*
+	 * OK, this is pretty long to hold a semaphore, even if
+	 * if is just for reading. But if you want speed, don't use
+	 * dynamic system calls!
+	 */
+	down_read(&dsyscall_sem);
+	switch (type) {
+	case DSYSCALL_GET:
+		dprintk("sys_dsyscall: DSYSCALL_GET, ");
+		memset (&d,0,sizeof(d));
+		ret = -EFAULT;
+		if (strncpy_from_user(d.name,user_name,DSYSCALL_NAME_SZ-1) < 0) {
+			dprintk(">>>BAD NAME<<<\n");
+			goto out;
+		}
+		dprintk("%s: ", d.name);
+
+		/* just in case */
+		d.name[DSYSCALL_NAME_SZ-1] = 0;
+
+		ds = find_dsyscall_by_name(d.name);
+
+		if (!ds) {
+			dprintk("not found\n");
+			ret = -ENODEV;
+			goto out;
+		}
+
+		dprintk("found\n");
+		d.id = ds->id;
+		d.iteration = ds->iteration;
+		d.argc = ds->args;
+
+		ret = 0;
+		if (copy_to_user(dcall,&d,sizeof(d)) != 0) { 
+			ret = -EFAULT;
+		}
+		break;
+
+	case DSYSCALL_CALL:
+		ret = -EFAULT;
+		if (copy_from_user(&d,dcall,sizeof(d)) != 0) {
+			goto out;
+		}
+
+		ds = find_dsyscall_by_id(&d);
+		if (!ds) {
+			ret = -ENODEV;
+			goto out;
+		}
+		/* Comparing to ds->args which can not be bigger than DSYSCALL_MAX_ARGS */
+		if (d.argc != ds->args) {
+			ret = -EINVAL;
+			goto out;
+		}
+		
+		if (d.argc > 0) {
+			if (copy_from_user(argv,d.argv,sizeof(char*)*d.argc) != 0) {
+				ret = -EFAULT;
+				goto out;
+			}
+		}
+
+		switch (d.argc) {
+		case 0:
+			ret = ds->func(0); /* The argument should be ignored */
+			break;
+		case 1:
+			ret = ds->func(argv[0]);
+			break;
+		case 2:
+			ret = ds->func(argv[0],argv[1]);
+			break;
+		case 3:
+			ret = ds->func(argv[0],argv[1],argv[2]);
+			break;
+		case 4:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3]);
+			break;
+		case 5:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4]);
+			break;
+		case 6:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]);
+			break;
+		}	
+		goto out;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+ out:
+	up_read(&dsyscall_sem);
+
+	return ret;
+}
+
+int dsyscall_register(char *name, int args, int (*func)(long,...))
+{
+	int ret = -1;
+	struct dsyscall_struct *ds;
+
+	dprintk("dsyscall_register: %s args: %d func=%p\n",name,args,func);
+
+	if (strlen(name) >= DSYSCALL_NAME_SZ) {
+		printk(KERN_INFO "dsyscall: name %s is too large.", name);
+		return -1;
+	}
+	if (args > DSYSCALL_MAX_ARGS) {
+		printk(KERN_INFO "dsyscall: args is too big.");
+		return -1;
+	}
+	
+	down_write(&dsyscall_sem);
+	if ((ds = find_dsyscall_by_name(name)) != NULL) {
+		printk(KERN_INFO "dsyscall: name %s is already in use.",name);
+		goto out;
+	}
+
+	ds = kmem_cache_alloc(dsyscall_cache,GFP_KERNEL);
+	if (!ds) {
+		printk(KERN_INFO "dsyscall: could not allocate dsyscall_struct");
+		goto out;
+	}
+
+	ds->args = args;
+	ds->func = func;
+	ds->id = dsyscall_next_id++;
+	ds->iteration = dsyscall_iterations;
+	if (!dsyscall_next_id) {
+		if (!++dsyscall_iterations) {
+			printk(KERN_WARNING "dsyscall: iterations has overflowed???");
+		}
+	}
+	strcpy(ds->name,name);
+	
+	list_add(&ds->next,&dsyscall_syscalls);
+	dsyscall_hash_add(ds);
+
+	ret = 0;
+ out:
+	up_write(&dsyscall_sem);
+	return ret;
+}
+
+int dsyscall_unregister(char *name)
+{
+	struct dsyscall_struct *ds;
+
+	down_write(&dsyscall_sem);
+	if ((ds = find_dsyscall_by_name(name)) == NULL) {
+		printk("dsyscall: name %s is not registered\n",name);
+		up_write(&dsyscall_sem);
+		return -1;
+	}
+
+	list_del(&ds->next);
+	list_del(&ds->link);
+
+	up_write(&dsyscall_sem);
+
+	kmem_cache_free(dsyscall_cache,ds);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(dsyscall_register);
+EXPORT_SYMBOL_GPL(dsyscall_unregister);
+
+int __init dsyscall_init(void)
+{
+	int i;
+
+	dsyscall_cache = kmem_cache_create("dsyscalls", sizeof(struct dsyscall_struct),
+					   0, 0, NULL, NULL);
+	if (!dsyscall_cache)
+		panic ("Can't allocate dsyscall cache!");  /* Too much? something else is wrong if
+							      we fail here. */
+	
+	for (i=0; i < DSYSCALL_HASH_SIZE; i++) {
+		INIT_LIST_HEAD(&dsyscall_hash[i]);
+	}
+
+	return 0;
+}
+__initcall(dsyscall_init);
Index: include/asm-i386/unistd.h
===================================================================
--- include/asm-i386/unistd.h	(revision 15)
+++ include/asm-i386/unistd.h	(working copy)
@@ -300,8 +300,9 @@
 #define __NR_vperfctr_unlink	(__NR_perfctr_info+3)
 #define __NR_vperfctr_iresume	(__NR_perfctr_info+4)
 #define __NR_vperfctr_read	(__NR_perfctr_info+5)
+#define __NR_dsyscall		295
 
-#define NR_syscalls 295
+#define NR_syscalls 296
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
Index: include/linux/dsyscall.h
===================================================================
--- include/linux/dsyscall.h	(revision 0)
+++ include/linux/dsyscall.h	(revision 0)
@@ -0,0 +1,174 @@
+/*
+ * dsyscall.h
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _LINUX_DSYSCALL_H
+#define _LINUX_DSYSCALL_H
+
+#define DSYSCALL_NAME_SZ 128
+#define DSYSCALL_MAX_ARGS 6
+
+enum dsyscall_cmd {
+	DSYSCALL_GET = 1,
+	DSYSCALL_CALL,
+};
+
+struct dsyscall {
+	char name[DSYSCALL_NAME_SZ];	/* Name of system call */
+	long id;			/* unique id of available dynamic syscalls */
+	long iteration;			/* incase this box runs longer than we have been on earth
+					   count the iterations of id's. If interation overflows,
+					   then we are simply out of luck! */
+	int argc;			/* Number of arguments that this system call takes. */
+	long *argv;			/* pointer to the argument list */
+};
+
+#define DSYSCALL_FUNC(func) ((int(*)(long,...))func)
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+
+struct dsyscall_struct {
+	struct list_head next;		/* list of all dynamic syscalls */
+	struct list_head link;		/* used in the hash */
+	char name[DSYSCALL_NAME_SZ];	/* name of the dynamic syscall */	
+	int args;			/* number of arguments for this syscall */
+	int (*func)(long,...);		/* The actual dynamic system call */
+	long id;
+	long iteration;
+
+};
+
+int dsyscall_register(char *name, int args, int (*func)(long,...));
+int dsyscall_unregister(char *name);
+
+#else /* !__KERNEL__ */
+
+/* OK, this should probably be in another file for users */
+#include <asm/unistd.h>
+
+#define _dsyscall_call(name,args,arg) \
+{ \
+ long __res;  \
+ static int has_init = 0; \
+ static struct dsyscall ds; \
+ if (!has_init) { \
+	 __res = dsyscall(DSYSCALL_GET,#name,&ds); \
+	 if (!__res) \
+		 has_init = 1; \
+	 else \
+		 return __res; \
+ } \
+ ds.argc = args; \
+ ds.argv = arg; \
+ __res = dsyscall(DSYSCALL_CALL,#name,&ds); \
+ if (__res < 0 && errno == ENODEV) { \
+	 has_init = 0; \
+ } \
+ return __res; \
+}
+
+#define _dsyscall0(type,name) \
+type name(void) \
+{ \
+ long argv[0]; \
+ _dsyscall_call(name,0,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+ long argv[1]; \
+ argv[0] = (long)arg1; \
+ _dsyscall_call(name,1,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1, type2 arg2) \
+{ \
+ long argv[2]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ _dsyscall_call(name,2,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1, type2 arg2, type3 arg3) \
+{ \
+ long argv[3]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ _dsyscall_call(name,3,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall4(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+ long argv[4]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ _dsyscall_call(name,4,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall5(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+          type5 arg5) \
+{ \
+ long argv[5]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ _dsyscall_call(name,5,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall6(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4,type5,arg5,type6,arg6) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+          type5 arg5, type6 arg6) \
+{ \
+ long argv[6]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ argv[5] = (long)arg6; \
+ _dsyscall_call(name,6,argv); \
+ return 0; /* not reached */ \
+}
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DSYSCALL_H */
Index: init/Kconfig
===================================================================
--- init/Kconfig	(revision 15)
+++ init/Kconfig	(working copy)
@@ -249,6 +249,14 @@
 	  through /proc/config.gz.
 
 
+config DSYSCALL
+	bool "Enable dynamic system calls"
+	default y
+	help
+	  This option enables usage of dynamic system calls by drivers.
+	  This allows drivers to register system calls that are not
+	  already defined by the compiled kernel.
+
 menuconfig EMBEDDED
 	bool "Configure standard kernel features (for small systems)"
 	help
Index: arch/i386/kernel/entry.S
===================================================================
--- arch/i386/kernel/entry.S	(revision 15)
+++ arch/i386/kernel/entry.S	(working copy)
@@ -906,5 +906,10 @@
 	.long sys_vperfctr_unlink
 	.long sys_vperfctr_iresume
 	.long sys_vperfctr_read
+#ifdef CONFIG_DSYSCALL
+	.long sys_dsyscall		/* 295 */
+#else
+	.long sys_ni_syscall		/* 295 */
+#endif
 
 syscall_table_size=(.-sys_call_table)


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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 16:07         ` Steven Rostedt
@ 2004-12-06 17:16           ` Steven Rostedt
  2004-12-06 17:32             ` Zwane Mwaikambo
  2004-12-07  0:20           ` Michael Buesch
  1 sibling, 1 reply; 22+ messages in thread
From: Steven Rostedt @ 2004-12-06 17:16 UTC (permalink / raw)
  To: Adrian Bunk; +Cc: Jan Engelhardt, LKML

On Mon, 2004-12-06 at 11:07 -0500, Steven Rostedt wrote:
> On Mon, 2004-12-06 at 00:46 +0100, Adrian Bunk wrote:
> > 
> > Why don't you EXPORT_SYMBOL_GPL dsyscall_{,un}register?
> > 
> > This should at least fix the binary only module concerns.
> 
> Done!
> 
> Updated on http://home.stny.rr.com/rostedt/dynamic as well as included
> in this email for ease.  
> 
> Now, I guess you can still get around this if the "Bad Vendor" were to
> write a GPL module with their added system calls, and have that module
> include hooks to their binary module.  So, until we can fix that, I
> guess Linus won't allow for this module to be included in the main line.

I added the following to my sys_dsyscall routine. The routine that is
the only system call for a user process to access dynamic system calls
(at anytime), even if dynamic system calls are loaded.

	static int is_tainted = 0;

	if (tainted & TAINT_PROPRIETARY_MODULE) {
		if (!is_tainted) {
			printk(KERN_INFO "Sorry, can't use dynamic system calls with proprietary modules\n");
			is_tainted = 1;
		}
		return -EINVAL;
	}

Once a proprietary module is loaded then all dynamic system calls will
become useless.

This way, only systems that never loaded a proprietary module may be
able to use dynamic system calls.  This may suck for those that have
NVidia cards, but this may be a start to overcome the problem of
allowing binary hooks into default kernels. It also is a way to motivate
end users to not use proprietary modules.

What do others think about this?

Once again I've update my account and added here the patch.

Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 15)
+++ kernel/Makefile	(working copy)
@@ -29,6 +29,7 @@
 obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_CRASH_DUMP) += crash.o
+obj-$(CONFIG_DSYSCALL) += dsyscall.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: kernel/dsyscall.c
===================================================================
--- kernel/dsyscall.c	(revision 0)
+++ kernel/dsyscall.c	(revision 0)
@@ -0,0 +1,294 @@
+/*
+ * dsyscall.c
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/dsyscall.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+
+#include <asm/uaccess.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...) do { } while(0)
+#endif
+
+#define DSYSCALL_HASH_SIZE 32
+
+DECLARE_RWSEM(dsyscall_sem);
+
+static long dsyscall_next_id = 0;
+static long dsyscall_iterations = 0;
+static kmem_cache_t *dsyscall_cache;
+static struct list_head dsyscall_hash[DSYSCALL_HASH_SIZE];
+static LIST_HEAD(dsyscall_syscalls);
+
+static int dsyscall_hash_add(struct dsyscall_struct *ds)
+{
+	list_add(&ds->link,&dsyscall_hash[ds->id & (DSYSCALL_HASH_SIZE - 1)]);
+	return 0;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_name(char *name)
+{
+	struct list_head *li;
+	struct dsyscall_struct *ds, *ret = NULL;
+
+	/* slow, but this should not be called often. */
+	list_for_each(li,&dsyscall_syscalls) {
+		ds = list_entry(li, struct dsyscall_struct, next);
+		if (strcmp(ds->name,name) == 0) {
+			ret = ds;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_id(struct dsyscall *d)
+{
+	struct list_head *li;
+	struct dsyscall_struct *ds, *ret = NULL;
+
+	/* For now it's a little faster. We can optimize this if we need to */
+	list_for_each(li,&dsyscall_hash[d->id & (DSYSCALL_HASH_SIZE - 1)]) {
+		ds = list_entry(li, struct dsyscall_struct, link);
+		if (ds->id == d->id) {
+			if (likely(ds->iteration == d->iteration)) 
+				ret = ds;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+int sys_dsyscall(int type, char *user_name, struct dsyscall *dcall)
+{
+	int ret;
+	struct dsyscall_struct *ds;
+	struct dsyscall d;
+	long argv[DSYSCALL_MAX_ARGS];
+	static int is_tainted = 0;
+
+	if (tainted & TAINT_PROPRIETARY_MODULE) {
+		if (!is_tainted) {
+			printk(KERN_INFO "Sorry, can't use dynamic system calls with proprietary modules\n");
+			is_tainted = 1;
+		}
+		return -EINVAL;
+	}
+	/*
+	 * OK, this is pretty long to hold a semaphore, even if
+	 * if is just for reading. But if you want speed, don't use
+	 * dynamic system calls!
+	 */
+	down_read(&dsyscall_sem);
+	switch (type) {
+	case DSYSCALL_GET:
+		dprintk("sys_dsyscall: DSYSCALL_GET, ");
+		memset (&d,0,sizeof(d));
+		ret = -EFAULT;
+		if (strncpy_from_user(d.name,user_name,DSYSCALL_NAME_SZ-1) < 0) {
+			dprintk(">>>BAD NAME<<<\n");
+			goto out;
+		}
+		dprintk("%s: ", d.name);
+
+		/* just in case */
+		d.name[DSYSCALL_NAME_SZ-1] = 0;
+
+		ds = find_dsyscall_by_name(d.name);
+
+		if (!ds) {
+			dprintk("not found\n");
+			ret = -ENODEV;
+			goto out;
+		}
+
+		dprintk("found\n");
+		d.id = ds->id;
+		d.iteration = ds->iteration;
+		d.argc = ds->args;
+
+		ret = 0;
+		if (copy_to_user(dcall,&d,sizeof(d)) != 0) { 
+			ret = -EFAULT;
+		}
+		break;
+
+	case DSYSCALL_CALL:
+		ret = -EFAULT;
+		if (copy_from_user(&d,dcall,sizeof(d)) != 0) {
+			goto out;
+		}
+
+		ds = find_dsyscall_by_id(&d);
+		if (!ds) {
+			ret = -ENODEV;
+			goto out;
+		}
+		/* Comparing to ds->args which can not be bigger than DSYSCALL_MAX_ARGS */
+		if (d.argc != ds->args) {
+			ret = -EINVAL;
+			goto out;
+		}
+		
+		if (d.argc > 0) {
+			if (copy_from_user(argv,d.argv,sizeof(char*)*d.argc) != 0) {
+				ret = -EFAULT;
+				goto out;
+			}
+		}
+
+		switch (d.argc) {
+		case 0:
+			ret = ds->func(0); /* The argument should be ignored */
+			break;
+		case 1:
+			ret = ds->func(argv[0]);
+			break;
+		case 2:
+			ret = ds->func(argv[0],argv[1]);
+			break;
+		case 3:
+			ret = ds->func(argv[0],argv[1],argv[2]);
+			break;
+		case 4:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3]);
+			break;
+		case 5:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4]);
+			break;
+		case 6:
+			ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]);
+			break;
+		}	
+		goto out;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+ out:
+	up_read(&dsyscall_sem);
+
+	return ret;
+}
+
+int dsyscall_register(char *name, int args, int (*func)(long,...))
+{
+	int ret = -1;
+	struct dsyscall_struct *ds;
+
+	dprintk("dsyscall_register: %s args: %d func=%p\n",name,args,func);
+
+	if (strlen(name) >= DSYSCALL_NAME_SZ) {
+		printk(KERN_INFO "dsyscall: name %s is too large.", name);
+		return -1;
+	}
+	if (args > DSYSCALL_MAX_ARGS) {
+		printk(KERN_INFO "dsyscall: args is too big.");
+		return -1;
+	}
+	
+	down_write(&dsyscall_sem);
+	if ((ds = find_dsyscall_by_name(name)) != NULL) {
+		printk(KERN_INFO "dsyscall: name %s is already in use.",name);
+		goto out;
+	}
+
+	ds = kmem_cache_alloc(dsyscall_cache,GFP_KERNEL);
+	if (!ds) {
+		printk(KERN_INFO "dsyscall: could not allocate dsyscall_struct");
+		goto out;
+	}
+
+	ds->args = args;
+	ds->func = func;
+	ds->id = dsyscall_next_id++;
+	ds->iteration = dsyscall_iterations;
+	if (!dsyscall_next_id) {
+		if (!++dsyscall_iterations) {
+			printk(KERN_WARNING "dsyscall: iterations has overflowed???");
+		}
+	}
+	strcpy(ds->name,name);
+	
+	list_add(&ds->next,&dsyscall_syscalls);
+	dsyscall_hash_add(ds);
+
+	ret = 0;
+ out:
+	up_write(&dsyscall_sem);
+	return ret;
+}
+
+int dsyscall_unregister(char *name)
+{
+	struct dsyscall_struct *ds;
+
+	down_write(&dsyscall_sem);
+	if ((ds = find_dsyscall_by_name(name)) == NULL) {
+		printk("dsyscall: name %s is not registered\n",name);
+		up_write(&dsyscall_sem);
+		return -1;
+	}
+
+	list_del(&ds->next);
+	list_del(&ds->link);
+
+	up_write(&dsyscall_sem);
+
+	kmem_cache_free(dsyscall_cache,ds);
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(dsyscall_register);
+EXPORT_SYMBOL_GPL(dsyscall_unregister);
+
+int __init dsyscall_init(void)
+{
+	int i;
+
+	dsyscall_cache = kmem_cache_create("dsyscalls", sizeof(struct dsyscall_struct),
+					   0, 0, NULL, NULL);
+	if (!dsyscall_cache)
+		panic ("Can't allocate dsyscall cache!");  /* Too much? something else is wrong if
+							      we fail here. */
+	
+	for (i=0; i < DSYSCALL_HASH_SIZE; i++) {
+		INIT_LIST_HEAD(&dsyscall_hash[i]);
+	}
+
+	return 0;
+}
+__initcall(dsyscall_init);
Index: include/asm-i386/unistd.h
===================================================================
--- include/asm-i386/unistd.h	(revision 15)
+++ include/asm-i386/unistd.h	(working copy)
@@ -300,8 +300,9 @@
 #define __NR_vperfctr_unlink	(__NR_perfctr_info+3)
 #define __NR_vperfctr_iresume	(__NR_perfctr_info+4)
 #define __NR_vperfctr_read	(__NR_perfctr_info+5)
+#define __NR_dsyscall		295
 
-#define NR_syscalls 295
+#define NR_syscalls 296
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
Index: include/linux/dsyscall.h
===================================================================
--- include/linux/dsyscall.h	(revision 0)
+++ include/linux/dsyscall.h	(revision 0)
@@ -0,0 +1,174 @@
+/*
+ * dsyscall.h
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _LINUX_DSYSCALL_H
+#define _LINUX_DSYSCALL_H
+
+#define DSYSCALL_NAME_SZ 128
+#define DSYSCALL_MAX_ARGS 6
+
+enum dsyscall_cmd {
+	DSYSCALL_GET = 1,
+	DSYSCALL_CALL,
+};
+
+struct dsyscall {
+	char name[DSYSCALL_NAME_SZ];	/* Name of system call */
+	long id;			/* unique id of available dynamic syscalls */
+	long iteration;			/* incase this box runs longer than we have been on earth
+					   count the iterations of id's. If interation overflows,
+					   then we are simply out of luck! */
+	int argc;			/* Number of arguments that this system call takes. */
+	long *argv;			/* pointer to the argument list */
+};
+
+#define DSYSCALL_FUNC(func) ((int(*)(long,...))func)
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+
+struct dsyscall_struct {
+	struct list_head next;		/* list of all dynamic syscalls */
+	struct list_head link;		/* used in the hash */
+	char name[DSYSCALL_NAME_SZ];	/* name of the dynamic syscall */	
+	int args;			/* number of arguments for this syscall */
+	int (*func)(long,...);		/* The actual dynamic system call */
+	long id;
+	long iteration;
+
+};
+
+int dsyscall_register(char *name, int args, int (*func)(long,...));
+int dsyscall_unregister(char *name);
+
+#else /* !__KERNEL__ */
+
+/* OK, this should probably be in another file for users */
+#include <asm/unistd.h>
+
+#define _dsyscall_call(name,args,arg) \
+{ \
+ long __res;  \
+ static int has_init = 0; \
+ static struct dsyscall ds; \
+ if (!has_init) { \
+	 __res = dsyscall(DSYSCALL_GET,#name,&ds); \
+	 if (!__res) \
+		 has_init = 1; \
+	 else \
+		 return __res; \
+ } \
+ ds.argc = args; \
+ ds.argv = arg; \
+ __res = dsyscall(DSYSCALL_CALL,#name,&ds); \
+ if (__res < 0 && errno == ENODEV) { \
+	 has_init = 0; \
+ } \
+ return __res; \
+}
+
+#define _dsyscall0(type,name) \
+type name(void) \
+{ \
+ long argv[0]; \
+ _dsyscall_call(name,0,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+ long argv[1]; \
+ argv[0] = (long)arg1; \
+ _dsyscall_call(name,1,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1, type2 arg2) \
+{ \
+ long argv[2]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ _dsyscall_call(name,2,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1, type2 arg2, type3 arg3) \
+{ \
+ long argv[3]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ _dsyscall_call(name,3,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall4(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+ long argv[4]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ _dsyscall_call(name,4,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall5(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+          type5 arg5) \
+{ \
+ long argv[5]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ _dsyscall_call(name,5,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall6(type,name,type1,arg1,type2,arg2,type3,arg3, \
+                   type4,arg4,type5,arg5,type6,arg6) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+          type5 arg5, type6 arg6) \
+{ \
+ long argv[6]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ argv[5] = (long)arg6; \
+ _dsyscall_call(name,6,argv); \
+ return 0; /* not reached */ \
+}
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DSYSCALL_H */
Index: init/Kconfig
===================================================================
--- init/Kconfig	(revision 15)
+++ init/Kconfig	(working copy)
@@ -249,6 +249,14 @@
 	  through /proc/config.gz.
 
 
+config DSYSCALL
+	bool "Enable dynamic system calls"
+	default y
+	help
+	  This option enables usage of dynamic system calls by drivers.
+	  This allows drivers to register system calls that are not
+	  already defined by the compiled kernel.
+
 menuconfig EMBEDDED
 	bool "Configure standard kernel features (for small systems)"
 	help
Index: arch/i386/kernel/entry.S
===================================================================
--- arch/i386/kernel/entry.S	(revision 15)
+++ arch/i386/kernel/entry.S	(working copy)
@@ -906,5 +906,10 @@
 	.long sys_vperfctr_unlink
 	.long sys_vperfctr_iresume
 	.long sys_vperfctr_read
+#ifdef CONFIG_DSYSCALL
+	.long sys_dsyscall		/* 295 */
+#else
+	.long sys_ni_syscall		/* 295 */
+#endif
 
 syscall_table_size=(.-sys_call_table)


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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 17:16           ` Steven Rostedt
@ 2004-12-06 17:32             ` Zwane Mwaikambo
  2004-12-06 17:57               ` linux-os
                                 ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Zwane Mwaikambo @ 2004-12-06 17:32 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: Adrian Bunk, Jan Engelhardt, LKML

On Mon, 6 Dec 2004, Steven Rostedt wrote:

> I added the following to my sys_dsyscall routine. The routine that is
> the only system call for a user process to access dynamic system calls
> (at anytime), even if dynamic system calls are loaded.
> 
> 	static int is_tainted = 0;
> 
> 	if (tainted & TAINT_PROPRIETARY_MODULE) {
> 		if (!is_tainted) {
> 			printk(KERN_INFO "Sorry, can't use dynamic system calls with proprietary modules\n");
> 			is_tainted = 1;
> 		}
> 		return -EINVAL;
> 	}
> 
> Once a proprietary module is loaded then all dynamic system calls will
> become useless.
> 
> This way, only systems that never loaded a proprietary module may be
> able to use dynamic system calls.  This may suck for those that have
> NVidia cards, but this may be a start to overcome the problem of
> allowing binary hooks into default kernels. It also is a way to motivate
> end users to not use proprietary modules.

I didn't know we were on a crusade to end all binary modules at all costs. 
Why not just make _all_ symbols in the kernel EXPORT_SYMBOL_GPL then? I 
really believe this is taking things to new levels of silliness, we should 
also possibly consider adding code in glibc to stop proprietary 
libraries/applications from running. What do you think?

	Zwane


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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 17:32             ` Zwane Mwaikambo
@ 2004-12-06 17:57               ` linux-os
  2004-12-06 18:03               ` Steven Rostedt
  2004-12-06 18:18               ` Arjan van de Ven
  2 siblings, 0 replies; 22+ messages in thread
From: linux-os @ 2004-12-06 17:57 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Steven Rostedt, Adrian Bunk, Jan Engelhardt, LKML

On Mon, 6 Dec 2004, Zwane Mwaikambo wrote:

> On Mon, 6 Dec 2004, Steven Rostedt wrote:
>
>> I added the following to my sys_dsyscall routine. The routine that is
>> the only system call for a user process to access dynamic system calls
>> (at anytime), even if dynamic system calls are loaded.
>>
>> 	static int is_tainted = 0;
>>
>> 	if (tainted & TAINT_PROPRIETARY_MODULE) {
>> 		if (!is_tainted) {
>> 			printk(KERN_INFO "Sorry, can't use dynamic system calls with proprietary modules\n");
>> 			is_tainted = 1;
>> 		}
>> 		return -EINVAL;
>> 	}
>>
>> Once a proprietary module is loaded then all dynamic system calls will
>> become useless.
>>
>> This way, only systems that never loaded a proprietary module may be
>> able to use dynamic system calls.  This may suck for those that have
>> NVidia cards, but this may be a start to overcome the problem of
>> allowing binary hooks into default kernels. It also is a way to motivate
>> end users to not use proprietary modules.
>
> I didn't know we were on a crusade to end all binary modules at all costs.
> Why not just make _all_ symbols in the kernel EXPORT_SYMBOL_GPL then? I
> really believe this is taking things to new levels of silliness, we should
> also possibly consider adding code in glibc to stop proprietary
> libraries/applications from running. What do you think?
>
> 	Zwane

Let 'em play their games. We all know how to fork a kernel
that works with our requirements. Currently, 'tainted' can
be zeroed-out with the /proc interface. Code like the demo
above puts one person's policy into the kernel. Policy is
not supposed to be inside the kernel.

Cheers,
Dick Johnson
Penguin : Linux version 2.6.9 on an i686 machine (5537.79 BogoMips).
  Notice : All mail here is now cached for review by John Ashcroft.
                  98.36% of all statistics are fiction.

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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 17:32             ` Zwane Mwaikambo
  2004-12-06 17:57               ` linux-os
@ 2004-12-06 18:03               ` Steven Rostedt
  2004-12-06 18:18               ` Arjan van de Ven
  2 siblings, 0 replies; 22+ messages in thread
From: Steven Rostedt @ 2004-12-06 18:03 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Adrian Bunk, Jan Engelhardt, LKML

On Mon, 2004-12-06 at 10:32 -0700, Zwane Mwaikambo wrote:

> 
> I didn't know we were on a crusade to end all binary modules at all costs. 
> Why not just make _all_ symbols in the kernel EXPORT_SYMBOL_GPL then? I 
> really believe this is taking things to new levels of silliness, we should 
> also possibly consider adding code in glibc to stop proprietary 
> libraries/applications from running. What do you think?

Personally? I don't really care. But what goes in the main linux kernel
is decided by Linus, and he doesn't want dynamic system calls because...

Back in 2000 Linus wrote:

The problem is that dynamic system calls are not going to happen.

Why?

License issues. I will not allow system calls to be added from modules.
Because I do not think that adding a system call is a valid thing for a
module to do. It's that easy.

It's the old thing about "hooks". You must not sidestep the GPL by just
putting a hook in place. And dynamic system calls are the ultimate hook.

                Linus


And I was just trying to solve the one reason that I can understand why
Linus doesn't want dynamic system calls. If Linus had not stated this, I
would not be changing my original patch (which is still available and
doesn't do any of this nastiness).

-- Steve

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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 17:32             ` Zwane Mwaikambo
  2004-12-06 17:57               ` linux-os
  2004-12-06 18:03               ` Steven Rostedt
@ 2004-12-06 18:18               ` Arjan van de Ven
  2 siblings, 0 replies; 22+ messages in thread
From: Arjan van de Ven @ 2004-12-06 18:18 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Steven Rostedt, Adrian Bunk, Jan Engelhardt, LKML


> I didn't know we were on a crusade to end all binary modules at all costs. 
> Why not just make _all_ symbols in the kernel EXPORT_SYMBOL_GPL then? I 
> really believe this is taking things to new levels of silliness, we should 
> also possibly consider adding code in glibc to stop proprietary 
> libraries/applications from running. What do you think?


unlike the glibc license (LGPL) the kernel license (GPL) does not allow 
for binary only modules to be linked against it.
So your question is a bit weird... 


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

* Re: [RFC] dynamic syscalls revisited
  2004-11-29 16:41   ` [RFC] " Jan Engelhardt
  2004-11-29 17:10     ` Steven Rostedt
@ 2004-12-06 21:14     ` H. Peter Anvin
  2004-12-06 22:01       ` Steven Rostedt
  1 sibling, 1 reply; 22+ messages in thread
From: H. Peter Anvin @ 2004-12-06 21:14 UTC (permalink / raw)
  To: linux-kernel

Followup to:  <Pine.LNX.4.53.0411291740390.30846@yvahk01.tjqt.qr>
By author:    Jan Engelhardt <jengelh@linux01.gwdg.de>
In newsgroup: linux.dev.kernel
> 
> I do not see how dsyscalls could be better than static ones, so they are
> one-on-one. Maybe someone could elaborate why they are "a really bad idea"?
> 

Because we already have a name resolution mechanism in the kernel,
called the filesystem?  We also have a mechanism for ad hoc system
calls, it's called ioctl().

And before you go "but ioctl() sucks": dynamic syscalls suck for
*exactly* the same reasons.

	-hpa

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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 21:14     ` H. Peter Anvin
@ 2004-12-06 22:01       ` Steven Rostedt
  2004-12-06 22:20         ` H. Peter Anvin
  0 siblings, 1 reply; 22+ messages in thread
From: Steven Rostedt @ 2004-12-06 22:01 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: LKML

On Mon, 2004-12-06 at 21:14 +0000, H. Peter Anvin wrote:
> Because we already have a name resolution mechanism in the kernel,
> called the filesystem?  We also have a mechanism for ad hoc system
> calls, it's called ioctl().
> 
> And before you go "but ioctl() sucks": dynamic syscalls suck for
> *exactly* the same reasons.
> 

I disagree about this statement.  ioctl's suck because they usually have
none, or very poor documentation and you are stuck with opening devices,
and sending parameters to them that may be for the wrong device and
there is really no good checking to see what you sent is what you want
since its all defined by human unreadable numbers.

As for dynamic system calls (and especially the way I've implemented
them) you have human readable names, with varying amount of parameters
that can make sense. So even if you still have none to very poor
documentation, you can understand things perhaps a little better.  There
is also much better checking in dynamic system calls than to ioctls.

So instead of 

struct mydev_struct myparams;

fd = open("/dev/mydev",O_RDWR);

myparams.arg1 = arg1;
myparams.arg2 = arg2;
... etc ...

ioctl(fd,IO_HOPE_THIS_IS_RIGHT_IOCTL_NUMBER,&myparams);


you now have

mydev_syscall(arg1,arg2,arg3,...);


But you do give me a idea on how to implement dynamic system calls with
the ioctl approach, and this can be added for anyone that wants dynamic
system calls. But I like my original patch better, since the ioctl way
would really be a nasty hack.

-- Steve


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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 22:01       ` Steven Rostedt
@ 2004-12-06 22:20         ` H. Peter Anvin
  2004-12-06 22:38           ` Steven Rostedt
  0 siblings, 1 reply; 22+ messages in thread
From: H. Peter Anvin @ 2004-12-06 22:20 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: LKML

Steven Rostedt wrote:
> 
> I disagree about this statement.  ioctl's suck because they usually have
> none, or very poor documentation and you are stuck with opening devices,
> and sending parameters to them that may be for the wrong device and
> there is really no good checking to see what you sent is what you want
> since its all defined by human unreadable numbers.
> 

That's like saying you might be calling the wrong syscall by accident.

> As for dynamic system calls (and especially the way I've implemented
> them) you have human readable names, with varying amount of parameters
> that can make sense. So even if you still have none to very poor
> documentation, you can understand things perhaps a little better.  There
> is also much better checking in dynamic system calls than to ioctls.

There is NO checking in the syscall interface.  Period.  Any such 
checking is a facility of some kind of stub generator, and that's 
independent of the method used to invoke it.

	-hpa





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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 22:20         ` H. Peter Anvin
@ 2004-12-06 22:38           ` Steven Rostedt
  2004-12-14 23:14             ` Werner Almesberger
  0 siblings, 1 reply; 22+ messages in thread
From: Steven Rostedt @ 2004-12-06 22:38 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: LKML

On Mon, 2004-12-06 at 14:20 -0800, H. Peter Anvin wrote:
> Steven Rostedt wrote:
> > 
> > I disagree about this statement.  ioctl's suck because they usually have
> > none, or very poor documentation and you are stuck with opening devices,
> > and sending parameters to them that may be for the wrong device and
> > there is really no good checking to see what you sent is what you want
> > since its all defined by human unreadable numbers.
> > 
> 
> That's like saying you might be calling the wrong syscall by accident.

It can be easier to send the wrong command to a device, or even the
wrong device than to use a wrong system call.  

You can do a mknod and use the wrong number, or have an outdated header
file, or wrong arch, and use the wrong command.  Usually either of these
will just break the application doing so, but still can be dangerous.

> > As for dynamic system calls (and especially the way I've implemented
> > them) you have human readable names, with varying amount of parameters
> > that can make sense. So even if you still have none to very poor
> > documentation, you can understand things perhaps a little better.  There
> > is also much better checking in dynamic system calls than to ioctls.
> 
> There is NO checking in the syscall interface.  Period.  Any such 
> checking is a facility of some kind of stub generator, and that's 
> independent of the method used to invoke it.

I'll grant you that there is a stub generator that facilitates this, but
the entire mechanism is still better than the ioctl interface, and it
does have some kind of checking.

To get a system call, you must first ask for it by name. This is where
ioctl and dynamic system calls do differ. Since the name would be define
and you would have to match it. It's harder to confuse a name than a
number. Of course they also differ with the fact that the dynamic system
calls don't need a device.

As for the stub generator (which does the above action), it still gives
the methodology of making the system call with a format to check that
the arguments match. Yes, you do have to use a macro to define your
system call (like any other system call), but once that is done, then
you have a way to check parameters before they are sent. It's not
perfect (what is) but still can be useful, and I'm arguing that it can
be a better interface than the ioctls.

-- Steve

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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 16:07         ` Steven Rostedt
  2004-12-06 17:16           ` Steven Rostedt
@ 2004-12-07  0:20           ` Michael Buesch
  2004-12-07  0:57             ` Steven Rostedt
  1 sibling, 1 reply; 22+ messages in thread
From: Michael Buesch @ 2004-12-07  0:20 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: Jan Engelhardt, LKML, Adrian Bunk

[-- Attachment #1: Type: text/plain, Size: 1067 bytes --]

Quoting Steven Rostedt <rostedt@goodmis.org>:
> Done!
> 
> Updated on http://home.stny.rr.com/rostedt/dynamic as well as included
> in this email for ease.  
> 
> Now, I guess you can still get around this if the "Bad Vendor" were to
> write a GPL module with their added system calls, and have that module
> include hooks to their binary module.  So, until we can fix that, I
> guess Linus won't allow for this module to be included in the main line.
> 
> -- Steve
[SNIP]
> Index: arch/i386/kernel/entry.S
> ===================================================================
> --- arch/i386/kernel/entry.S (revision 15)
> +++ arch/i386/kernel/entry.S (working copy)
> @@ -906,5 +906,10 @@
>   .long sys_vperfctr_unlink
>   .long sys_vperfctr_iresume
>   .long sys_vperfctr_read
> +#ifdef CONFIG_DSYSCALL
> + .long sys_dsyscall  /* 295 */
> +#else
> + .long sys_ni_syscall  /* 295 */
> +#endif

Wouldn't it be better to do a
cond_syscall(sys_dsyscall)
in kernel/sys_ni.c

-- 
Regards Michael Buesch  [ http://www.tuxsoft.de.vu ]



[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: [RFC] dynamic syscalls revisited
  2004-12-07  0:20           ` Michael Buesch
@ 2004-12-07  0:57             ` Steven Rostedt
  0 siblings, 0 replies; 22+ messages in thread
From: Steven Rostedt @ 2004-12-07  0:57 UTC (permalink / raw)
  To: Michael Buesch; +Cc: LKML

On Tue, 2004-12-07 at 01:20 +0100, Michael Buesch wrote:
> Wouldn't it be better to do a
> cond_syscall(sys_dsyscall)
> in kernel/sys_ni.c
> 

You learn something everyday!

Thanks,

-- Steve


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

* Re: [RFC] dynamic syscalls revisited
  2004-12-06 22:38           ` Steven Rostedt
@ 2004-12-14 23:14             ` Werner Almesberger
  2004-12-15  2:14               ` Steven Rostedt
  0 siblings, 1 reply; 22+ messages in thread
From: Werner Almesberger @ 2004-12-14 23:14 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: H. Peter Anvin, LKML

Steven Rostedt wrote:
> It can be easier to send the wrong command to a device, or even the
> wrong device than to use a wrong system call.  

So invent some /dev/syscall/<syscall-device-name> and you've reduced
this to good old clashes in a flat name space. You can hide all the
ugliness, sanity checking, etc. in a library.

I also think that a more direct approach for dynamic syscalls would
be nice, but the current status quo is far from unbearable.


- Werner

-- 
  _________________________________________________________________________
 / Werner Almesberger, Buenos Aires, Argentina         wa@almesberger.net /
/_http://www.almesberger.net/____________________________________________/

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

* Re: [RFC] dynamic syscalls revisited
  2004-12-14 23:14             ` Werner Almesberger
@ 2004-12-15  2:14               ` Steven Rostedt
  2004-12-15  3:35                 ` Steven Rostedt
  0 siblings, 1 reply; 22+ messages in thread
From: Steven Rostedt @ 2004-12-15  2:14 UTC (permalink / raw)
  To: Werner Almesberger; +Cc: H. Peter Anvin, LKML

On Tue, 2004-12-14 at 20:14 -0300, Werner Almesberger wrote:
> Steven Rostedt wrote:
> > It can be easier to send the wrong command to a device, or even the
> > wrong device than to use a wrong system call.  
> 
> So invent some /dev/syscall/<syscall-device-name> and you've reduced
> this to good old clashes in a flat name space. You can hide all the
> ugliness, sanity checking, etc. in a library.
> 

Already working on something. But I was a little distracted by some real
work :-)   But I'll have a little device driver that can implement
dynamic system calls soon, and a library that will hide the real
ugliness.

> I also think that a more direct approach for dynamic syscalls would
> be nice, but the current status quo is far from unbearable.
> 
> 
> - Werner
> 

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

* Re: [RFC] dynamic syscalls revisited
  2004-12-15  2:14               ` Steven Rostedt
@ 2004-12-15  3:35                 ` Steven Rostedt
  0 siblings, 0 replies; 22+ messages in thread
From: Steven Rostedt @ 2004-12-15  3:35 UTC (permalink / raw)
  To: Werner Almesberger; +Cc: H. Peter Anvin, LKML

On Tue, 2004-12-14 at 21:14 -0500, Steven Rostedt wrote:
> On Tue, 2004-12-14 at 20:14 -0300, Werner Almesberger wrote:
> > Steven Rostedt wrote:
> > > It can be easier to send the wrong command to a device, or even the
> > > wrong device than to use a wrong system call.  
> > 
> > So invent some /dev/syscall/<syscall-device-name> and you've reduced
> > this to good old clashes in a flat name space. You can hide all the
> > ugliness, sanity checking, etc. in a library.
> > 
> 
> Already working on something. But I was a little distracted by some real
> work :-)   But I'll have a little device driver that can implement
> dynamic system calls soon, and a library that will hide the real
> ugliness.
> 
> > I also think that a more direct approach for dynamic syscalls would
> > be nice, but the current status quo is far from unbearable.
> > 
> > 

OK, my first attempt at a hack is done. If anyone wants a quick and
nasty dynamic system call interface, here it is. It should work on any
arch, although it is not user space thread safe (SMP safe though). It
dynamically creates a device that implements system calls through it.
It's a hack, but it gets around the kernel maintainers from forbidding
dynamic system calls.

get it here:  http://home.stny.rr.com/rostedt/dynamic/dsyscall_dev.tgz

-- Steve


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

end of thread, other threads:[~2004-12-15  3:35 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-11-29 15:11 [PATCH][RFC] dynamic syscalls revisited Steven Rostedt
2004-11-29 15:17 ` Christoph Hellwig
2004-11-29 15:36   ` Steven Rostedt
2004-11-30 19:30     ` Kristian Sørensen
2004-11-29 16:41   ` [RFC] " Jan Engelhardt
2004-11-29 17:10     ` Steven Rostedt
2004-12-05 23:46       ` Adrian Bunk
2004-12-06 16:07         ` Steven Rostedt
2004-12-06 17:16           ` Steven Rostedt
2004-12-06 17:32             ` Zwane Mwaikambo
2004-12-06 17:57               ` linux-os
2004-12-06 18:03               ` Steven Rostedt
2004-12-06 18:18               ` Arjan van de Ven
2004-12-07  0:20           ` Michael Buesch
2004-12-07  0:57             ` Steven Rostedt
2004-12-06 21:14     ` H. Peter Anvin
2004-12-06 22:01       ` Steven Rostedt
2004-12-06 22:20         ` H. Peter Anvin
2004-12-06 22:38           ` Steven Rostedt
2004-12-14 23:14             ` Werner Almesberger
2004-12-15  2:14               ` Steven Rostedt
2004-12-15  3:35                 ` Steven Rostedt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).