Skip to contentSkip to conversation

consolidate compat readv/writev/execve/select/nfsservctl [v2]

PATCH In review Arnd Bergmann 3 participants 8 messages Apr 17, 2004 – May 25, 2004

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

I'm following up with patches to introduce new compat_sys_* functions for the largest four ones. All of these had some bugs on most architectures, usually resulting from missing updates after the native handler was changed.

This is the second version of these cleanups that include a fix for compat_sys_select and an update from Arun Sharma to use compat_do_execve on ia64 as well.

For readv, writev, execve and select, ia64 and x86_64 use a different method from the others and I chose to use the more common one, which is a bit more code but avoids an extra copy of the user data.

The patches are also available at
http://www.arndb.de/patches/linux/2.6.6-rc1/ and apply cleanly to 2.6.6-rc1 and 2.6.5-mm6. They are tested on x86_64, ia64 and s390.

Please consider for 2.6.6-rc*-mm* and 2.6.7.

	Arnd <><
#1 lore raw

PATCH 1/4 Consolidate sys32_readv and sys32_writev

The seven implementations of this have gone out of sync and are mostly buggy. The new compat_sys_* version is based on the ppc64 implementation, which most closely resembles the code in sys_readv/sys_writev.

Tested on x86_64, ia64 and s390.

 arch/ia64/ia32/ia32_entry.S        |    4
 arch/ia64/ia32/sys_ia32.c          |   79 ---------------
 arch/mips/kernel/linux32.c         |  144 ----------------------------
 arch/mips/kernel/scall64-n32.S     |    4
 arch/mips/kernel/scall64-o32.S     |    4
 arch/parisc/kernel/sys_parisc32.c  |  143 ----------------------------
 arch/parisc/kernel/syscall_table.S |    4
 arch/ppc64/kernel/misc.S           |    4
 arch/ppc64/kernel/sys_ppc32.c      |  172 ----------------------------------
 arch/s390/kernel/compat_linux.c    |  138 ---------------------------
 arch/s390/kernel/compat_wrapper.S  |   16 +--
 arch/s390/kernel/syscalls.S        |    4
 arch/sparc64/kernel/sys_sparc32.c  |  176 -----------------------------------
 arch/sparc64/kernel/sys_sunos32.c  |    7 -
 arch/sparc64/kernel/systbls.S      |    2
 arch/x86_64/ia32/ia32entry.S       |    4
 arch/x86_64/ia32/sys_ia32.c        |   98 -------------------
 fs/compat.c                        |  186 +++++++++++++++++++++++++++++++++++++
 include/linux/compat.h             |    6 +
 19 files changed, 217 insertions(+), 978 deletions(-)

===== arch/ia64/ia32/ia32_entry.S 1.35 vs edited =====

arch/ia64/ia32/ia32_entry.S +2 -2
@@ -353,8 +353,8 @@
 	data8 sys32_select
 	data8 sys_flock
 	data8 sys32_msync
-	data8 sys32_readv	  /* 145 */
-	data8 sys32_writev
+	data8 compat_sys_readv	  /* 145 */
+	data8 compat_sys_writev
 	data8 sys_getsid
 	data8 sys_fdatasync
 	data8 sys32_sysctl

===== arch/ia64/ia32/sys_ia32.c 1.94 vs edited =====

arch/ia64/ia32/sys_ia32.c +0 -79

85 lines not on this page · raw message

===== arch/mips/kernel/linux32.c 1.22 vs edited =====

arch/mips/kernel/linux32.c +0 -144

150 lines not on this page · raw message

===== arch/mips/kernel/scall64-n32.S 1.2 vs edited =====

arch/mips/kernel/scall64-n32.S +2 -2
@@ -128,8 +128,8 @@
 	PTR	compat_sys_ioctl		/* 6015 */
 	PTR	sys_pread64
 	PTR	sys_pwrite64
-	PTR	sys32_readv
-	PTR	sys32_writev
+	PTR	compat_sys_readv
+	PTR	compat_sys_writev
 	PTR	sys_access			/* 6020 */
 	PTR	sys_pipe
 	PTR	sys32_select

===== arch/mips/kernel/scall64-o32.S 1.2 vs edited =====

arch/mips/kernel/scall64-o32.S +2 -2
@@ -400,8 +400,8 @@
 	sys	sys32_select	5
 	sys	sys_flock	2
 	sys	sys_msync	3
-	sys	sys32_readv	3			/* 4145 */
-	sys	sys32_writev	3
+	sys	compat_sys_readv	3		/* 4145 */
+	sys	compat_sys_writev	3
 	sys	sys_cacheflush	3
 	sys	sys_cachectl	3
 	sys	sys_sysmips	4

===== arch/parisc/kernel/sys_parisc32.c 1.25 vs edited =====

arch/parisc/kernel/sys_parisc32.c +0 -143

149 lines not on this page · raw message

===== arch/parisc/kernel/syscall_table.S 1.4 vs edited =====

arch/parisc/kernel/syscall_table.S +2 -2
@@ -236,8 +236,8 @@
 	ENTRY_SAME(flock)
 	ENTRY_SAME(msync)
 	/* struct iovec contains pointers */
-	ENTRY_DIFF(readv)		/* 145 */
-	ENTRY_DIFF(writev)
+	ENTRY_COMP(readv)		/* 145 */
+	ENTRY_COMP(writev)
 	ENTRY_SAME(getsid)
 	ENTRY_SAME(fdatasync)
 	/* struct __sysctl_args is a mess */

===== arch/ppc64/kernel/misc.S 1.75 vs edited =====

arch/ppc64/kernel/misc.S +2 -2
@@ -717,8 +717,8 @@
 	.llong .ppc32_select
 	.llong .sys_flock
 	.llong .sys_msync
-	.llong .sys32_readv		/* 145 */
-	.llong .sys32_writev
+	.llong .compat_sys_readv	/* 145 */
+	.llong .compat_sys_writev
 	.llong .sys32_getsid
 	.llong .sys_fdatasync
 	.llong .sys32_sysctl

===== arch/ppc64/kernel/sys_ppc32.c 1.86 vs edited =====

arch/ppc64/kernel/sys_ppc32.c +0 -172

178 lines not on this page · raw message

===== arch/s390/kernel/compat_linux.c 1.19 vs edited =====

arch/s390/kernel/compat_linux.c +0 -138

144 lines not on this page · raw message

===== arch/s390/kernel/compat_wrapper.S 1.9 vs edited =====

arch/s390/kernel/compat_wrapper.S +8 -8
@@ -663,19 +663,19 @@
 	lgfr	%r4,%r4			# int
 	jg	sys_msync		# branch to system call
 
-	.globl  sys32_readv_wrapper 
-sys32_readv_wrapper:
+	.globl  compat_sys_readv_wrapper 
+compat_sys_readv_wrapper:
 	lgfr	%r2,%r2			# int
-	llgtr	%r3,%r3			# const struct iovec_emu31 *
+	llgtr	%r3,%r3			# const struct compat_iovec *
 	llgfr	%r4,%r4			# unsigned long
-	jg	sys32_readv		# branch to system call
+	jg	compat_sys_readv	# branch to system call
 
-	.globl  sys32_writev_wrapper 
-sys32_writev_wrapper:
+	.globl  compat_sys_writev_wrapper 
+compat_sys_writev_wrapper:
 	lgfr	%r2,%r2			# int
-	llgtr	%r3,%r3			# const struct iovec_emu31 *
+	llgtr	%r3,%r3			# const struct compat_iovec *
 	llgfr	%r4,%r4			# unsigned long
-	jg	sys32_writev		# branch to system call
+	jg	compat_sys_writev	# branch to system call
 
 	.globl  sys32_getsid_wrapper 
 sys32_getsid_wrapper:

===== arch/s390/kernel/syscalls.S 1.9 vs edited =====

arch/s390/kernel/syscalls.S +2 -2
@@ -153,8 +153,8 @@
 SYSCALL(sys_select,sys_select,sys32_select_wrapper)
 SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
 SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
-SYSCALL(sys_readv,sys_readv,sys32_readv_wrapper)		/* 145 */
-SYSCALL(sys_writev,sys_writev,sys32_writev_wrapper)
+SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper)		/* 145 */
+SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper)
 SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper)
 SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper)
 SYSCALL(sys_sysctl,sys_sysctl,sys32_sysctl_wrapper)

===== arch/sparc64/kernel/sys_sparc32.c 1.95 vs edited =====

arch/sparc64/kernel/sys_sparc32.c +0 -176

182 lines not on this page · raw message

===== arch/sparc64/kernel/sys_sunos32.c 1.39 vs edited =====

arch/sparc64/kernel/sys_sunos32.c +2 -5
@@ -1203,9 +1203,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count);
-extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count);
-
 asmlinkage int sunos_read(unsigned int fd, u32 buf, u32 count)
 {
 	int ret;
@@ -1218,7 +1215,7 @@
 {
 	int ret;
 
-	ret = check_nonblock(sys32_readv(fd, vector, count), fd);
+	ret = check_nonblock(compat_sys_readv(fd, (void*)A(vector), count), fd);
 	return ret;
 }
 
@@ -1234,7 +1231,7 @@
 {
 	int ret;
 
-	ret = check_nonblock(sys32_writev(fd, vector, count), fd);
+	ret = check_nonblock(compat_sys_writev(fd, (void*)A(vector), count), fd);
 	return ret;
 }
 

===== arch/sparc64/kernel/systbls.S 1.52 vs edited =====

arch/sparc64/kernel/systbls.S +1 -1
@@ -43,7 +43,7 @@
 	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid
 /*110*/	.word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
 	.word sys_getgroups, sys32_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd
-/*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
+/*120*/	.word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
 	.word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate
 /*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64

===== arch/x86_64/ia32/ia32entry.S 1.31 vs edited =====

arch/x86_64/ia32/ia32entry.S +2 -2
@@ -450,8 +450,8 @@
 	.quad sys32_select
 	.quad sys_flock
 	.quad sys_msync
-	.quad sys32_readv		/* 145 */
-	.quad sys32_writev
+	.quad compat_sys_readv		/* 145 */
+	.quad compat_sys_writev
 	.quad sys_getsid
 	.quad sys_fdatasync
 	.quad sys32_sysctl	/* sysctl */

===== arch/x86_64/ia32/sys_ia32.c 1.57 vs edited =====

arch/x86_64/ia32/sys_ia32.c +0 -98

104 lines not on this page · raw message

===== fs/compat.c 1.22 vs edited =====

fs/compat.c +186 -0

198 lines not on this page · raw message

===== include/linux/compat.h 1.20 vs edited =====

include/linux/compat.h +6 -0
@@ -117,5 +117,11 @@
 long compat_sys_shmctl(int first, int second, void __user *uptr);
 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
 		unsigned nsems, const struct compat_timespec __user *timeout);
+
+asmlinkage ssize_t compat_sys_readv(unsigned long fd,
+		const struct compat_iovec __user *vec, unsigned long vlen);
+asmlinkage ssize_t compat_sys_writev(unsigned long fd,
+		const struct compat_iovec __user *vec, unsigned long vlen);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
#2 lore raw

PATCH 2/4 Consolidate do_execve32

In reply to Arnd Bergmann

The code for sys32_execve/do_execve32 in most of the seven versions was copied from fs/exec.c but not kept up-to-date. The new compat_do_execve() function is based on the mips code and has been resync'ed with do_execve(). IA64 changes are from Arun Sharma.

Tested on x86_64, ia64 and s390

 arch/ia64/ia32/sys_ia32.c         |   70 ++---------
 arch/mips/kernel/linux32.c        |  228 -------------------------------------
 arch/parisc/kernel/sys_parisc32.c |  187 ------------------------------
 arch/ppc64/kernel/sys_ppc32.c     |  187 ------------------------------
 arch/s390/kernel/compat_linux.c   |  187 ------------------------------
 arch/sparc64/kernel/sys_sparc32.c |  195 --------------------------------
 arch/x86_64/ia32/sys_ia32.c       |  101 ++--------------
 fs/compat.c                       |  231 ++++++++++++++++++++++++++++++++++++++
 include/linux/compat.h            |    3
 9 files changed, 275 insertions(+), 1114 deletions(-)

===== arch/ia64/ia32/sys_ia32.c 1.95 vs edited =====

arch/ia64/ia32/sys_ia32.c +14 -56
@@ -90,58 +90,17 @@
 /* XXX make per-mm: */
 static DECLARE_MUTEX(ia32_mmap_sem);
 
-static int
-nargs (unsigned int arg, char **ap)
-{
-	unsigned int addr;
-	int n, err;
-
-	if (!arg)
-		return 0;
-
-	n = 0;
-	do {
-		err = get_user(addr, (unsigned int *)A(arg));
-		if (err)
-			return err;
-		if (ap)
-			*ap++ = (char *) A(addr);
-		arg += sizeof(unsigned int);
-		n++;
-	} while (addr);
-	return n - 1;
-}
-
 asmlinkage long
-sys32_execve (char *filename, unsigned int argv, unsigned int envp,
-	      struct pt_regs *regs)
+sys32_execve (char *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp, struct pt_regs *regs)
 {
+	long error;
+	char *filename;
 	unsigned long old_map_base, old_task_size, tssd;
-	char **av, **ae;
-	int na, ne, len;
-	long r;
-
-	na = nargs(argv, NULL);
-	if (na < 0)
-		return na;
-	ne = nargs(envp, NULL);
-	if (ne < 0)
-		return ne;
-	len = (na + ne + 2) * sizeof(*av);
-	av = kmalloc(len, GFP_KERNEL);
-	if (!av)
-		return -ENOMEM;
-
-	ae = av + na + 1;
-	av[na] = NULL;
-	ae[ne] = NULL;
-
-	r = nargs(argv, av);
-	if (r < 0)
-		goto out;
-	r = nargs(envp, ae);
-	if (r < 0)
-		goto out;
+
+	filename = getname(name);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		return error;
 
 	old_map_base  = current->thread.map_base;
 	old_task_size = current->thread.task_size;
@@ -153,19 +112,18 @@
 	ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob);
 	ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);
 
-	set_fs(KERNEL_DS);
-	r = sys_execve(filename, av, ae, regs);
-	if (r < 0) {
+	error = compat_do_execve(filename, argv, envp, regs);
+	putname(filename);
+
+	if (error < 0) {
 		/* oops, execve failed, switch back to old values... */
 		ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
 		ia64_set_kr(IA64_KR_TSSD, tssd);
 		current->thread.map_base  = old_map_base;
 		current->thread.task_size = old_task_size;
-		set_fs(USER_DS);	/* establish new task-size as the address-limit */
 	}
-  out:
-	kfree(av);
-	return r;
+
+	return error;
 }
 
 int cp_compat_stat(struct kstat *stat, struct compat_stat *ubuf)

===== arch/mips/kernel/linux32.c 1.23 vs edited =====

arch/mips/kernel/linux32.c +3 -225

243 lines not on this page · raw message

===== arch/parisc/kernel/sys_parisc32.c 1.26 vs edited =====

arch/parisc/kernel/sys_parisc32.c +2 -185

199 lines not on this page · raw message

===== arch/ppc64/kernel/sys_ppc32.c 1.87 vs edited =====

arch/ppc64/kernel/sys_ppc32.c +1 -186

199 lines not on this page · raw message

===== arch/s390/kernel/compat_linux.c 1.20 vs edited =====

arch/s390/kernel/compat_linux.c +3 -184

202 lines not on this page · raw message

===== arch/sparc64/kernel/sys_sparc32.c 1.96 vs edited =====

arch/sparc64/kernel/sys_sparc32.c +3 -192

213 lines not on this page · raw message

===== arch/x86_64/ia32/sys_ia32.c 1.58 vs edited =====

arch/x86_64/ia32/sys_ia32.c +15 -86

108 lines not on this page · raw message

===== fs/compat.c 1.23 vs edited =====

fs/compat.c +231 -0

234 lines not on this page · raw message

===== include/linux/compat.h 1.21 vs edited =====

include/linux/compat.h +3 -0
@@ -123,5 +123,8 @@
 asmlinkage ssize_t compat_sys_writev(unsigned long fd,
 		const struct compat_iovec __user *vec, unsigned long vlen);
 
+int compat_do_execve(char * filename, compat_uptr_t __user *argv,
+	        compat_uptr_t __user *envp, struct pt_regs * regs);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
#3 lore raw

PATCH 3/4 Consolidate sys32_select

In reply to Arnd Bergmann

sys32_select has seven mostly but not exactly identical versions, so consolidate them as compat_sys_select. Based on the ppc64 implementation, which most closely resembles sys_select. One bug that was not caught by LTP has been fixed since the first version of this patch.

tested x86_64, ia64 and s390.

 arch/ia64/ia32/ia32_entry.S        |    2
 arch/ia64/ia32/sys_ia32.c          |  108 ---------------------
 arch/mips/kernel/linux32.c         |  161 -------------------------------
 arch/mips/kernel/scall64-n32.S     |    2
 arch/mips/kernel/scall64-o32.S     |    2
 arch/parisc/kernel/sys_parisc32.c  |  121 -----------------------
 arch/parisc/kernel/syscall_table.S |    2
 arch/ppc64/kernel/sys_ppc32.c      |  163 --------------------------------
 arch/s390/kernel/compat_linux.c    |  154 ------------------------------
 arch/s390/kernel/compat_wrapper.S  |   14 +-
 arch/s390/kernel/syscalls.S        |    2
 arch/sparc64/kernel/sys_sparc32.c  |  152 -----------------------------
 arch/sparc64/kernel/sys_sunos32.c  |    9 -
 arch/sparc64/kernel/systbls.S      |    4
 arch/x86_64/ia32/ia32entry.S       |    2
 arch/x86_64/ia32/sys_ia32.c        |  105 --------------------
 fs/compat.c                        |  188 +++++++++++++++++++++++++++++++++++++
 include/linux/compat.h             |    4
 18 files changed, 218 insertions(+), 977 deletions(-)

===== arch/ia64/ia32/ia32_entry.S 1.36 vs edited =====

arch/ia64/ia32/ia32_entry.S +1 -1
@@ -350,7 +350,7 @@
 	data8 sys_setfsgid	/* 16-bit version */
 	data8 sys_llseek	  /* 140 */
 	data8 sys32_getdents
-	data8 sys32_select
+	data8 compat_sys_select
 	data8 sys_flock
 	data8 sys32_msync
 	data8 compat_sys_readv	  /* 145 */

===== arch/ia64/ia32/sys_ia32.c 1.95 vs edited =====

arch/ia64/ia32/sys_ia32.c +2 -106

120 lines not on this page · raw message

===== arch/mips/kernel/linux32.c 1.23 vs edited =====

arch/mips/kernel/linux32.c +0 -161

167 lines not on this page · raw message

===== arch/mips/kernel/scall64-n32.S 1.3 vs edited =====

arch/mips/kernel/scall64-n32.S +1 -1
@@ -132,7 +132,7 @@
 	PTR	compat_sys_writev
 	PTR	sys_access			/* 6020 */
 	PTR	sys_pipe
-	PTR	sys32_select
+	PTR	compat_sys_select
 	PTR	sys_sched_yield
 	PTR	sys_mremap
 	PTR	sys_msync			/* 6025 */

===== arch/mips/kernel/scall64-o32.S 1.3 vs edited =====

arch/mips/kernel/scall64-o32.S +1 -1
@@ -397,7 +397,7 @@
 	sys	sys_setfsgid	1
 	sys	sys32_llseek	5			/* 4140 */
 	sys	sys32_getdents	3
-	sys	sys32_select	5
+	sys	compat_sys_select	5
 	sys	sys_flock	2
 	sys	sys_msync	3
 	sys	compat_sys_readv	3		/* 4145 */

===== arch/parisc/kernel/sys_parisc32.c 1.26 vs edited =====

arch/parisc/kernel/sys_parisc32.c +0 -121

133 lines not on this page · raw message

===== arch/parisc/kernel/syscall_table.S 1.5 vs edited =====

arch/parisc/kernel/syscall_table.S +1 -1
@@ -232,7 +232,7 @@
 	ENTRY_DIFF(getdents)
 	/* it is POSSIBLE that select will be OK because even though fd_set
 	 * contains longs, the macros and sizes are clever. */
-	ENTRY_DIFF(select)
+	ENTRY_COMP(select)
 	ENTRY_SAME(flock)
 	ENTRY_SAME(msync)
 	/* struct iovec contains pointers */

===== arch/ppc64/kernel/sys_ppc32.c 1.87 vs edited =====

arch/ppc64/kernel/sys_ppc32.c +4 -159

171 lines not on this page · raw message

===== arch/s390/kernel/compat_linux.c 1.20 vs edited =====

arch/s390/kernel/compat_linux.c +0 -154

160 lines not on this page · raw message

===== arch/s390/kernel/compat_wrapper.S 1.10 vs edited =====

arch/s390/kernel/compat_wrapper.S +7 -7
@@ -641,14 +641,14 @@
 	llgfr	%r4,%r4			# unsigned int
 	jg	sys32_getdents		# branch to system call
 
-	.globl  sys32_select_wrapper 
-sys32_select_wrapper:
+	.globl  compat_sys_select_wrapper 
+compat_sys_select_wrapper:
 	lgfr	%r2,%r2			# int
-	llgtr	%r3,%r3			# fd_set *
-	llgtr	%r4,%r4			# fd_set *
-	llgtr	%r5,%r5			# fd_set *
-	llgtr	%r6,%r6			# struct timeval_emu31 *
-	jg	sys32_select		# branch to system call
+	llgtr	%r3,%r3			# compat_fd_set *
+	llgtr	%r4,%r4			# compat_fd_set *
+	llgtr	%r5,%r5			# compat_fd_set *
+	llgtr	%r6,%r6			# struct compat_timeval *
+	jg	compat_sys_select	# branch to system call
 
 	.globl  sys32_flock_wrapper 
 sys32_flock_wrapper:

===== arch/s390/kernel/syscalls.S 1.10 vs edited =====

arch/s390/kernel/syscalls.S +1 -1
@@ -150,7 +150,7 @@
 SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper)	/* old setfsgid16 syscall */
 SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper)		/* 140 */
 SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper)
-SYSCALL(sys_select,sys_select,sys32_select_wrapper)
+SYSCALL(sys_select,sys_select,compat_sys_select_wrapper)
 SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
 SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
 SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper)		/* 145 */

===== arch/sparc64/kernel/sys_sparc32.c 1.96 vs edited =====

arch/sparc64/kernel/sys_sparc32.c +0 -152

158 lines not on this page · raw message

===== arch/sparc64/kernel/sys_sunos32.c 1.40 vs edited =====

arch/sparc64/kernel/sys_sunos32.c +3 -6
@@ -528,18 +528,15 @@
 	return ret;
 }
 
-/* SunOS mount system call emulation */
-extern asmlinkage int
-sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp);
-
 asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x)
 {
 	int ret;
 
 	/* SunOS binaries expect that select won't change the tvp contents */
-	ret = sys32_select (width, inp, outp, exp, tvp_x);
+	ret = compat_sys_select(width, compat_ptr(inp), compat_ptr(outp),
+				compat_ptr(exp), compat_ptr(tvp_x));
 	if (ret == -EINTR && tvp_x) {
-		struct compat_timeval *tvp = (struct compat_timeval *)A(tvp_x);
+		struct compat_timeval *tvp = compat_ptr(tvp_x);
 		time_t sec, usec;
 
 		__get_user(sec, &tvp->tv_sec);

===== arch/sparc64/kernel/systbls.S 1.53 vs edited =====

arch/sparc64/kernel/systbls.S +2 -2
@@ -37,7 +37,7 @@
 	.word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys32_getgroups16
 /*80*/	.word sys32_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64
 	.word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
-/*90*/	.word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid
+/*90*/	.word sys_dup2, sys_setfsuid, compat_sys_fcntl, compat_sys_select, sys_setfsgid
 	.word sys_fsync, sys_setpriority32, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
 	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid
@@ -65,7 +65,7 @@
 	.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
 /*220*/	.word compat_sys_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys_getpgid
 	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
-/*230*/	.word sys32_select, sys_time, sys_nis_syscall, sys_stime, compat_statfs64
+/*230*/	.word compat_sys_select, sys_time, sys_nis_syscall, sys_stime, compat_statfs64
 	.word compat_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep

===== arch/x86_64/ia32/ia32entry.S 1.32 vs edited =====

arch/x86_64/ia32/ia32entry.S +1 -1
@@ -447,7 +447,7 @@
 	.quad sys_setfsgid16
 	.quad sys_llseek		/* 140 */
 	.quad sys32_getdents
-	.quad sys32_select
+	.quad compat_sys_select
 	.quad sys_flock
 	.quad sys_msync
 	.quad compat_sys_readv		/* 145 */

===== arch/x86_64/ia32/sys_ia32.c 1.58 vs edited =====

arch/x86_64/ia32/sys_ia32.c +2 -103

117 lines not on this page · raw message

===== fs/compat.c 1.23 vs edited =====

fs/compat.c +188 -0

191 lines not on this page · raw message

===== include/linux/compat.h 1.21 vs edited =====

include/linux/compat.h +4 -0
@@ -126,5 +126,9 @@
 int compat_do_execve(char * filename, compat_uptr_t __user *argv,
 	        compat_uptr_t __user *envp, struct pt_regs * regs);
 
+asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
+		compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+		struct compat_timeval __user *tvp);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
Quoted 1 line
#4 lore raw

Re: [PATCH 3/4] Consolidate sys32_select

On Fri, 2004-04-16 at 18:05, Arnd Bergmann wrote:

Hi Arnd.

Quoted 7 lines

sys32_select has seven mostly but not exactly identical versions, so consolidate them as compat_sys_select. Based on the ppc64 implementation, which most closely resembles sys_select. One bug that was not caught by LTP has been fixed since the first version of this patch.

tested x86_64, ia64 and s390.

This breaks sparc64. rsync -> select() -> compat_sys_select() with a user pointer that has bit (1<<32) set.
I came to this conclusion after having added lots of debug printk's. Here's the debug printk:

compat_sys_select: before verify_area 00000001efff6468

The address printed is the address of the tvp argument.
The only weird thing with it is the (1<<32) bit, otherwise it looks like the other pointers (this doesn't happen for all select()'s but I have a testcase with rsync that reproduces it every time in exactly the same way)

When this happens __get_user() generates a pagefault and we somehow get stuck in a pagefault loop, we livelock.
(verify_area() is a noop on sparc64)

How it used to look in arch/sparc64/kernel/sys_sparc32.c

Quoted 4 lines
arch/sparc64/kernel/sys_sparc32.c +0 -4
-asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
-{
-	fd_set_bits fds;
-	struct compat_timeval *tvp = (struct compat_timeval *)AA(tvp_x);

[snip]

arch/mips/kernel/linux32.c line 607

Quoted 4 lines
arch/mips/kernel/linux32.c +0 -4
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
-			goto out_nofds;

What it looks like now:

asmlinkage long
compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
{
[snip]

		time_t sec, usec;

		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
		    || (ret = __get_user(sec, &tvp->tv_sec))
		    || (ret = __get_user(usec, &tvp->tv_usec)))
			goto out_nofds;

This combined with this comment from arch/sparc64/kernel/sys_sparc32.c

/* Things to consider: the low-level assembly stub does
srl x, 0, x for first four arguments, so if you have pointer to something in the first four arguments, just declare it as a pointer, not u32. On the other side, arguments from 5th onwards should be declared as u32 for pointers, and need AA() around each usage.

I added some simple casting to get rid of the high-bit and now rsync works just fine and we don't livelock.

Do you have any ideas how to cleanly get this working again? Masking argument five and onwards with 0xffffffffUL ?

On a related note, a quick look through fs/compat.c indicates that we have the same problem with these compat functions as well:

compat_sys_io_getevent
compat_sys_mount

Signature · 1 line
/Martin
#5 lore raw

Re: [PATCH 3/4] Consolidate sys32_select

Just fix the code to use compat_ptr(). That's what we created that macro for :-)

#6 lore raw

Re: [PATCH 3/4] Consolidate sys32_select

Quoted 2 lines · David S. Miller

Just fix the code to use compat_ptr(). That's what we created that macro for :-)

You mean in compat_sys_select() ?
compat_ptr() takes an u32 as argument, needs casting, ugly. But you want it done that way?

I see this problem when compat_sys_select() is called directly from syscall, not via sunos_select() which uses compat_ptr()

Signature · 1 line
/Martin
#7 lore raw

PATCH 4/4 Consolidate sys32_nfsservctl

In reply to Arnd Bergmann

sys32_nfsservctl is the largest remaining syscall emulation handler that can be consolidated. mips and ia64 currently don't use this at all, parisc has a simpler implementation than the one used by s390, sparc ppc and that the new compat_sys_nfsservctl is based on.

The user access checks in the code are inconsistant at least, which should be fixed here.

Compile tested only due to lack of proper test setup.

 arch/ia64/ia32/sys_ia32.c          |  170 --------------------------
 arch/parisc/kernel/sys_parisc32.c  |   88 -------------
 arch/parisc/kernel/syscall_table.S |    2
 arch/ppc64/kernel/misc.S           |    2
 arch/ppc64/kernel/sys_ppc32.c      |  239 -------------------------------------
 arch/s390/kernel/compat_linux.c    |  220 ----------------------------------
 arch/s390/kernel/compat_wrapper.S  |   10 -
 arch/s390/kernel/syscalls.S        |    2
 arch/sparc64/kernel/sys_sparc32.c  |  226 ----------------------------------
 arch/sparc64/kernel/systbls.S      |    2
 arch/x86_64/ia32/ia32entry.S       |    2
 arch/x86_64/ia32/sys_ia32.c        |  227 -----------------------------------
 fs/compat.c                        |  239 +++++++++++++++++++++++++++++++++++++
 13 files changed, 249 insertions(+), 1180 deletions(-)

===== arch/ia64/ia32/sys_ia32.c 1.96 vs edited =====

arch/ia64/ia32/sys_ia32.c +0 -170
@@ -2200,176 +2200,6 @@
 	return sys_setresgid(srgid, segid, ssgid);
 }
 
-/* Stuff for NFS server syscalls... */
-struct nfsctl_svc32 {
-	u16			svc32_port;
-	s32			svc32_nthreads;
-};
-
-struct nfsctl_client32 {
-	s8			cl32_ident[NFSCLNT_IDMAX+1];
-	s32			cl32_naddr;
-	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
-	s32			cl32_fhkeytype;
-	s32			cl32_fhkeylen;
-	u8			cl32_fhkey[NFSCLNT_KEYMAX];
-};
-
-struct nfsctl_export32 {
-	s8			ex32_client[NFSCLNT_IDMAX+1];
-	s8			ex32_path[NFS_MAXPATHLEN+1];
-	compat_dev_t	ex32_dev;
-	compat_ino_t	ex32_ino;
-	s32			ex32_flags;
-	compat_uid_t	ex32_anon_uid;
-	compat_gid_t	ex32_anon_gid;
-};
-
-struct nfsctl_arg32 {
-	s32			ca32_version;	/* safeguard */
-	union {
-		struct nfsctl_svc32	u32_svc;
-		struct nfsctl_client32	u32_client;
-		struct nfsctl_export32	u32_export;
-		u32			u32_debug;
-	} u;
-#define ca32_svc	u.u32_svc
-#define ca32_client	u.u32_client
-#define ca32_export	u.u32_export
-#define ca32_debug	u.u32_debug
-};
-
-union nfsctl_res32 {
-	struct knfs_fh		cr32_getfh;
-	u32			cr32_debug;
-};
-
-static int
-nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
-	err |= __get_user(karg->ca_svc.svc_nthreads,
-			  &arg32->ca32_svc.svc32_nthreads);
-	return err;
-}
-
-static int
-nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_client.cl_ident[0],
-			  &arg32->ca32_client.cl32_ident[0],
-			  NFSCLNT_IDMAX);
-	err |= __get_user(karg->ca_client.cl_naddr,
-			  &arg32->ca32_client.cl32_naddr);
-	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
-			  &arg32->ca32_client.cl32_addrlist[0],
-			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
-	err |= __get_user(karg->ca_client.cl_fhkeytype,
-		      &arg32->ca32_client.cl32_fhkeytype);
-	err |= __get_user(karg->ca_client.cl_fhkeylen,
-		      &arg32->ca32_client.cl32_fhkeylen);
-	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
-			  &arg32->ca32_client.cl32_fhkey[0],
-			  NFSCLNT_KEYMAX);
-	return err;
-}
-
-static int
-nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_export.ex_client[0],
-			  &arg32->ca32_export.ex32_client[0],
-			  NFSCLNT_IDMAX);
-	err |= copy_from_user(&karg->ca_export.ex_path[0],
-			  &arg32->ca32_export.ex32_path[0],
-			  NFS_MAXPATHLEN);
-	err |= __get_user(karg->ca_export.ex_dev,
-		      &arg32->ca32_export.ex32_dev);
-	err |= __get_user(karg->ca_export.ex_ino,
-		      &arg32->ca32_export.ex32_ino);
-	err |= __get_user(karg->ca_export.ex_flags,
-		      &arg32->ca32_export.ex32_flags);
-	err |= __get_user(karg->ca_export.ex_anon_uid,
-		      &arg32->ca32_export.ex32_anon_uid);
-	err |= __get_user(karg->ca_export.ex_anon_gid,
-		      &arg32->ca32_export.ex32_anon_gid);
-	return err;
-}
-
-static int
-nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
-{
-	int err;
-
-	err = copy_to_user(&res32->cr32_getfh,
-			&kres->cr_getfh,
-			sizeof(res32->cr32_getfh));
-	err |= __put_user(kres->cr_debug, &res32->cr32_debug);
-	return err;
-}
-
-int asmlinkage
-sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
-{
-	struct nfsctl_arg *karg = NULL;
-	union nfsctl_res *kres = NULL;
-	mm_segment_t oldfs;
-	int err;
-
-	karg = kmalloc(sizeof(*karg), GFP_USER);
-	if(!karg)
-		return -ENOMEM;
-	if(res32) {
-		kres = kmalloc(sizeof(*kres), GFP_USER);
-		if(!kres) {
-			kfree(karg);
-			return -ENOMEM;
-		}
-	}
-	switch(cmd) {
-	case NFSCTL_SVC:
-		err = nfs_svc32_trans(karg, arg32);
-		break;
-	case NFSCTL_ADDCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_DELCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_EXPORT:
-		err = nfs_exp32_trans(karg, arg32);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	if(err)
-		goto done;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_nfsservctl(cmd, karg, kres);
-	set_fs(oldfs);
-
-	if(!err && cmd == NFSCTL_GETFS)
-		err = nfs_getfh32_res_trans(kres, res32);
-
-done:
-	if(karg)
-		kfree(karg);
-	if(kres)
-		kfree(kres);
-	return err;
-}
-
 /* Handle adjtimex compatibility. */
 
 struct timex32 {

===== arch/parisc/kernel/sys_parisc32.c 1.27 vs edited =====

arch/parisc/kernel/sys_parisc32.c +0 -88

94 lines not on this page · raw message

===== arch/parisc/kernel/syscall_table.S 1.6 vs edited =====

arch/parisc/kernel/syscall_table.S +1 -1
@@ -266,7 +266,7 @@
 	ENTRY_SAME(ni_syscall)		/* query_module */
 	ENTRY_SAME(poll)
 	/* structs contain pointers and an in_addr... */
-	ENTRY_DIFF(nfsservctl)
+	ENTRY_COMP(nfsservctl)
 	ENTRY_SAME(setresgid)		/* 170 */
 	ENTRY_SAME(getresgid)
 	ENTRY_SAME(prctl)

===== arch/ppc64/kernel/misc.S 1.76 vs edited =====

arch/ppc64/kernel/misc.S +1 -1
@@ -740,7 +740,7 @@
 	.llong .sys_getresuid	        /* 165 */
 	.llong .sys_ni_syscall		/* old query_module syscall */
 	.llong .sys_poll
-	.llong .sys32_nfsservctl
+	.llong .compat_sys_nfsservctl
 	.llong .sys_setresgid
 	.llong .sys_getresgid	        /* 170 */
 	.llong .sys32_prctl

===== arch/ppc64/kernel/sys_ppc32.c 1.88 vs edited =====

arch/ppc64/kernel/sys_ppc32.c +0 -239

245 lines not on this page · raw message

===== arch/s390/kernel/compat_linux.c 1.21 vs edited =====

arch/s390/kernel/compat_linux.c +0 -220

226 lines not on this page · raw message

===== arch/s390/kernel/compat_wrapper.S 1.11 vs edited =====

arch/s390/kernel/compat_wrapper.S +5 -5
@@ -786,12 +786,12 @@
 	lgfr	%r4,%r4			# long 
 	jg	sys_poll		# branch to system call
 
-	.globl  sys32_nfsservctl_wrapper 
-sys32_nfsservctl_wrapper:
+	.globl  compat_sys_nfsservctl_wrapper 
+compat_sys_nfsservctl_wrapper:
 	lgfr	%r2,%r2			# int 
-	llgtr	%r3,%r3			# struct nfsctl_arg_emu31 * 
-	llgtr	%r4,%r4			# union nfsctl_res_emu31 * 
-	jg	sys32_nfsservctl	# branch to system call
+	llgtr	%r3,%r3			# struct compat_nfsctl_arg* 
+	llgtr	%r4,%r4			# union compat_nfsctl_res* 
+	jg	compat_sys_nfsservctl	# branch to system call
 
 	.globl  sys32_setresgid16_wrapper 
 sys32_setresgid16_wrapper:

===== arch/s390/kernel/syscalls.S 1.11 vs edited =====

arch/s390/kernel/syscalls.S +1 -1
@@ -177,7 +177,7 @@
 NI_SYSCALL							/* for vm86 */
 NI_SYSCALL							/* old sys_query_module */
 SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
-SYSCALL(sys_nfsservctl,sys_nfsservctl,sys32_nfsservctl_wrapper)
+SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper)
 SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper)	/* 170 old setresgid16 syscall */
 SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper)	/* old getresgid16 syscall */
 SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)

===== arch/sparc64/kernel/sys_sparc32.c 1.97 vs edited =====

arch/sparc64/kernel/sys_sparc32.c +0 -226

232 lines not on this page · raw message

===== arch/sparc64/kernel/systbls.S 1.54 vs edited =====

arch/sparc64/kernel/systbls.S +1 -1
@@ -69,7 +69,7 @@
 	.word compat_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
-/*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+/*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, compat_sys_nfsservctl
 	.word sys_ni_syscall, compat_clock_settime, compat_clock_gettime, compat_clock_getres, compat_clock_nanosleep
 /*260*/	.word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, compat_timer_settime, compat_timer_gettime, sys_timer_getoverrun
 	.word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy

===== arch/x86_64/ia32/ia32entry.S 1.33 vs edited =====

arch/x86_64/ia32/ia32entry.S +1 -1
@@ -474,7 +474,7 @@
 	.quad sys32_vm86_warning	/* vm86 */ 
 	.quad quiet_ni_syscall	/* query_module */
 	.quad sys_poll
-	.quad sys32_nfsservctl
+	.quad compat_sys_nfsservctl
 	.quad sys_setresgid16	/* 170 */
 	.quad sys_getresgid16
 	.quad sys_prctl

===== arch/x86_64/ia32/sys_ia32.c 1.59 vs edited =====

arch/x86_64/ia32/sys_ia32.c +0 -227

233 lines not on this page · raw message

===== fs/compat.c 1.24 vs edited =====

fs/compat.c +239 -0

242 lines not on this page · raw message