diff options
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 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 |