Skip to contentSkip to conversation

Assigning syscall numbers for testing

PATCH In review Keith Owens 12 participants 30 messages Dec 22, 2001 – Dec 26, 2001 Proc filesystem

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Assigning syscall numbers for testing

It is clear (to me at least) that developers have problems assigning syscall numbers for testing, before their code is accepted into the kernel. Developers have to worry about collisions with everybody else who is testing syscalls. More importantly, the user space code has to "know" what the testing syscall number is this week. As a minor problem, strace cannot report on testing syscalls, except to print the number.

The patch below dynamically assigns a syscall number to a name and exports the number and name via /proc. Dynamic assignment removes the collision problem. Exporting via /proc allows user space code to automatically find out what the syscall number is this week. strace could read the /proc output to print the syscall name, although it still cannot print the arguments.

This facility must only be used while testing code, until the developer's code is accepted by Linus when it should be assigned a permanent syscall number. Anybody caught using this kernel facility for code that is in Linus's kernel will be hung, drawn, quartered then forced to write in COBOL.

To dynamically register a syscall number, ignoring error checking :-

  #include <linux/dynamic_syscalls.h>

printk(KERN_DEBUG "Assigned syscall number %d for %s\n",

     register_dynamic_syscall("attrctl", DYNAMIC_SYSCALL_FUNC(sys_attrctl)),
     "attrctl");

There is no deregister function. Syscalls are _not_ supported in modules, there is no architecture independent way of handling the branch from the syscall handler to a module. I know that people have done syscalls in modules but unless they have coded some architecture dependent assembler glue, I guarantee that their code will break on ia64 and ppc64. In any case, Linus has said that syscalls are not supported in modules. Ignore the modules howto, it is hopelessly out of date.

User space code should open /proc/dynamic_syscalls, read the lines looking for their syscall name, extract the number and call the glibc syscall() function using that number. Do not use the _syscalln() functions, they require a constant syscall number at compile time.

If the code cannot open /proc/dynamic_syscalls or cannot find the desired syscall name, fall back to the assigned syscall number (if any) or fail if there is no assigned syscall number. By falling back to the assigned syscall number, new versions of the user space code are backwards compatible, on older kernels it will use the dynamic syscall number, on newer kernels it will use the assigned number.

The patch has support for i386 and ia64. Each architecture needs include/asm-$(ARCH)/dynamic_syscalls.h defining the range of dynamic syscalls and information about entries in sys_call_table. On archs that use function pointers, DYNAMIC_SYSCALL_FUNCADDR must extract the function address from the descriptor.

The patch is against 2.4.17 but should fit 2.4.16 and 2.5 as well. Enjoy.

fs/proc/proc_misc.c +9 -0
diff -urN 2.4.16-pristine/fs/proc/proc_misc.c 2.4.16-syscalls/fs/proc/proc_misc.c
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
+#include <linux/dynamic_syscalls.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -320,6 +321,13 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
+static int dynamic_syscalls_read_proc(char *page, char **start, off_t off,
+				 int count, int *eof, void *data)
+{
+	int len = get_dynamic_syscalls_list(page);
+	return proc_calc_metrics(page, start, off, count, eof, len);
+}
+
 static int partitions_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
@@ -511,6 +519,7 @@
 #endif
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
+		{"dynamic_syscalls",	dynamic_syscalls_read_proc},
 		{"partitions",	partitions_read_proc},
 #if !defined(CONFIG_ARCH_S390)
 		{"interrupts",	interrupts_read_proc},
include/asm-i386/dynamic_syscalls.h +21 -0
diff -urN 2.4.16-pristine/include/asm-i386/dynamic_syscalls.h 2.4.16-syscalls/include/asm-i386/dynamic_syscalls.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_DYNAMIC_SYSCALLS_H
+#define _ASM_DYNAMIC_SYSCALLS_H
+
+#include <linux/sys.h>
+
+/* The first and last numbers do not have to be 100% accurate, register_dynamic_syscall
+ * will find the first free entry.  The offset and type must be accurate.
+ */
+
+#define DYNAMIC_SYSCALL_OFFSET		0
+#define DYNAMIC_SYSCALL_FIRST		226
+#define DYNAMIC_SYSCALL_LAST		NR_syscalls-1
+#define DYNAMIC_SYSCALL_T		long
+
+/* This is a noop on most systems.  It does real work on architectures that use
+ * function descriptors.  See asm-ia64/dynamic_syscalls.h for an example.
+ */
+
+#define DYNAMIC_SYSCALL_FUNCADDR(f)	(DYNAMIC_SYSCALL_T)(f)
+
+#endif /* _ASM_DYNAMIC_SYSCALLS_H */
include/asm-ia64/dynamic_syscalls.h +28 -0
diff -urN 2.4.16-pristine/include/asm-ia64/dynamic_syscalls.h 2.4.16-syscalls/include/asm-ia64/dynamic_syscalls.h
@@ -0,0 +1,28 @@
+#ifndef _ASM_DYNAMIC_SYSCALLS_H
+#define _ASM_DYNAMIC_SYSCALLS_H
+
+#include <linux/sys.h>
+
+/* The first and last numbers do not have to be 100% accurate, register_dynamic_syscall
+ * will find the first free entry.  The offset and type must be accurate.
+ */
+
+#define DYNAMIC_SYSCALL_OFFSET		1024
+#define DYNAMIC_SYSCALL_FIRST		(1217-DYNAMIC_SYSCALL_OFFSET)
+#define DYNAMIC_SYSCALL_LAST		NR_syscalls-1
+#define DYNAMIC_SYSCALL_T		long long
+
+/* IA64 function parameters do not point to the function itself, they point to a
+ * descriptor containing the 64 bit address of the function and the global
+ * pointer.  Dereference the function pointer to get the real function address,
+ * the syscall table requires direct addresses.
+ *
+ * This will almost certainly destroy your kernel if the syscall function is in
+ * a module because it will be entered with the wrong global pointer.
+ * Don't do that.
+ */
+
+#include <linux/types.h>
+#define DYNAMIC_SYSCALL_FUNCADDR(f)	({DYNAMIC_SYSCALL_T *fp = (DYNAMIC_SYSCALL_T *)(f); fp[0];})
+
+#endif /* _ASM_DYNAMIC_SYSCALLS_H */
include/linux/dynamic_syscalls.h +10 -0
diff -urN 2.4.16-pristine/include/linux/dynamic_syscalls.h 2.4.16-syscalls/include/linux/dynamic_syscalls.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_DYNAMIC_SYSCALLS_H
+#define _LINUX_DYNAMIC_SYSCALLS_H
+
+extern int get_syscalls_list(char *page);
+extern int register_dynamic_syscall(const char *name, void (*func)(void));
+extern int unregister_dynamic_syscall(const char *name);
+
+#define DYNAMIC_SYSCALL_FUNC(f) (void (*)(void))(&f)
+
+#endif /* _LINUX_DYNAMIC_SYSCALLS_H */
init/main.c +4 -0
diff -urN 2.4.16-pristine/init/main.c 2.4.16-syscalls/init/main.c
@@ -794,6 +794,8 @@
 #endif
 }
 
+#include <linux/dynamic_syscalls.h>
+
 static int init(void * unused)
 {
 	lock_kernel();
@@ -808,6 +810,8 @@
 	 */
 	free_initmem();
 	unlock_kernel();
+
+	printk("registered %d\n", register_dynamic_syscall("test", DYNAMIC_SYSCALL_FUNC(register_dynamic_syscall)));
 
 	if (open("/dev/console", O_RDWR, 0) < 0)
 		printk("Warning: unable to open an initial console.\n");
kernel/Makefile +1 -1
diff -urN 2.4.16-pristine/kernel/Makefile 2.4.16-syscalls/kernel/Makefile
@@ -14,7 +14,7 @@
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
-	    signal.o sys.o kmod.o context.o
+	    signal.o sys.o kmod.o context.o dynamic_syscalls.o
 
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
kernel/dynamic_syscalls.c +115 -0

115 lines not on this page · raw message

#1 lore raw
Quoted 4 lines

User space code should open /proc/dynamic_syscalls, read the lines looking for their syscall name, extract the number and call the glibc syscall() function using that number. Do not use the _syscalln() functions, they require a constant syscall number at compile time.

Simple brutal and to the point. Also it means a dynamic library can switch to real syscalls and dynamic apps will migrate fine.

One request - can we specify a namespace of the form

['vendorid'].[call]

vendorid is the wrong phrase but "some sane way of knowing whose syscall it is" - it would be bad for andrea-aio and ben-aio to use the same names..

Alan

#2 lore raw
Quoted 8 lines · Alan Cox
Quoted 4 lines

User space code should open /proc/dynamic_syscalls, read the lines looking for their syscall name, extract the number and call the glibc syscall() function using that number. Do not use the _syscalln() functions, they require a constant syscall number at compile time.

Simple brutal and to the point. Also it means a dynamic library can switch to real syscalls and dynamic apps will migrate fine.

Quoted 6 lines

One request - can we specify a namespace of the form

['vendorid'].[call]

vendorid is the wrong phrase but "some sane way of knowing whose syscall it is" - it would be bad for andrea-aio and ben-aio to use the same names..

Did that in the comments.

/**
* register_dynamic_syscall - assign a dynamic syscall number.
* @name: the name of the syscall, used by user space code to find the number.
* Use a unique name, if there is any possibility of conflict with
* other test syscalls then include your company or initials in the name.

#3 lore raw
In reply to Keith Owens
Quoted 6 lines · Keith Owens

The patch below dynamically assigns a syscall number to a name and exports the number and name via /proc. Dynamic assignment removes the collision problem. Exporting via /proc allows user space code to automatically find out what the syscall number is this week. strace could read the /proc output to print the syscall name, although it still cannot print the arguments.

Doesn't work. You've still got problems running binaries compiled against newer kernels (say, glibc supporting a new syscall) against the dynamic syscall. Numbers don't work, plain and simple.

-ben

#4 lore raw
Quoted 11 lines · Benjamin LaHaise
Quoted 6 lines · Keith Owens

The patch below dynamically assigns a syscall number to a name and exports the number and name via /proc. Dynamic assignment removes the collision problem. Exporting via /proc allows user space code to automatically find out what the syscall number is this week. strace could read the /proc output to print the syscall name, although it still cannot print the arguments.

Doesn't work. You've still got problems running binaries compiled against newer kernels (say, glibc supporting a new syscall) against the dynamic syscall. Numbers don't work, plain and simple.

You did not read my mail all the way through, did you? I said -

If the [user space] code cannot open /proc/dynamic_syscalls or cannot find the desired syscall name, fall back to the assigned syscall number (if any) or fail if there is no assigned syscall number. By falling back to the assigned syscall number, new versions of the user space code are backwards compatible, on older kernels it will use the dynamic syscall number, on newer kernels it will use the assigned number.

#5 lore raw
In reply to Benjamin LaHaise
Quoted 8 lines · Keith Owens

You did not read my mail all the way through, did you? I said -

If the [user space] code cannot open /proc/dynamic_syscalls or cannot find the desired syscall name, fall back to the assigned syscall number (if any) or fail if there is no assigned syscall number. By falling back to the assigned syscall number, new versions of the user space code are backwards compatible, on older kernels it will use the dynamic syscall number, on newer kernels it will use the assigned number.

No, that's not the case I'm talking about: what happens when a vendor starts shipping this patch and Linus decides to add a new syscall that uses a syscall number that the old kernel used for dynamic syscalls?

-ben

Signature · 1 line
Fish.
#6 lore raw
Quoted 10 lines · Benjamin LaHaise
Quoted 8 lines · Keith Owens

You did not read my mail all the way through, did you? I said -

If the [user space] code cannot open /proc/dynamic_syscalls or cannot find the desired syscall name, fall back to the assigned syscall number (if any) or fail if there is no assigned syscall number. By falling back to the assigned syscall number, new versions of the user space code are backwards compatible, on older kernels it will use the dynamic syscall number, on newer kernels it will use the assigned number.

Quoted 3 lines

No, that's not the case I'm talking about: what happens when a vendor starts shipping this patch and Linus decides to add a new syscall that uses a syscall number that the old kernel used for dynamic syscalls?

That is why the dynamic syscall range starts well above the currently allocated range. If you are looking at my first mail then the patch is wrong, in my second mail with the correct patch (first patch line is 17.1/kernel/Makefile) the dynamic range starts at 240.

#7 lore raw
In reply to Benjamin LaHaise
Quoted 3 lines

No, that's not the case I'm talking about: what happens when a vendor starts shipping this patch and Linus decides to add a new syscall that uses a syscall number that the old kernel used for dynamic syscalls?

Isn't that a non-issue, based on the patch that was sent? So, you change a few #define statements to point to other unused slots in the syscall table, and you're good to go.

If I understood correctly, /proc/dynamic_syscalls contains the information about dynamically registered syscall name->number associations, which are placed beyond the end of the currently registered set of syscalls. Later on down the line when we have 500 syscalls (exaggeration of course), the patch should still work as intended by just telling it that the empty slots in the syscall table begin at 501. So now your syscall that was registered as syscall 241 with the dynamic syscall patch in 2.4.17 now gets number 502 (or anything else for that matter) with the same patch under 5.4.23. Whee.

Chris

#8 lore raw
Quoted 4 lines · Chris Vandomelen
Quoted 3 lines

No, that's not the case I'm talking about: what happens when a vendor starts shipping this patch and Linus decides to add a new syscall that uses a syscall number that the old kernel used for dynamic syscalls?

Quoted 9 lines

If I understood correctly, /proc/dynamic_syscalls contains the information about dynamically registered syscall name->number associations, which are placed beyond the end of the currently registered set of syscalls. Later on down the line when we have 500 syscalls (exaggeration of course), the patch should still work as intended by just telling it that the empty slots in the syscall table begin at 501. So now your syscall that was registered as syscall 241 with the dynamic syscall patch in 2.4.17 now gets number 502 (or anything else for that matter) with the same patch under 5.4.23. Whee.

I'm glad somebody understands the code :).

#9 lore raw
In reply to Chris Vandomelen
Quoted 1 line · Keith Owens

I'm glad somebody understands the code :).

There are two directions of binary compatibility: forwads and backwards. Your patch breaks forwards compatibility if used outside the main tree. Try to understand this.

-ben

Signature · 1 line
Fish.
#10 lore raw
Quoted 6 lines · Benjamin LaHaise
Quoted 1 line · Keith Owens

I'm glad somebody understands the code :).

There are two directions of binary compatibility: forwads and backwards. Your patch breaks forwards compatibility if used outside the main tree. Try to understand this.

Guys, doing this in the correct way is not difficult, just we need glibc cooperation. The module ( app or sl ) will have a table of system call mappings :

unsinged sysmap[];

and it'll know that sys_getpid is entry 0, etc... ( static knowledge ). When invoking sys_getpid it'll load the syscall # register with sysmap[0] and then it'll invoke the syscall entry. Current system call will retain their current #ID and this will provide backward compatibility. The table is filled at module initialization time by calling ( for performance reasons ) a fixed #ID system call sys_namemap(), that will use an internal hashed map of system names to #ID, and will return the #ID given a system call name. If the module require a system call that it's not present inside the loading kernel, it'll fail the module load. glibc ver >= N will require kernel ver >= M ( that will have the sys_namemap() function ). System call names should be placed in a special gcc section where they can be easily looped at init time to fill the sysmap[] table. Where does it break ?

- Davide

#11 lore raw
In reply to Benjamin LaHaise
Quoted 6 lines · Benjamin LaHaise
Quoted 1 line · Keith Owens

I'm glad somebody understands the code :).

There are two directions of binary compatibility: forwads and backwards. Your patch breaks forwards compatibility if used outside the main tree. Try to understand this.

Too vague, give me an example with real code and effects.

#12 lore raw
Quoted 10 lines · Keith Owens
Quoted 6 lines · Benjamin LaHaise
Quoted 2 lines · Keith Owens

I'm glad somebody understands the code :).

There are two directions of binary compatibility: forwads and backwards. Your patch breaks forwards compatibility if used outside the main tree. Try to understand this.

Too vague, give me an example with real code and effects.

Well, I'm not going to mess with code, but here's the example. Say you start at syscall 240 for dynamic registration. Someone then submits a patch to Linus that he accepts and which uses syscalls 240 and 241. Now, you can modify the base of your patch, but if it has been accepted into any real kernels anywhere, then someone could inadvertently end up running a user space app compiled against Linus' new kernel and that uses the newly allocated syscalls 240 and 241. If that's run on an older kernel with your patch, then you call into the wrong syscalls with the wrong data. That's how forward compatibility is broken. Ben's point is that you can move the numbers up as high as you want, move them around as often as you want, but unless either A) Linus grants your dynamic range as an *official* set of syscall numbers or B) you get rid of the numbers entirely, it is never guaranteed to be compatible with binaries compiled against newer kernels.

Signature · 3 lines
 Doug Ledford <[email protected]>  http://people.redhat.com/dledford
      Please check my web site for aic7xxx updates/answers before
                      e-mailing me about problems
#13 lore raw
Quoted 2 lines

Well, I'm not going to mess with code, but here's the example. Say you start at syscall 240 for dynamic registration. Someone then submits a patch

The number you start at depends on the kernel you run.

Quoted 4 lines

modify the base of your patch, but if it has been accepted into any real kernels anywhere, then someone could inadvertently end up running a user space app compiled against Linus' new kernel and that uses the newly allocated syscalls 240 and 241. If that's run on an older kernel with your

The code on execution will read the syscall numbers from procfs. It will find new numbers and call those. Its a very simple implementation of lazy binding. It only breaks if you actually run out of syscalls, and then it fails safe.

Alan

#14 lore raw
Quoted 9 lines · Alan Cox
Quoted 2 lines

Well, I'm not going to mess with code, but here's the example. Say you start at syscall 240 for dynamic registration. Someone then submits a patch

The number you start at depends on the kernel you run.

Quoted 2 lines

modify the base of your patch, but if it has been accepted into any real kernels anywhere, then someone could inadvertently end up running a user space app compiled against Linus' new kernel and that uses the newly allocated syscalls 240 and 241. If that's run on an older kernel with your

Quoted 8 lines

The code on execution will read the syscall numbers from procfs. It will find new numbers and call those. Its a very simple implementation of lazy binding. It only breaks if you actually run out of syscalls, and then it fails safe.

Alan

No it doesn't. You are *assuming* that *all* code will check the lazy syscall bindings. My example was about code using the predefined syscall number for new functions on an older kernel where those functions don't exist, but where they overlap with the older dynamic syscall numbers. In short, the patch is safe for code that uses the lazy binding, but it can still overlap with future syscall numbers and code that doesn't use the lazy binding but instead uses predefined numbers.

Signature · 3 lines
 Doug Ledford <[email protected]>  http://people.redhat.com/dledford
      Please check my web site for aic7xxx updates/answers before
                      e-mailing me about problems
#15 lore raw

you miss the point, the syscall numbers will not nessasarily be consistant from boot to boot so if your code does not check for them it's seriously broken (and remember this is only for stuff in experimental status). The hope is that most if not all of the real checking can end up being done in glibc

David Lang

Quoted 51 lines · Doug Ledford

Date: Mon, 24 Dec 2001 12:06:19 -0500
From: Doug Ledford <[email protected]>
To: Alan Cox <[email protected]>
Cc: Keith Owens <[email protected]>, Benjamin LaHaise <[email protected]>,
[email protected]
Subject: Re: [patch] Assigning syscall numbers for testing

Quoted 13 lines · Alan Cox
Quoted 3 lines

Well, I'm not going to mess with code, but here's the example. Say you start at syscall 240 for dynamic registration. Someone then submits a patch

The number you start at depends on the kernel you run.

Quoted 5 lines

modify the base of your patch, but if it has been accepted into any real kernels anywhere, then someone could inadvertently end up running a user space app compiled against Linus' new kernel and that uses the newly allocated syscalls 240 and 241. If that's run on an older kernel with your

Quoted 8 lines

The code on execution will read the syscall numbers from procfs. It will find new numbers and call those. Its a very simple implementation of lazy binding. It only breaks if you actually run out of syscalls, and then it fails safe.

Alan

No it doesn't. You are *assuming* that *all* code will check the lazy syscall bindings. My example was about code using the predefined syscall number for new functions on an older kernel where those functions don't exist, but where they overlap with the older dynamic syscall numbers. In short, the patch is safe for code that uses the lazy binding, but it can still overlap with future syscall numbers and code that doesn't use the lazy binding but instead uses predefined numbers.

--

Doug Ledford <[email protected]> http://people.redhat.com/dledford
Please check my web site for aic7xxx updates/answers before
e-mailing me about problems

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#16 lore raw
Quoted 5 lines · David Lang

you miss the point, the syscall numbers will not nessasarily be consistant from boot to boot so if your code does not check for them it's seriously broken (and remember this is only for stuff in experimental status). The hope is that most if not all of the real checking can end up being done in glibc

No, I'm not missing the point. Try to follow with me here, this isn't rocket science. *NOT* *ALL* *SOFTWARE* *IS* *OR* *WILL* *BE* *USING* *DYNAMIC* *SYSCALLS*. Your scenario is fine if you want to convert all existing software to dynamic syscalls. However, my scenario specifically dealt with software that *DOES* *NOT* use dynamic syscalls (and which doesn't need to because the syscalls it *does* use have been allocated).

Since people are having such a hard time with this, let me spell it out in more detail. Assume the following scenario:

Linux 2.4.17 + dynamic syscall patch. Dynamic syscalls start at 240.

Linux 2.4.18 comes out, and now there are two *new* *official* *statically* *allocated* syscalls at 240 and 241 (they are SYSGETAMIBLKHEAD and SYSSETAMIBLKHEAD).

A new piece of software (or an existing one, doesn't matter) is written to take advantage of the new syscalls. It uses the *predefined* syscall numbers and is compiled against 2.4.18. It relies upon -ENOSYS (as is typical for non-dynamic syscalls) to indicate if the kernel doesn't support the intended syscalls.

Now, someone without realizing the implications of what's going on, runs this new program on a machine running the 2.4.17 + dynamic syscall patch.

BOOM!

So, to reiterate my points. This *IS* *NOT* *SAFE* unless either A) the dynamic syscall number range is officially allocated *before* the patch goes into use to avoid these collisions later or B) you switch *all* software to using dynamic syscalls (which does have a performance impact on the software and which would also require lots of work).

Quoted 62 lines

David Lang

Quoted 54 lines · Doug Ledford

Date: Mon, 24 Dec 2001 12:06:19 -0500
From: Doug Ledford <[email protected]>
To: Alan Cox <[email protected]>
Cc: Keith Owens <[email protected]>, Benjamin LaHaise <[email protected]>,
[email protected]
Subject: Re: [patch] Assigning syscall numbers for testing

Quoted 14 lines · Alan Cox
Quoted 4 lines

Well, I'm not going to mess with code, but here's the example. Say you start at syscall 240 for dynamic registration. Someone then submits a patch

The number you start at depends on the kernel you run.

Quoted 6 lines

modify the base of your patch, but if it has been accepted into any real kernels anywhere, then someone could inadvertently end up running a user space app compiled against Linus' new kernel and that uses the newly allocated syscalls 240 and 241. If that's run on an older kernel with your

Quoted 9 lines

The code on execution will read the syscall numbers from procfs. It will find new numbers and call those. Its a very simple implementation of lazy binding. It only breaks if you actually run out of syscalls, and then it fails safe.

Alan

No it doesn't. You are *assuming* that *all* code will check the lazy syscall bindings. My example was about code using the predefined syscall number for new functions on an older kernel where those functions don't exist, but where they overlap with the older dynamic syscall numbers. In short, the patch is safe for code that uses the lazy binding, but it can still overlap with future syscall numbers and code that doesn't use the lazy binding but instead uses predefined numbers.

--

Doug Ledford <[email protected]> http://people.redhat.com/dledford
Please check my web site for aic7xxx updates/answers before
e-mailing me about problems

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 3 lines
 Doug Ledford <[email protected]>  http://people.redhat.com/dledford
      Please check my web site for aic7xxx updates/answers before
                      e-mailing me about problems
#17 lore raw

so this just means that an eye needs to be kept on the non-dynamic syscalls and up the starting point for dynamic syscalls significantly before we run out of space for the non-dynamic ones.

running software that depends on features in a new kernel on a significantly older kernel is always questionable, if you software really needs to do that you need to watch for a bunch of things.

David Lang

Quoted 121 lines · Doug Ledford

Date: Mon, 24 Dec 2001 13:13:29 -0500
From: Doug Ledford <[email protected]>
To: David Lang <[email protected]>
Cc: Alan Cox <[email protected]>, Keith Owens <[email protected]>,
Benjamin LaHaise <[email protected]>, [email protected]
Subject: Re: [patch] Assigning syscall numbers for testing

Quoted 5 lines · David Lang

you miss the point, the syscall numbers will not nessasarily be consistant from boot to boot so if your code does not check for them it's seriously broken (and remember this is only for stuff in experimental status). The hope is that most if not all of the real checking can end up being done in glibc

No, I'm not missing the point. Try to follow with me here, this isn't rocket science. *NOT* *ALL* *SOFTWARE* *IS* *OR* *WILL* *BE* *USING* *DYNAMIC* *SYSCALLS*. Your scenario is fine if you want to convert all existing software to dynamic syscalls. However, my scenario specifically dealt with software that *DOES* *NOT* use dynamic syscalls (and which doesn't need to because the syscalls it *does* use have been allocated).

Since people are having such a hard time with this, let me spell it out in more detail. Assume the following scenario:

Linux 2.4.17 + dynamic syscall patch. Dynamic syscalls start at 240.

Linux 2.4.18 comes out, and now there are two *new* *official* *statically* *allocated* syscalls at 240 and 241 (they are SYSGETAMIBLKHEAD and SYSSETAMIBLKHEAD).

A new piece of software (or an existing one, doesn't matter) is written to take advantage of the new syscalls. It uses the *predefined* syscall numbers and is compiled against 2.4.18. It relies upon -ENOSYS (as is typical for non-dynamic syscalls) to indicate if the kernel doesn't support the intended syscalls.

Now, someone without realizing the implications of what's going on, runs this new program on a machine running the 2.4.17 + dynamic syscall patch.

BOOM!

So, to reiterate my points. This *IS* *NOT* *SAFE* unless either A) the dynamic syscall number range is officially allocated *before* the patch goes into use to avoid these collisions later or B) you switch *all* software to using dynamic syscalls (which does have a performance impact on the software and which would also require lots of work).

Quoted 4 lines

David Lang

Quoted 58 lines
Quoted 54 lines · Doug Ledford

Date: Mon, 24 Dec 2001 12:06:19 -0500
From: Doug Ledford <[email protected]>
To: Alan Cox <[email protected]>
Cc: Keith Owens <[email protected]>, Benjamin LaHaise <[email protected]>,
[email protected]
Subject: Re: [patch] Assigning syscall numbers for testing

Quoted 14 lines · Alan Cox
Quoted 4 lines

Well, I'm not going to mess with code, but here's the example. Say you start at syscall 240 for dynamic registration. Someone then submits a patch

The number you start at depends on the kernel you run.

Quoted 6 lines

modify the base of your patch, but if it has been accepted into any real kernels anywhere, then someone could inadvertently end up running a user space app compiled against Linus' new kernel and that uses the newly allocated syscalls 240 and 241. If that's run on an older kernel with your

Quoted 9 lines

The code on execution will read the syscall numbers from procfs. It will find new numbers and call those. Its a very simple implementation of lazy binding. It only breaks if you actually run out of syscalls, and then it fails safe.

Alan

No it doesn't. You are *assuming* that *all* code will check the lazy syscall bindings. My example was about code using the predefined syscall number for new functions on an older kernel where those functions don't exist, but where they overlap with the older dynamic syscall numbers. In short, the patch is safe for code that uses the lazy binding, but it can still overlap with future syscall numbers and code that doesn't use the lazy binding but instead uses predefined numbers.

--

Doug Ledford <[email protected]> http://people.redhat.com/dledford
Please check my web site for aic7xxx updates/answers before
e-mailing me about problems

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

--

Doug Ledford <[email protected]> http://people.redhat.com/dledford
Please check my web site for aic7xxx updates/answers before
e-mailing me about problems

#18 lore raw
Quoted 7 lines · David Lang

so this just means that an eye needs to be kept on the non-dynamic syscalls and up the starting point for dynamic syscalls significantly before we run out of space for the non-dynamic ones.

running software that depends on features in a new kernel on a significantly older kernel is always questionable, if you software really needs to do that you need to watch for a bunch of things.

No. This is different. Calling a syscall and expecting to get either A) the syscall you intended or B) -ENOSYS is an accepted, safe practice under Unix/Linux. This breaks that practice.

Signature · 3 lines
 Doug Ledford <[email protected]>  http://people.redhat.com/dledford
      Please check my web site for aic7xxx updates/answers before
                      e-mailing me about problems
#19 lore raw
In reply to David Lang

Hi David.

Quoted 3 lines

so this just means that an eye needs to be kept on the non-dynamic syscalls and up the starting point for dynamic syscalls significantly before we run out of space for the non-dynamic ones.

How far in advance do you call "significantly"? I know of dedicated systems still running Linux 1.2.12, and I use 2.0 series kernels on some of my systems, so your solution is a non-starter in my book.

I'd say that there are only three options for safely dealing with this problem...

1. Allocate a fixed range for dynamic syscalls that can NEVER be used by static ones. If the static syscalls hit the bottom of it, they skip it and restart just above its top.

Two variants of this have been proposed so far...

a. Negative syscall numbers are dynamic.

b. Syscall numbers with the MSB set are dynamic.

...and these are essentially variants on the same thing.

2. Each syscall includes a flag stating whether it's a static or dynamic one, with separate jump tables for each. This would be something that is currently always the same state for existing static syscalls.

One variant of this would be to redefine the syscall number as being two fields, with the MSB as the static/dynamic flag and the rest as the syscall number. This would incorporate option (1b) as a variant of this option.

3. Have separate syscall entry points for static and dynamic syscalls.

...and anything else is at risk from the scenario referred to.

Quoted 3 lines

running software that depends on features in a new kernel on a significantly older kernel is always questionable, if you software really needs to do that you need to watch for a bunch of things.

Very true, but not necessarily relevant.

Quoted 14 lines
Quoted 14 lines
Quoted 5 lines

you miss the point, the syscall numbers will not nessasarily be consistant from boot to boot so if your code does not check for them it's seriously broken (and remember this is only for stuff in experimental status). The hope is that most if not all of the real checking can end up being done in glibc

No, I'm not missing the point. Try to follow with me here, this isn't rocket science. *NOT* *ALL* *SOFTWARE* *IS* *OR* *WILL* *BE* *USING* *DYNAMIC* *SYSCALLS*. Your scenario is fine if you want to convert all existing software to dynamic syscalls. However, my scenario specifically dealt with software that *DOES* *NOT* use dynamic syscalls (and which doesn't need to because the syscalls it *does* use have been allocated).

Quoted 4 lines
Quoted 4 lines

Since people are having such a hard time with this, let me spell it out in more detail. Assume the following scenario:

Linux 2.4.17 + dynamic syscall patch. Dynamic syscalls start at 240.

Assume they finish at 255 for my comments below.

Quoted 3 lines
Quoted 3 lines

Linux 2.4.18 comes out, and now there are two *new* *official* *statically* *allocated* syscalls at 240 and 241 (they are SYSGETAMIBLKHEAD and SYSSETAMIBLKHEAD).

Preventing this would require that solution (1) has been implemented, in which case the new syscalls would be 256 and 257 as 240 through 255 are reserved for the dynamic syscalls.

Quoted 14 lines
Quoted 14 lines

A new piece of software (or an existing one, doesn't matter) is written to take advantage of the new syscalls. It uses the *predefined* syscall numbers and is compiled against 2.4.18. It relies upon -ENOSYS (as is typical for non-dynamic syscalls) to indicate if the kernel doesn't support the intended syscalls.

Now, someone without realizing the implications of what's going on, runs this new program on a machine running the 2.4.17+dynamic syscall patch.

BOOM!

So, to reiterate my points. This *IS* *NOT* *SAFE* unless either

Quoted 7 lines
Quoted 7 lines

A) the dynamic syscall number range is officially allocated *before* the patch goes into use to avoid these collisions later or

B) you switch *all* software to using dynamic syscalls (which does have a performance impact on the software and which would also require lots of work).

Best wishes from Riley.

#20 lore raw
In reply to Doug Ledford
Quoted 16 lines · Doug Ledford

David Lang wrote:
Since people are having such a hard time with this, let me spell it out in more detail. Assume the following scenario:

Linux 2.4.17 + dynamic syscall patch. Dynamic syscalls start at 240.

Linux 2.4.18 comes out, and now there are two *new* *official* *statically* *allocated* syscalls at 240 and 241 (they are SYSGETAMIBLKHEAD and SYSSETAMIBLKHEAD).

A new piece of software (or an existing one, doesn't matter) is written to take advantage of the new syscalls. It uses the *predefined* syscall numbers and is compiled against 2.4.18. It relies upon -ENOSYS (as is typical for non-dynamic syscalls) to indicate if the kernel doesn't support the intended syscalls.

Quoted 4 lines

Now, someone without realizing the implications of what's going on, runs this new program on a machine running the 2.4.17 + dynamic syscall patch.

BOOM!

i386 dynamic syscall table starts at 240. Last assigned syscall entry is currently 225, leaving room for 14 new assigned syscalls. 2.4.0 (January 5 2001) had 222 syscalls, so 2.4 added 3 assigned syscalls in just under a year. At that rate the dynamic syscall range is safe for 4 years. I make the reasonable assumption that new syscalls are assigned monotonically, that Linus does not arbitrarily assign numbers with gaps between them.

You can argue about whether the gap will close in 2 or 4 years. I suspect it will be longer than 4 years because syscall growth has been dropping off since 2.0.

You will only get a problem when :-

* The assigned numbers reach the dynamic range _and_
* A program with an assigned syscall that overlaps the old dynamic range runs on a 4 year old kernel _and_
* The 4 year old kernel has the dynamic syscall patch _and_
* Some code on the 4 year old kernel is using dynamic syscalls.

A problem will only arise if _all_ of those criteria are met. In particular the old kernel must still be running application code that uses dynamic syscalls, no dynamic syscalls used == no problem.

My patch is for _testing_ syscalls, not for long term use instead of getting assigned syscall numbers. Even if you run a brand new application on a 4 year old kernel, you will not still be running testing code on the old kernel.

I agree that it would be nice to have a permanently reserved dynamic range and if my patch goes into the kernel that is exactly what I will ask Linus for. Even if there is no reserved dynamic range, the risk of causing problems with new applications on old kernels is miniscule.

ps. Bah, humbug!

#21 lore raw
In reply to Doug Ledford
Quoted 4 lines · Keith Owens

i386 dynamic syscall table starts at 240. Last assigned syscall entry is currently 225, leaving room for 14 new assigned syscalls. 2.4.0 (January 5 2001) had 222 syscalls, so 2.4 added 3 assigned syscalls in just under a year.

Erm, there's a rather obvious flaw in your argument here - 2.4 is supposed to be a stable kernel with relatively few features appearing in it. We're now into 2.5. We've already seen several people trying to get new syscall numbers between 2.5.0 and 2.5.1, which is also a relatively short timeframe.

Lets look at some more realistic timeframe. These figures are for i386:

	2.2.20	- 190 syscalls, last one is sys_vfork
	2.4.17	- 225 syscalls, last one is sys_readahead

So, between these two stable kernel series, _35_ syscalls have been added. If we assume this trend will continue through 2.5, then we'll be up to 260 syscalls when 2.6 or 3.0 is out.

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

#22 lore raw
In reply to Doug Ledford
Quoted 6 lines

syscall bindings. My example was about code using the predefined syscall number for new functions on an older kernel where those functions don't exist, but where they overlap with the older dynamic syscall numbers. In short, the patch is safe for code that uses the lazy binding, but it can still overlap with future syscall numbers and code that doesn't use the lazy binding but instead uses predefined numbers.

Now I follow you. So if Linus takes that patch he needs to allocate a block of per architecture dynamic syscall number space for it to use. Negative syscall numbers seem the most promising approach ?

#23 lore raw
Quoted 8 lines · Alan Cox
Quoted 2 lines

syscall bindings. My example was about code using the predefined syscall number for new functions on an older kernel where those functions don't exist, but where they overlap with the older dynamic syscall numbers. In short, the patch is safe for code that uses the lazy binding, but it can still overlap with future syscall numbers and code that doesn't use the lazy binding but instead uses predefined numbers.

Now I follow you. So if Linus takes that patch he needs to allocate a block of per architecture dynamic syscall number space for it to use. Negative syscall numbers seem the most promising approach ?

Something like that. It needs to be a large enough range to reasonably support the maximum number of expected syscalls that could possibly be in testing at one time (which is a total guesstimate if you ask me), and it should hopefully be up high so that we aren't allocating new numbers around it. However, I think it needs to be allocated *regardless* of whether Linus takes the patch into his kernel. Even if the patch is simply used outside Linus's kernel, it still needs the allocation to truly be safe.

Signature · 3 lines
 Doug Ledford <[email protected]>  http://people.redhat.com/dledford
      Please check my web site for aic7xxx updates/answers before
                      e-mailing me about problems
#24 lore raw
Quoted 3 lines

it. However, I think it needs to be allocated *regardless* of whether Linus takes the patch into his kernel. Even if the patch is simply used outside Linus's kernel, it still needs the allocation to truly be safe.

Negative numbers are safe until Linus has 2^31 syscalls, at which point quite frankly we would have a few other problems including the fact that the syscall table won't fit in kernel mapped memory.

I'm sure we could get Linus to agree not to use negative numbers out of spite.

#25 lore raw
In reply to Doug Ledford
Quoted 7 lines · Alan Cox
Quoted 3 lines

it. However, I think it needs to be allocated *regardless* of whether Linus takes the patch into his kernel. Even if the patch is simply used outside Linus's kernel, it still needs the allocation to truly be safe.

Negative numbers are safe until Linus has 2^31 syscalls, at which point quite frankly we would have a few other problems including the fact that the syscall table won't fit in kernel mapped memory.

Please leave the allocation of the exact number space to the port maintainers discression.

--
Russell King ([email protected]) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html

#26 lore raw
Quoted 6 lines
Quoted 3 lines

Negative numbers are safe until Linus has 2^31 syscalls, at which point quite frankly we would have a few other problems including the fact that the syscall table won't fit in kernel mapped memory.

Please leave the allocation of the exact number space to the port maintainers discression.

Sorry.. I'm talking about x86 here. Linus is the x86 port maintainer as well so we have to plan it out that way. For non x86 sure.

Alan

#27 lore raw
In reply to Doug Ledford
Quoted 6 lines · Russell King
Quoted 4 lines · Alan Cox
Quoted 3 lines

it. However, I think it needs to be allocated *regardless* of whether Linus takes the patch into his kernel. Even if the patch is simply used outside Linus's kernel, it still needs the allocation to truly be safe.

Quoted 6 lines
Quoted 3 lines

Negative numbers are safe until Linus has 2^31 syscalls, at which point quite frankly we would have a few other problems including the fact that the syscall table won't fit in kernel mapped memory.

Please leave the allocation of the exact number space to the port maintainers discression.

Why not assign 1 syscall that gets the name of an experimental syscall as its first argument and does the demultiplexing?

Ciao, ET.

#28 lore raw
Quoted 13 lines · On 24-Dec-2001 Edgar Toernig wrote:
Quoted 12 lines · Russell King
Quoted 9 lines · Alan Cox
Quoted 5 lines

it. However, I think it needs to be allocated *regardless* of whether Linus
takes the patch into his kernel. Even if the patch is simply used outside
Linus's kernel, it still needs the allocation to truly be safe.

Negative numbers are safe until Linus has 2^31 syscalls, at which point quite frankly we would have a few other problems including the fact that the syscall table won't fit in kernel mapped memory.

Quoted 6 lines
Quoted 2 lines

Please leave the allocation of the exact number space to the port maintainers discression.

Why not assign 1 syscall that gets the name of an experimental syscall as its first argument and does the demultiplexing?

Please, no multiplexing. A well defined range (small as it may be) open to developers (and thus collision) will do.

Quoted 7 lines

Ciao, ET.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Andreas Steinmetz
D.O.M. Datenverarbeitung GmbH

#29 lore raw
In reply to Keith Owens

On Sat, 22 Dec 2001, Keith Owens wrote:

[...]

<>

Quoted 6 lines · Benjamin LaHaise

What I'm saying is that for more people to play with it, it needs to be more widely available. The set of developers that read linux-kernel and linux-aio aren't giving much feedback. I do not expect the code to go into 2.5 at this point in time. All I need is a set of syscall numbers that aren't going to change should this implementation stand up to the test of time.

It would be nice to have a cooperation between glibc and the kernel to have syscalls mapped by name, not by number.
With name->number resolved by crtbegin.o reading a public kernel table or accessing a fixed-ID kernel map function and filling a map. So if internally ( at the application ) sys_getpid has index 0, the sysmap[0] will be filled with the id retrieved inside the kernel by looking up "sys_getpid".
Eat too spicy today ?
<>

So i did not eat too spicy that day :)

- Davide