diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index a101ba36c444..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> |
@@ -621,11 +625,18 @@ static int set_user(struct cred *new) | |||
621 | if (!new_user) | 625 | if (!new_user) |
622 | return -EAGAIN; | 626 | return -EAGAIN; |
623 | 627 | ||
628 | /* | ||
629 | * We don't fail in case of NPROC limit excess here because too many | ||
630 | * poorly written programs don't check set*uid() return code, assuming | ||
631 | * it never fails if called by root. We may still enforce NPROC limit | ||
632 | * for programs doing set*uid()+execve() by harmlessly deferring the | ||
633 | * failure to the execve() stage. | ||
634 | */ | ||
624 | if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && | 635 | if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && |
625 | new_user != INIT_USER) { | 636 | new_user != INIT_USER) |
626 | free_uid(new_user); | 637 | current->flags |= PF_NPROC_EXCEEDED; |
627 | return -EAGAIN; | 638 | else |
628 | } | 639 | current->flags &= ~PF_NPROC_EXCEEDED; |
629 | 640 | ||
630 | free_uid(new->user); | 641 | free_uid(new->user); |
631 | new->user = new_user; | 642 | new->user = new_user; |
@@ -1154,6 +1165,34 @@ DECLARE_RWSEM(uts_sem); | |||
1154 | #define override_architecture(name) 0 | 1165 | #define override_architecture(name) 0 |
1155 | #endif | 1166 | #endif |
1156 | 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 | |||
1157 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | 1196 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) |
1158 | { | 1197 | { |
1159 | int errno = 0; | 1198 | int errno = 0; |
@@ -1163,6 +1202,8 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | |||
1163 | errno = -EFAULT; | 1202 | errno = -EFAULT; |
1164 | up_read(&uts_sem); | 1203 | up_read(&uts_sem); |
1165 | 1204 | ||
1205 | if (!errno && override_release(name->release, sizeof(name->release))) | ||
1206 | errno = -EFAULT; | ||
1166 | if (!errno && override_architecture(name)) | 1207 | if (!errno && override_architecture(name)) |
1167 | errno = -EFAULT; | 1208 | errno = -EFAULT; |
1168 | return errno; | 1209 | return errno; |
@@ -1184,6 +1225,8 @@ SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) | |||
1184 | error = -EFAULT; | 1225 | error = -EFAULT; |
1185 | up_read(&uts_sem); | 1226 | up_read(&uts_sem); |
1186 | 1227 | ||
1228 | if (!error && override_release(name->release, sizeof(name->release))) | ||
1229 | error = -EFAULT; | ||
1187 | if (!error && override_architecture(name)) | 1230 | if (!error && override_architecture(name)) |
1188 | error = -EFAULT; | 1231 | error = -EFAULT; |
1189 | return error; | 1232 | return error; |
@@ -1218,6 +1261,8 @@ SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) | |||
1218 | 1261 | ||
1219 | if (!error && override_architecture(name)) | 1262 | if (!error && override_architecture(name)) |
1220 | error = -EFAULT; | 1263 | error = -EFAULT; |
1264 | if (!error && override_release(name->release, sizeof(name->release))) | ||
1265 | error = -EFAULT; | ||
1221 | return error ? -EFAULT : 0; | 1266 | return error ? -EFAULT : 0; |
1222 | } | 1267 | } |
1223 | #endif | 1268 | #endif |