diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2011-09-20 21:45:56 +0200 | 
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2011-09-20 21:45:56 +0200 | 
| commit | 1fdb4888e45f1413972a8e9da55f3ffc08b9abcb (patch) | |
| tree | 635ef73cdff38d21a529bbdcab4cd2cb39a29484 /kernel/sys.c | |
| parent | 1884af9365a96314164f4110d4528d425e5dd843 (diff) | |
| parent | ceb1c532ba6220900e61ec7073a9234661efa450 (diff) | |
Merge branch 'omap/cleanup' into next/cleanup
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 38 | 
1 files changed, 38 insertions, 0 deletions
| diff --git a/kernel/sys.c b/kernel/sys.c index dd948a1fca4..18ee1d2f647 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -37,6 +37,8 @@  #include <linux/fs_struct.h>  #include <linux/gfp.h>  #include <linux/syscore_ops.h> +#include <linux/version.h> +#include <linux/ctype.h>  #include <linux/compat.h>  #include <linux/syscalls.h> @@ -44,6 +46,8 @@  #include <linux/user_namespace.h>  #include <linux/kmsg_dump.h> +/* Move somewhere else to avoid recompiling? */ +#include <generated/utsrelease.h>  #include <asm/uaccess.h>  #include <asm/io.h> @@ -1161,6 +1165,34 @@ DECLARE_RWSEM(uts_sem);  #define override_architecture(name)	0  #endif +/* + * Work around broken programs that cannot handle "Linux 3.0". + * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 + */ +static int override_release(char __user *release, int len) +{ +	int ret = 0; +	char buf[len]; + +	if (current->personality & UNAME26) { +		char *rest = UTS_RELEASE; +		int ndots = 0; +		unsigned v; + +		while (*rest) { +			if (*rest == '.' && ++ndots >= 3) +				break; +			if (!isdigit(*rest) && *rest != '.') +				break; +			rest++; +		} +		v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40; +		snprintf(buf, len, "2.6.%u%s", v, rest); +		ret = copy_to_user(release, buf, len); +	} +	return ret; +} +  SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)  {  	int errno = 0; @@ -1170,6 +1202,8 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)  		errno = -EFAULT;  	up_read(&uts_sem); +	if (!errno && override_release(name->release, sizeof(name->release))) +		errno = -EFAULT;  	if (!errno && override_architecture(name))  		errno = -EFAULT;  	return errno; @@ -1191,6 +1225,8 @@ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)  		error = -EFAULT;  	up_read(&uts_sem); +	if (!error && override_release(name->release, sizeof(name->release))) +		error = -EFAULT;  	if (!error && override_architecture(name))  		error = -EFAULT;  	return error; @@ -1225,6 +1261,8 @@ SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)  	if (!error && override_architecture(name))  		error = -EFAULT; +	if (!error && override_release(name->release, sizeof(name->release))) +		error = -EFAULT;  	return error ? -EFAULT : 0;  }  #endif | 
