aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2011-08-19 19:15:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-08-25 13:17:28 -0400
commitbe27425dcc516fd08245b047ea57f83b8f6f0903 (patch)
tree0f7cfb258a663d99ebeedf8ed3b9637b266b021c /kernel/sys.c
parentcaca9510ff4e5d842c0589110243d60927836222 (diff)
Add a personality to report 2.6.x version numbers
I ran into a couple of programs which broke with the new Linux 3.0 version. Some of those were binary only. I tried to use LD_PRELOAD to work around it, but it was quite difficult and in one case impossible because of a mix of 32bit and 64bit executables. For example, all kind of management software from HP doesnt work, unless we pretend to run a 2.6 kernel. $ uname -a Linux svivoipvnx001 3.0.0-08107-g97cd98f #1062 SMP Fri Aug 12 18:11:45 CEST 2011 i686 i686 i386 GNU/Linux $ hpacucli ctrl all show Error: No controllers detected. $ rpm -qf /usr/sbin/hpacucli hpacucli-8.75-12.0 Another notable case is that Python now reports "linux3" from sys.platform(); which in turn can break things that were checking sys.platform() == "linux2": https://bugzilla.mozilla.org/show_bug.cgi?id=664564 It seems pretty clear to me though it's a bug in the apps that are using '==' instead of .startswith(), but this allows us to unbreak broken programs. This patch adds a UNAME26 personality that makes the kernel report a 2.6.40+x version number instead. The x is the x in 3.x. I know this is somewhat ugly, but I didn't find a better workaround, and compatibility to existing programs is important. Some programs also read /proc/sys/kernel/osrelease. This can be worked around in user space with mount --bind (and a mount namespace) To use: wget ftp://ftp.kernel.org/pub/linux/kernel/people/ak/uname26/uname26.c gcc -o uname26 uname26.c ./uname26 program Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index dd948a1fca4c..18ee1d2f6474 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -37,6 +37,8 @@
37#include <linux/fs_struct.h> 37#include <linux/fs_struct.h>
38#include <linux/gfp.h> 38#include <linux/gfp.h>
39#include <linux/syscore_ops.h> 39#include <linux/syscore_ops.h>
40#include <linux/version.h>
41#include <linux/ctype.h>
40 42
41#include <linux/compat.h> 43#include <linux/compat.h>
42#include <linux/syscalls.h> 44#include <linux/syscalls.h>
@@ -44,6 +46,8 @@
44#include <linux/user_namespace.h> 46#include <linux/user_namespace.h>
45 47
46#include <linux/kmsg_dump.h> 48#include <linux/kmsg_dump.h>
49/* Move somewhere else to avoid recompiling? */
50#include <generated/utsrelease.h>
47 51
48#include <asm/uaccess.h> 52#include <asm/uaccess.h>
49#include <asm/io.h> 53#include <asm/io.h>
@@ -1161,6 +1165,34 @@ DECLARE_RWSEM(uts_sem);
1161#define override_architecture(name) 0 1165#define override_architecture(name) 0
1162#endif 1166#endif
1163 1167
1168/*
1169 * Work around broken programs that cannot handle "Linux 3.0".
1170 * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
1171 */
1172static int override_release(char __user *release, int len)
1173{
1174 int ret = 0;
1175 char buf[len];
1176
1177 if (current->personality & UNAME26) {
1178 char *rest = UTS_RELEASE;
1179 int ndots = 0;
1180 unsigned v;
1181
1182 while (*rest) {
1183 if (*rest == '.' && ++ndots >= 3)
1184 break;
1185 if (!isdigit(*rest) && *rest != '.')
1186 break;
1187 rest++;
1188 }
1189 v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
1190 snprintf(buf, len, "2.6.%u%s", v, rest);
1191 ret = copy_to_user(release, buf, len);
1192 }
1193 return ret;
1194}
1195
1164SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) 1196SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
1165{ 1197{
1166 int errno = 0; 1198 int errno = 0;
@@ -1170,6 +1202,8 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
1170 errno = -EFAULT; 1202 errno = -EFAULT;
1171 up_read(&uts_sem); 1203 up_read(&uts_sem);
1172 1204
1205 if (!errno && override_release(name->release, sizeof(name->release)))
1206 errno = -EFAULT;
1173 if (!errno && override_architecture(name)) 1207 if (!errno && override_architecture(name))
1174 errno = -EFAULT; 1208 errno = -EFAULT;
1175 return errno; 1209 return errno;
@@ -1191,6 +1225,8 @@ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
1191 error = -EFAULT; 1225 error = -EFAULT;
1192 up_read(&uts_sem); 1226 up_read(&uts_sem);
1193 1227
1228 if (!error && override_release(name->release, sizeof(name->release)))
1229 error = -EFAULT;
1194 if (!error && override_architecture(name)) 1230 if (!error && override_architecture(name))
1195 error = -EFAULT; 1231 error = -EFAULT;
1196 return error; 1232 return error;
@@ -1225,6 +1261,8 @@ SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
1225 1261
1226 if (!error && override_architecture(name)) 1262 if (!error && override_architecture(name))
1227 error = -EFAULT; 1263 error = -EFAULT;
1264 if (!error && override_release(name->release, sizeof(name->release)))
1265 error = -EFAULT;
1228 return error ? -EFAULT : 0; 1266 return error ? -EFAULT : 0;
1229} 1267}
1230#endif 1268#endif