|
@@ -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
|