arch/x86/kernel/syscall_table_32.S | 2 include/asm-generic/resource.h | 11 +++ include/asm-x86/unistd_32.h | 2 include/linux/init_task.h | 1 include/linux/resource.h | 5 + include/linux/sched.h | 1 kernel/ChangeLog | 10 ++ kernel/sys.c | 126 +++++++++++++++++++++++++++++++++++++ 8 files changed, 158 insertions(+) diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/arch/x86/kernel/syscall_table_32.S linux-2.6.26-rlim64/arch/x86/kernel/syscall_table_32.S --- linux-2.6.26-base/arch/x86/kernel/syscall_table_32.S 2008-07-14 03:21:29.000000000 +0530 +++ linux-2.6.26-rlim64/arch/x86/kernel/syscall_table_32.S 2008-07-20 21:06:22.000000000 +0530 @@ -326,3 +326,5 @@ ENTRY(sys_call_table) .long sys_fallocate .long sys_timerfd_settime /* 325 */ .long sys_timerfd_gettime + .long sys_setrlimit64 + .long sys_getrlimit64 diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/include/asm-generic/resource.h linux-2.6.26-rlim64/include/asm-generic/resource.h --- linux-2.6.26-base/include/asm-generic/resource.h 2008-07-14 03:21:29.000000000 +0530 +++ linux-2.6.26-rlim64/include/asm-generic/resource.h 2008-07-20 21:10:48.000000000 +0530 @@ -46,6 +46,7 @@ #define RLIMIT_RTPRIO 14 /* maximum realtime priority */ #define RLIMIT_RTTIME 15 /* timeout for RT tasks in us */ #define RLIM_NLIMITS 16 +#define RLIM64_NLIMITS 2 /* * SuS says limits have to be unsigned. @@ -57,6 +58,10 @@ # define RLIM_INFINITY (~0UL) #endif +#ifndef RLIM64_INFINITY +# define RLIM64_INFINITY (~0ULL) +#endif + /* * RLIMIT_STACK default maximum - some architectures override it: */ @@ -89,6 +94,12 @@ [RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY }, \ } +#define INIT_RLIMITS64 \ +{ \ + [0] = { RLIM64_INFINITY, RLIM64_INFINITY }, \ + [RLIMIT_FSIZE] = { RLIM64_INFINITY, RLIM64_INFINITY }, \ +} + #endif /* __KERNEL__ */ #endif diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/include/asm-x86/unistd_32.h linux-2.6.26-rlim64/include/asm-x86/unistd_32.h --- linux-2.6.26-base/include/asm-x86/unistd_32.h 2008-07-14 03:21:29.000000000 +0530 +++ linux-2.6.26-rlim64/include/asm-x86/unistd_32.h 2008-07-20 21:12:41.000000000 +0530 @@ -332,6 +332,8 @@ #define __NR_fallocate 324 #define __NR_timerfd_settime 325 #define __NR_timerfd_gettime 326 +#define __NR_setrlimit64 327 +#define __NR_getrlimit64 328 #ifdef __KERNEL__ diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/include/linux/init_task.h linux-2.6.26-rlim64/include/linux/init_task.h --- linux-2.6.26-base/include/linux/init_task.h 2008-07-14 03:21:29.000000000 +0530 +++ linux-2.6.26-rlim64/include/linux/init_task.h 2008-07-20 21:14:24.000000000 +0530 @@ -47,6 +47,7 @@ extern struct files_struct init_files; .posix_timers = LIST_HEAD_INIT(sig.posix_timers), \ .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \ .rlim = INIT_RLIMITS, \ + .rlim64 = INIT_RLIMITS64, \ } extern struct nsproxy init_nsproxy; diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/include/linux/resource.h linux-2.6.26-rlim64/include/linux/resource.h --- linux-2.6.26-base/include/linux/resource.h 2008-07-14 03:21:29.000000000 +0530 +++ linux-2.6.26-rlim64/include/linux/resource.h 2008-07-20 21:15:22.000000000 +0530 @@ -45,6 +45,11 @@ struct rlimit { unsigned long rlim_max; }; +struct rlimit64 { + u64 rlim64_cur; + u64 rlim64_max; +}; + #define PRIO_MIN (-20) #define PRIO_MAX 20 diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/include/linux/sched.h linux-2.6.26-rlim64/include/linux/sched.h --- linux-2.6.26-base/include/linux/sched.h 2008-07-14 03:21:29.000000000 +0530 +++ linux-2.6.26-rlim64/include/linux/sched.h 2008-07-20 21:17:05.000000000 +0530 @@ -523,6 +523,7 @@ struct signal_struct { * have no need to disable irqs. */ struct rlimit rlim[RLIM_NLIMITS]; + struct rlimit64 rlim64[RLIM64_NLIMITS]; struct list_head cpu_timers[3]; diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/kernel/ChangeLog linux-2.6.26-rlim64/kernel/ChangeLog --- linux-2.6.26-base/kernel/ChangeLog 1970-01-01 05:30:00.000000000 +0530 +++ linux-2.6.26-rlim64/kernel/ChangeLog 2008-07-28 16:06:15.000000000 +0530 @@ -0,0 +1,10 @@ +2008-07-28 Narendra Prasad + Problem Description: + The following issue affects the setrlimit() and getrlimit() system calls on Linux 2.6.13 (and earlier) on x86. + The Problem is filed at kernel.org bug 5042 (http://bugzilla.kernel.org/show_bug.cgi?id=5042) + Design Approach: + Add two system calls sys_setrlimit64()/sys_getrlimit64(). + And a type 'struct rlimit64' to accomodate limits more <= 2^64-1 + Implementation Details: + Inclutions: struct rlimit64, struct rlimit64 + rlim64[RLIM64_NRLIMITS] to task_struct diff -uNrp -X linux-2.6.26-base/Documentation/dontdiff linux-2.6.26-base/kernel/sys.c linux-2.6.26-rlim64/kernel/sys.c --- linux-2.6.26-base/kernel/sys.c 2008-07-14 03:21:29.000000000 +0530 +++ linux-2.6.26-rlim64/kernel/sys.c 2008-07-28 15:41:02.000000000 +0530 @@ -1524,6 +1524,132 @@ out: return 0; } +asmlinkage long sys_getrlimit64(unsigned int resource, struct rlimit64 __user *rlim) +{ + struct rlimit64 value; + + if (resource >= RLIM_NLIMITS) + return -EINVAL; + + printk("\nresource = %d, RLIM64_INFINITY = %llx, RLIMIT_FSIZE = %d, RLIM64_NLIMITS = %d", + resource, RLIM64_INFINITY, RLIMIT_FSIZE, RLIM64_NLIMITS); + if (resource == RLIMIT_FSIZE) { + task_lock(current->group_leader); + printk("\ncurrent rlim64 : max64 = %llx, cur64 = %llx", + current->signal->rlim64[resource].rlim64_max, current->signal->rlim64[resource].rlim64_cur); + printk("\nvalue (local var, before) : max64 = %llx, cur64 = %llx", value.rlim64_max, value.rlim64_cur); + value = current->signal->rlim64[resource]; + printk("\nvalue (after assignment) : max64 = %llx, cur64 = %llx", value.rlim64_max, value.rlim64_cur); + task_unlock(current->group_leader); + return copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; + } + else { + task_lock(current->group_leader); + value.rlim64_max = current->signal->rlim[resource].rlim_max; + value.rlim64_cur = current->signal->rlim[resource].rlim_cur; + task_unlock(current->group_leader); + if (value.rlim64_cur == RLIM_INFINITY) + value.rlim64_cur = RLIM64_INFINITY; + if (value.rlim64_max == RLIM_INFINITY) + value.rlim64_max = RLIM64_INFINITY; + /* XX: RLIM_SAVED_MAX ? RLIM_SAVED_CUR ? (See Large-File-Summit) */ + } + return (copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0); +} + +asmlinkage long sys_setrlimit64(unsigned int resource, struct rlimit64 __user *rlim) +{ + struct rlimit64 new_rlim; + struct rlimit *old_rlim, new_value; + unsigned long it_prof_secs; + int retval; + + if (resource >= RLIM_NLIMITS) + return -EINVAL; + if(copy_from_user(&new_rlim, rlim, sizeof(*rlim))) + return -EFAULT; + + if (resource == RLIMIT_FSIZE) { + struct rlimit64 *old_rlim; + struct rlimit *old_value; + + old_rlim = current->signal->rlim64 + resource; + if (((new_rlim.rlim64_cur > old_rlim->rlim64_max) || + (new_rlim.rlim64_max > old_rlim->rlim64_max)) && + !capable(CAP_SYS_RESOURCE)) + return -EPERM; + *old_rlim = new_rlim; + if (new_rlim.rlim64_cur > RLIM_INFINITY) + new_rlim.rlim64_cur = RLIM_INFINITY; + if (new_rlim.rlim64_max > RLIM_INFINITY) + new_rlim.rlim64_max = RLIM_INFINITY; + task_lock(current->group_leader); + old_value = (current->signal->rlim + resource); + old_value->rlim_max = new_rlim.rlim64_max; + old_value->rlim_cur = new_rlim.rlim64_cur; + task_unlock(current->group_leader); + return 0; + } + + old_rlim = current->signal->rlim + resource; + if (new_rlim.rlim64_cur > RLIM_INFINITY) new_rlim.rlim64_cur = RLIM_INFINITY; + if (new_rlim.rlim64_max > RLIM_INFINITY) new_rlim.rlim64_max = RLIM_INFINITY; + if (((new_rlim.rlim64_cur > old_rlim->rlim_max) || + (new_rlim.rlim64_max > old_rlim->rlim_max)) && + !capable(CAP_SYS_RESOURCE)) + return -EPERM; + if (resource == RLIMIT_NOFILE) { + if (new_rlim.rlim64_cur > INR_OPEN || new_rlim.rlim64_max > INR_OPEN) + return -EPERM; + } + new_value.rlim_max = new_rlim.rlim64_max; + new_value.rlim_cur = new_rlim.rlim64_cur; + retval = security_task_setrlimit(resource, &new_value); + if (retval) + return retval; + + if (resource == RLIMIT_CPU && new_value.rlim_cur == 0) { + /* + * The caller is asking for an immediate RLIMIT_CPU + * expiry. But we use the zero value to mean "it was + * never set". So let's cheat and make it one second + * instead + */ + new_value.rlim_cur = 1; + } + + task_lock(current->group_leader); + *old_rlim = new_value; + task_unlock(current->group_leader); + + if (resource != RLIMIT_CPU) + goto out; + + /* + * RLIMIT_CPU handling. Note that the kernel fails to return an error + * code if it rejected the user's attempt to set RLIMIT_CPU. This is a + * very long-standing error, and fixing it now risks breakage of + * applications, so we live with it + */ + if (new_value.rlim_cur == RLIM_INFINITY) + goto out; + + it_prof_secs = cputime_to_secs(current->signal->it_prof_expires); + if (it_prof_secs == 0 || new_value.rlim_cur <= it_prof_secs) { + unsigned long rlim_cur = new_value.rlim_cur; + cputime_t cputime; + + cputime = secs_to_cputime(rlim_cur); + read_lock(&tasklist_lock); + spin_lock_irq(¤t->sighand->siglock); + set_process_cpu_timer(current, CPUCLOCK_PROF, &cputime, NULL); + spin_unlock_irq(¤t->sighand->siglock); + read_unlock(&tasklist_lock); + } +out: + return 0; +} + /* * It would make sense to put struct rusage in the task_struct, * except that would make the task_struct be *really big*. After