diff options
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 130 | 
1 files changed, 110 insertions, 20 deletions
| diff --git a/kernel/sys.c b/kernel/sys.c index 8a94b4eabcaa..9aebc2935013 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -886,7 +886,7 @@ SYSCALL_DEFINE0(getegid)  	return from_kgid_munged(current_user_ns(), current_egid());  } -void do_sys_times(struct tms *tms) +static void do_sys_times(struct tms *tms)  {  	u64 tgutime, tgstime, cutime, cstime; @@ -912,6 +912,32 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf)  	return (long) jiffies_64_to_clock_t(get_jiffies_64());  } +#ifdef CONFIG_COMPAT +static compat_clock_t clock_t_to_compat_clock_t(clock_t x) +{ +	return compat_jiffies_to_clock_t(clock_t_to_jiffies(x)); +} + +COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf) +{ +	if (tbuf) { +		struct tms tms; +		struct compat_tms tmp; + +		do_sys_times(&tms); +		/* Convert our struct tms to the compat version. */ +		tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime); +		tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime); +		tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime); +		tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime); +		if (copy_to_user(tbuf, &tmp, sizeof(tmp))) +			return -EFAULT; +	} +	force_successful_syscall_return(); +	return compat_jiffies_to_clock_t(jiffies); +} +#endif +  /*   * This needs some heavy checking ...   * I just haven't the stomach for it. I also don't fully @@ -1306,6 +1332,54 @@ SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)  	return ret;  } +#ifdef CONFIG_COMPAT + +COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource, +		       struct compat_rlimit __user *, rlim) +{ +	struct rlimit r; +	struct compat_rlimit r32; + +	if (copy_from_user(&r32, rlim, sizeof(struct compat_rlimit))) +		return -EFAULT; + +	if (r32.rlim_cur == COMPAT_RLIM_INFINITY) +		r.rlim_cur = RLIM_INFINITY; +	else +		r.rlim_cur = r32.rlim_cur; +	if (r32.rlim_max == COMPAT_RLIM_INFINITY) +		r.rlim_max = RLIM_INFINITY; +	else +		r.rlim_max = r32.rlim_max; +	return do_prlimit(current, resource, &r, NULL); +} + +COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource, +		       struct compat_rlimit __user *, rlim) +{ +	struct rlimit r; +	int ret; + +	ret = do_prlimit(current, resource, NULL, &r); +	if (!ret) { +		struct compat_rlimit r32; +		if (r.rlim_cur > COMPAT_RLIM_INFINITY) +			r32.rlim_cur = COMPAT_RLIM_INFINITY; +		else +			r32.rlim_cur = r.rlim_cur; +		if (r.rlim_max > COMPAT_RLIM_INFINITY) +			r32.rlim_max = COMPAT_RLIM_INFINITY; +		else +			r32.rlim_max = r.rlim_max; + +		if (copy_to_user(rlim, &r32, sizeof(struct compat_rlimit))) +			return -EFAULT; +	} +	return ret; +} + +#endif +  #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT  /* @@ -1328,6 +1402,30 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,  	return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0;  } +#ifdef CONFIG_COMPAT +COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, +		       struct compat_rlimit __user *, rlim) +{ +	struct rlimit r; + +	if (resource >= RLIM_NLIMITS) +		return -EINVAL; + +	task_lock(current->group_leader); +	r = current->signal->rlim[resource]; +	task_unlock(current->group_leader); +	if (r.rlim_cur > 0x7FFFFFFF) +		r.rlim_cur = 0x7FFFFFFF; +	if (r.rlim_max > 0x7FFFFFFF) +		r.rlim_max = 0x7FFFFFFF; + +	if (put_user(r.rlim_cur, &rlim->rlim_cur) || +	    put_user(r.rlim_max, &rlim->rlim_max)) +		return -EFAULT; +	return 0; +} +#endif +  #endif  static inline bool rlim64_is_infinity(__u64 rlim64) @@ -1552,7 +1650,7 @@ static void accumulate_thread_rusage(struct task_struct *t, struct rusage *r)  	r->ru_oublock += task_io_get_oublock(t);  } -static void k_getrusage(struct task_struct *p, int who, struct rusage *r) +void getrusage(struct task_struct *p, int who, struct rusage *r)  {  	struct task_struct *t;  	unsigned long flags; @@ -1626,20 +1724,16 @@ out:  	r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */  } -int getrusage(struct task_struct *p, int who, struct rusage __user *ru) +SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru)  {  	struct rusage r; -	k_getrusage(p, who, &r); -	return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; -} - -SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru) -{  	if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN &&  	    who != RUSAGE_THREAD)  		return -EINVAL; -	return getrusage(current, who, ru); + +	getrusage(current, who, &r); +	return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;  }  #ifdef CONFIG_COMPAT @@ -1651,7 +1745,7 @@ COMPAT_SYSCALL_DEFINE2(getrusage, int, who, struct compat_rusage __user *, ru)  	    who != RUSAGE_THREAD)  		return -EINVAL; -	k_getrusage(current, who, &r); +	getrusage(current, who, &r);  	return put_compat_rusage(&r, ru);  }  #endif @@ -1802,15 +1896,11 @@ static int validate_prctl_map(struct prctl_mm_map *prctl_map)  	/*  	 * Finally, make sure the caller has the rights to -	 * change /proc/pid/exe link: only local root should +	 * change /proc/pid/exe link: only local sys admin should  	 * be allowed to.  	 */  	if (prctl_map->exe_fd != (u32)-1) { -		struct user_namespace *ns = current_user_ns(); -		const struct cred *cred = current_cred(); - -		if (!uid_eq(cred->uid, make_kuid(ns, 0)) || -		    !gid_eq(cred->gid, make_kgid(ns, 0))) +		if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN))  			goto out;  	} @@ -2266,7 +2356,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,  	case PR_GET_THP_DISABLE:  		if (arg2 || arg3 || arg4 || arg5)  			return -EINVAL; -		error = !!(me->mm->def_flags & VM_NOHUGEPAGE); +		error = !!test_bit(MMF_DISABLE_THP, &me->mm->flags);  		break;  	case PR_SET_THP_DISABLE:  		if (arg3 || arg4 || arg5) @@ -2274,9 +2364,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,  		if (down_write_killable(&me->mm->mmap_sem))  			return -EINTR;  		if (arg2) -			me->mm->def_flags |= VM_NOHUGEPAGE; +			set_bit(MMF_DISABLE_THP, &me->mm->flags);  		else -			me->mm->def_flags &= ~VM_NOHUGEPAGE; +			clear_bit(MMF_DISABLE_THP, &me->mm->flags);  		up_write(&me->mm->mmap_sem);  		break;  	case PR_MPX_ENABLE_MANAGEMENT: |