2697 lines · 62.9 KB · C
RawDownload
		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 * understand sessions/pgrp etc. Let somebody who does explain it. * * OK, I think I have the protection semantics right.... this is really * only important on a multi-user system anyway, to make sure one user * can't send a signal to a process owned by another.  -TYT, 12/12/91 * * !PF_FORKNOEXEC check to conform completely to POSIX. */SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid){	struct task_struct *p;	struct task_struct *group_leader = current->group_leader;	struct pid *pgrp;	int err; 	if (!pid)		pid = task_pid_vnr(group_leader);	if (!pgid)		pgid = pid;	if (pgid < 0)		return -EINVAL;	rcu_read_lock(); 	/* From this point forward we keep holding onto the tasklist lock	 * so that our parent does not change from under us. -DaveM	 */	write_lock_irq(&tasklist_lock); 	err = -ESRCH;	p = find_task_by_vpid(pid);	if (!p)		goto out; 	err = -EINVAL;	if (!thread_group_leader(p))		goto out; 	if (same_thread_group(p->real_parent, group_leader)) {		err = -EPERM;		if (task_session(p) != task_session(group_leader))			goto out;		err = -EACCES;		if (!(p->flags & PF_FORKNOEXEC))			goto out;	} else {		err = -ESRCH;		if (p != group_leader)			goto out;	} 	err = -EPERM;	if (p->signal->leader)		goto out; 	pgrp = task_pid(p);	if (pgid != pid) {		struct task_struct *g; 		pgrp = find_vpid(pgid);		g = pid_task(pgrp, PIDTYPE_PGID);		if (!g || task_session(g) != task_session(group_leader))			goto out;	} 	err = security_task_setpgid(p, pgid);	if (err)		goto out; 	if (task_pgrp(p) != pgrp)		change_pid(p, PIDTYPE_PGID, pgrp); 	err = 0;out:	/* All paths lead to here, thus we are safe. -DaveM */	write_unlock_irq(&tasklist_lock);	rcu_read_unlock();	return err;} static int do_getpgid(pid_t pid){	struct task_struct *p;	struct pid *grp;	int retval; 	rcu_read_lock();	if (!pid)		grp = task_pgrp(current);	else {		retval = -ESRCH;		p = find_task_by_vpid(pid);		if (!p)			goto out;		grp = task_pgrp(p);		if (!grp)			goto out; 		retval = security_task_getpgid(p);		if (retval)			goto out;	}	retval = pid_vnr(grp);out:	rcu_read_unlock();	return retval;} SYSCALL_DEFINE1(getpgid, pid_t, pid){	return do_getpgid(pid);} #ifdef __ARCH_WANT_SYS_GETPGRP SYSCALL_DEFINE0(getpgrp){	return do_getpgid(0);} #endif SYSCALL_DEFINE1(getsid, pid_t, pid){	struct task_struct *p;	struct pid *sid;	int retval; 	rcu_read_lock();	if (!pid)		sid = task_session(current);	else {		retval = -ESRCH;		p = find_task_by_vpid(pid);		if (!p)			goto out;		sid = task_session(p);		if (!sid)			goto out; 		retval = security_task_getsid(p);		if (retval)			goto out;	}	retval = pid_vnr(sid);out:	rcu_read_unlock();	return retval;} static void set_special_pids(struct pid *pid){	struct task_struct *curr = current->group_leader; 	if (task_session(curr) != pid)		change_pid(curr, PIDTYPE_SID, pid); 	if (task_pgrp(curr) != pid)		change_pid(curr, PIDTYPE_PGID, pid);} int ksys_setsid(void){	struct task_struct *group_leader = current->group_leader;	struct pid *sid = task_pid(group_leader);	pid_t session = pid_vnr(sid);	int err = -EPERM; 	write_lock_irq(&tasklist_lock);	/* Fail if I am already a session leader */	if (group_leader->signal->leader)		goto out; 	/* Fail if a process group id already exists that equals the	 * proposed session id.	 */	if (pid_task(sid, PIDTYPE_PGID))		goto out; 	group_leader->signal->leader = 1;	set_special_pids(sid); 	proc_clear_tty(group_leader); 	err = session;out:	write_unlock_irq(&tasklist_lock);	if (err > 0) {		proc_sid_connector(group_leader);		sched_autogroup_create_attach(group_leader);	}	return err;} SYSCALL_DEFINE0(setsid){	return ksys_setsid();} DECLARE_RWSEM(uts_sem); #ifdef COMPAT_UTS_MACHINE#define override_architecture(name) \	(personality(current->personality) == PER_LINUX32 && \	 copy_to_user(name->machine, COMPAT_UTS_MACHINE, \		      sizeof(COMPAT_UTS_MACHINE)))#else#define override_architecture(name)	0#endif /* * Work around broken programs that cannot handle "Linux 3.0". * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 * And we map 4.x and later versions to 2.6.60+x, so 4.0/5.0/6.0/... would be * 2.6.60. */static int override_release(char __user *release, size_t len){	int ret = 0; 	if (current->personality & UNAME26) {		const char *rest = UTS_RELEASE;		char buf[65] = { 0 };		int ndots = 0;		unsigned v;		size_t copy; 		while (*rest) {			if (*rest == '.' && ++ndots >= 3)				break;			if (!isdigit(*rest) && *rest != '.')				break;			rest++;		}		v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 60;		copy = clamp_t(size_t, len, 1, sizeof(buf));		copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);		ret = copy_to_user(release, buf, copy + 1);	}	return ret;} SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name){	struct new_utsname tmp; 	down_read(&uts_sem);	memcpy(&tmp, utsname(), sizeof(tmp));	up_read(&uts_sem);	if (copy_to_user(name, &tmp, sizeof(tmp)))		return -EFAULT; 	if (override_release(name->release, sizeof(name->release)))		return -EFAULT;	if (override_architecture(name))		return -EFAULT;	return 0;} #ifdef __ARCH_WANT_SYS_OLD_UNAME/* * Old cruft */SYSCALL_DEFINE1(uname, struct old_utsname __user *, name){	struct old_utsname tmp; 	if (!name)		return -EFAULT; 	down_read(&uts_sem);	memcpy(&tmp, utsname(), sizeof(tmp));	up_read(&uts_sem);	if (copy_to_user(name, &tmp, sizeof(tmp)))		return -EFAULT; 	if (override_release(name->release, sizeof(name->release)))		return -EFAULT;	if (override_architecture(name))		return -EFAULT;	return 0;} SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name){	struct oldold_utsname tmp; 	if (!name)		return -EFAULT; 	memset(&tmp, 0, sizeof(tmp)); 	down_read(&uts_sem);	memcpy(&tmp.sysname, &utsname()->sysname, __OLD_UTS_LEN);	memcpy(&tmp.nodename, &utsname()->nodename, __OLD_UTS_LEN);	memcpy(&tmp.release, &utsname()->release, __OLD_UTS_LEN);	memcpy(&tmp.version, &utsname()->version, __OLD_UTS_LEN);	memcpy(&tmp.machine, &utsname()->machine, __OLD_UTS_LEN);	up_read(&uts_sem);	if (copy_to_user(name, &tmp, sizeof(tmp)))		return -EFAULT; 	if (override_architecture(name))		return -EFAULT;	if (override_release(name->release, sizeof(name->release)))		return -EFAULT;	return 0;}#endif SYSCALL_DEFINE2(sethostname, char __user *, name, int, len){	int errno;	char tmp[__NEW_UTS_LEN]; 	if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))		return -EPERM; 	if (len < 0 || len > __NEW_UTS_LEN)		return -EINVAL;	errno = -EFAULT;	if (!copy_from_user(tmp, name, len)) {		struct new_utsname *u; 		down_write(&uts_sem);		u = utsname();		memcpy(u->nodename, tmp, len);		memset(u->nodename + len, 0, sizeof(u->nodename) - len);		errno = 0;		uts_proc_notify(UTS_PROC_HOSTNAME);		up_write(&uts_sem);	}	return errno;} #ifdef __ARCH_WANT_SYS_GETHOSTNAME SYSCALL_DEFINE2(gethostname, char __user *, name, int, len){	int i;	struct new_utsname *u;	char tmp[__NEW_UTS_LEN + 1]; 	if (len < 0)		return -EINVAL;	down_read(&uts_sem);	u = utsname();	i = 1 + strlen(u->nodename);	if (i > len)		i = len;	memcpy(tmp, u->nodename, i);	up_read(&uts_sem);	if (copy_to_user(name, tmp, i))		return -EFAULT;	return 0;} #endif /* * Only setdomainname; getdomainname can be implemented by calling * uname() */SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len){	int errno;	char tmp[__NEW_UTS_LEN]; 	if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))		return -EPERM;	if (len < 0 || len > __NEW_UTS_LEN)		return -EINVAL; 	errno = -EFAULT;	if (!copy_from_user(tmp, name, len)) {		struct new_utsname *u; 		down_write(&uts_sem);		u = utsname();		memcpy(u->domainname, tmp, len);		memset(u->domainname + len, 0, sizeof(u->domainname) - len);		errno = 0;		uts_proc_notify(UTS_PROC_DOMAINNAME);		up_write(&uts_sem);	}	return errno;} SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim){	struct rlimit value;	int ret; 	ret = do_prlimit(current, resource, NULL, &value);	if (!ret)		ret = copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; 	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 /* *	Back compatibility for getrlimit. Needed for some apps. */SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,		struct rlimit __user *, rlim){	struct rlimit x;	if (resource >= RLIM_NLIMITS)		return -EINVAL; 	resource = array_index_nospec(resource, RLIM_NLIMITS);	task_lock(current->group_leader);	x = current->signal->rlim[resource];	task_unlock(current->group_leader);	if (x.rlim_cur > 0x7FFFFFFF)		x.rlim_cur = 0x7FFFFFFF;	if (x.rlim_max > 0x7FFFFFFF)		x.rlim_max = 0x7FFFFFFF;	return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0;} #ifdef CONFIG_COMPATCOMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,		       struct compat_rlimit __user *, rlim){	struct rlimit r; 	if (resource >= RLIM_NLIMITS)		return -EINVAL; 	resource = array_index_nospec(resource, RLIM_NLIMITS);	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) ||

Lines 1001–1500 of 2697. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t