diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 0da73cf73e60..e30eba430b96 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -49,6 +49,11 @@ | |||
49 | #include <linux/user_namespace.h> | 49 | #include <linux/user_namespace.h> |
50 | #include <linux/binfmts.h> | 50 | #include <linux/binfmts.h> |
51 | 51 | ||
52 | #include <linux/sched.h> | ||
53 | #include <linux/rcupdate.h> | ||
54 | #include <linux/uidgid.h> | ||
55 | #include <linux/cred.h> | ||
56 | |||
52 | #include <linux/kmsg_dump.h> | 57 | #include <linux/kmsg_dump.h> |
53 | /* Move somewhere else to avoid recompiling? */ | 58 | /* Move somewhere else to avoid recompiling? */ |
54 | #include <generated/utsrelease.h> | 59 | #include <generated/utsrelease.h> |
@@ -1044,6 +1049,67 @@ change_okay: | |||
1044 | return old_fsgid; | 1049 | return old_fsgid; |
1045 | } | 1050 | } |
1046 | 1051 | ||
1052 | /** | ||
1053 | * sys_getpid - return the thread group id of the current process | ||
1054 | * | ||
1055 | * Note, despite the name, this returns the tgid not the pid. The tgid and | ||
1056 | * the pid are identical unless CLONE_THREAD was specified on clone() in | ||
1057 | * which case the tgid is the same in all threads of the same group. | ||
1058 | * | ||
1059 | * This is SMP safe as current->tgid does not change. | ||
1060 | */ | ||
1061 | SYSCALL_DEFINE0(getpid) | ||
1062 | { | ||
1063 | return task_tgid_vnr(current); | ||
1064 | } | ||
1065 | |||
1066 | /* Thread ID - the internal kernel "pid" */ | ||
1067 | SYSCALL_DEFINE0(gettid) | ||
1068 | { | ||
1069 | return task_pid_vnr(current); | ||
1070 | } | ||
1071 | |||
1072 | /* | ||
1073 | * Accessing ->real_parent is not SMP-safe, it could | ||
1074 | * change from under us. However, we can use a stale | ||
1075 | * value of ->real_parent under rcu_read_lock(), see | ||
1076 | * release_task()->call_rcu(delayed_put_task_struct). | ||
1077 | */ | ||
1078 | SYSCALL_DEFINE0(getppid) | ||
1079 | { | ||
1080 | int pid; | ||
1081 | |||
1082 | rcu_read_lock(); | ||
1083 | pid = task_tgid_vnr(rcu_dereference(current->real_parent)); | ||
1084 | rcu_read_unlock(); | ||
1085 | |||
1086 | return pid; | ||
1087 | } | ||
1088 | |||
1089 | SYSCALL_DEFINE0(getuid) | ||
1090 | { | ||
1091 | /* Only we change this so SMP safe */ | ||
1092 | return from_kuid_munged(current_user_ns(), current_uid()); | ||
1093 | } | ||
1094 | |||
1095 | SYSCALL_DEFINE0(geteuid) | ||
1096 | { | ||
1097 | /* Only we change this so SMP safe */ | ||
1098 | return from_kuid_munged(current_user_ns(), current_euid()); | ||
1099 | } | ||
1100 | |||
1101 | SYSCALL_DEFINE0(getgid) | ||
1102 | { | ||
1103 | /* Only we change this so SMP safe */ | ||
1104 | return from_kgid_munged(current_user_ns(), current_gid()); | ||
1105 | } | ||
1106 | |||
1107 | SYSCALL_DEFINE0(getegid) | ||
1108 | { | ||
1109 | /* Only we change this so SMP safe */ | ||
1110 | return from_kgid_munged(current_user_ns(), current_egid()); | ||
1111 | } | ||
1112 | |||
1047 | void do_sys_times(struct tms *tms) | 1113 | void do_sys_times(struct tms *tms) |
1048 | { | 1114 | { |
1049 | cputime_t tgutime, tgstime, cutime, cstime; | 1115 | cputime_t tgutime, tgstime, cutime, cstime; |
@@ -2245,3 +2311,148 @@ int orderly_poweroff(bool force) | |||
2245 | return 0; | 2311 | return 0; |
2246 | } | 2312 | } |
2247 | EXPORT_SYMBOL_GPL(orderly_poweroff); | 2313 | EXPORT_SYMBOL_GPL(orderly_poweroff); |
2314 | |||
2315 | /** | ||
2316 | * do_sysinfo - fill in sysinfo struct | ||
2317 | * @info: pointer to buffer to fill | ||
2318 | */ | ||
2319 | static int do_sysinfo(struct sysinfo *info) | ||
2320 | { | ||
2321 | unsigned long mem_total, sav_total; | ||
2322 | unsigned int mem_unit, bitcount; | ||
2323 | struct timespec tp; | ||
2324 | |||
2325 | memset(info, 0, sizeof(struct sysinfo)); | ||
2326 | |||
2327 | ktime_get_ts(&tp); | ||
2328 | monotonic_to_bootbased(&tp); | ||
2329 | info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); | ||
2330 | |||
2331 | get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT); | ||
2332 | |||
2333 | info->procs = nr_threads; | ||
2334 | |||
2335 | si_meminfo(info); | ||
2336 | si_swapinfo(info); | ||
2337 | |||
2338 | /* | ||
2339 | * If the sum of all the available memory (i.e. ram + swap) | ||
2340 | * is less than can be stored in a 32 bit unsigned long then | ||
2341 | * we can be binary compatible with 2.2.x kernels. If not, | ||
2342 | * well, in that case 2.2.x was broken anyways... | ||
2343 | * | ||
2344 | * -Erik Andersen <andersee@debian.org> | ||
2345 | */ | ||
2346 | |||
2347 | mem_total = info->totalram + info->totalswap; | ||
2348 | if (mem_total < info->totalram || mem_total < info->totalswap) | ||
2349 | goto out; | ||
2350 | bitcount = 0; | ||
2351 | mem_unit = info->mem_unit; | ||
2352 | while (mem_unit > 1) { | ||
2353 | bitcount++; | ||
2354 | mem_unit >>= 1; | ||
2355 | sav_total = mem_total; | ||
2356 | mem_total <<= 1; | ||
2357 | if (mem_total < sav_total) | ||
2358 | goto out; | ||
2359 | } | ||
2360 | |||
2361 | /* | ||
2362 | * If mem_total did not overflow, multiply all memory values by | ||
2363 | * info->mem_unit and set it to 1. This leaves things compatible | ||
2364 | * with 2.2.x, and also retains compatibility with earlier 2.4.x | ||
2365 | * kernels... | ||
2366 | */ | ||
2367 | |||
2368 | info->mem_unit = 1; | ||
2369 | info->totalram <<= bitcount; | ||
2370 | info->freeram <<= bitcount; | ||
2371 | info->sharedram <<= bitcount; | ||
2372 | info->bufferram <<= bitcount; | ||
2373 | info->totalswap <<= bitcount; | ||
2374 | info->freeswap <<= bitcount; | ||
2375 | info->totalhigh <<= bitcount; | ||
2376 | info->freehigh <<= bitcount; | ||
2377 | |||
2378 | out: | ||
2379 | return 0; | ||
2380 | } | ||
2381 | |||
2382 | SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info) | ||
2383 | { | ||
2384 | struct sysinfo val; | ||
2385 | |||
2386 | do_sysinfo(&val); | ||
2387 | |||
2388 | if (copy_to_user(info, &val, sizeof(struct sysinfo))) | ||
2389 | return -EFAULT; | ||
2390 | |||
2391 | return 0; | ||
2392 | } | ||
2393 | |||
2394 | #ifdef CONFIG_COMPAT | ||
2395 | struct compat_sysinfo { | ||
2396 | s32 uptime; | ||
2397 | u32 loads[3]; | ||
2398 | u32 totalram; | ||
2399 | u32 freeram; | ||
2400 | u32 sharedram; | ||
2401 | u32 bufferram; | ||
2402 | u32 totalswap; | ||
2403 | u32 freeswap; | ||
2404 | u16 procs; | ||
2405 | u16 pad; | ||
2406 | u32 totalhigh; | ||
2407 | u32 freehigh; | ||
2408 | u32 mem_unit; | ||
2409 | char _f[20-2*sizeof(u32)-sizeof(int)]; | ||
2410 | }; | ||
2411 | |||
2412 | COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info) | ||
2413 | { | ||
2414 | struct sysinfo s; | ||
2415 | |||
2416 | do_sysinfo(&s); | ||
2417 | |||
2418 | /* Check to see if any memory value is too large for 32-bit and scale | ||
2419 | * down if needed | ||
2420 | */ | ||
2421 | if ((s.totalram >> 32) || (s.totalswap >> 32)) { | ||
2422 | int bitcount = 0; | ||
2423 | |||
2424 | while (s.mem_unit < PAGE_SIZE) { | ||
2425 | s.mem_unit <<= 1; | ||
2426 | bitcount++; | ||
2427 | } | ||
2428 | |||
2429 | s.totalram >>= bitcount; | ||
2430 | s.freeram >>= bitcount; | ||
2431 | s.sharedram >>= bitcount; | ||
2432 | s.bufferram >>= bitcount; | ||
2433 | s.totalswap >>= bitcount; | ||
2434 | s.freeswap >>= bitcount; | ||
2435 | s.totalhigh >>= bitcount; | ||
2436 | s.freehigh >>= bitcount; | ||
2437 | } | ||
2438 | |||
2439 | if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) || | ||
2440 | __put_user(s.uptime, &info->uptime) || | ||
2441 | __put_user(s.loads[0], &info->loads[0]) || | ||
2442 | __put_user(s.loads[1], &info->loads[1]) || | ||
2443 | __put_user(s.loads[2], &info->loads[2]) || | ||
2444 | __put_user(s.totalram, &info->totalram) || | ||
2445 | __put_user(s.freeram, &info->freeram) || | ||
2446 | __put_user(s.sharedram, &info->sharedram) || | ||
2447 | __put_user(s.bufferram, &info->bufferram) || | ||
2448 | __put_user(s.totalswap, &info->totalswap) || | ||
2449 | __put_user(s.freeswap, &info->freeswap) || | ||
2450 | __put_user(s.procs, &info->procs) || | ||
2451 | __put_user(s.totalhigh, &info->totalhigh) || | ||
2452 | __put_user(s.freehigh, &info->freehigh) || | ||
2453 | __put_user(s.mem_unit, &info->mem_unit)) | ||
2454 | return -EFAULT; | ||
2455 | |||
2456 | return 0; | ||
2457 | } | ||
2458 | #endif /* CONFIG_COMPAT */ | ||