diff options
| author | Andi Kleen <ak@linux.intel.com> | 2011-08-19 19:15:10 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-08-25 13:17:28 -0400 |
| commit | be27425dcc516fd08245b047ea57f83b8f6f0903 (patch) | |
| tree | 0f7cfb258a663d99ebeedf8ed3b9637b266b021c /kernel | |
| parent | caca9510ff4e5d842c0589110243d60927836222 (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')
| -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 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 | */ | ||
| 1172 | static 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 | |||
| 1164 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | 1196 | SYSCALL_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 |
