Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: convert termios.h to the asm-generic version

This patch turned out more controversial than expected
and may get dropped in the future. I'm including it
for reference anyway.

The user_termio_to_kernel_termios and kernel_termios_to_user_termio
functions on x86 are lacking error checking from get_user and
are not portable to big-endian systems, so the asm-generic
header has to differ in this regard.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
LKML-Reference: <cover.1245354003.git.arnd@arndb.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>

authored by

Arnd Bergmann and committed by
H. Peter Anvin
69d5ffda 06f5013a

+63 -23
+63 -23
arch/x86/include/asm/termios.h
··· 1 - #ifndef _ASM_X86_TERMIOS_H 2 - #define _ASM_X86_TERMIOS_H 1 + #ifndef _ASM_GENERIC_TERMIOS_H 2 + #define _ASM_GENERIC_TERMIOS_H 3 + /* 4 + * Most architectures have straight copies of the x86 code, with 5 + * varying levels of bug fixes on top. Usually it's a good idea 6 + * to use this generic version instead, but be careful to avoid 7 + * ABI changes. 8 + * New architectures should not provide their own version. 9 + */ 3 10 4 11 #include <asm/termbits.h> 5 12 #include <asm/ioctls.h> ··· 61 54 /* 62 55 * Translate a "termio" structure into a "termios". Ugh. 63 56 */ 64 - #define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ 65 - unsigned short __tmp; \ 66 - get_user(__tmp,&(termio)->x); \ 67 - *(unsigned short *) &(termios)->x = __tmp; \ 68 - } 69 - 70 57 static inline int user_termio_to_kernel_termios(struct ktermios *termios, 71 - struct termio __user *termio) 58 + const struct termio __user *termio) 72 59 { 73 - SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); 74 - SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); 75 - SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); 76 - SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); 77 - get_user(termios->c_line, &termio->c_line); 78 - return copy_from_user(termios->c_cc, termio->c_cc, NCC); 60 + unsigned short tmp; 61 + 62 + if (get_user(tmp, &termio->c_iflag) < 0) 63 + goto fault; 64 + termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp; 65 + 66 + if (get_user(tmp, &termio->c_oflag) < 0) 67 + goto fault; 68 + termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp; 69 + 70 + if (get_user(tmp, &termio->c_cflag) < 0) 71 + goto fault; 72 + termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp; 73 + 74 + if (get_user(tmp, &termio->c_lflag) < 0) 75 + goto fault; 76 + termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp; 77 + 78 + if (get_user(termios->c_line, &termio->c_line) < 0) 79 + goto fault; 80 + 81 + if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0) 82 + goto fault; 83 + 84 + return 0; 85 + 86 + fault: 87 + return -EFAULT; 79 88 } 80 89 81 90 /* 82 91 * Translate a "termios" structure into a "termio". Ugh. 83 92 */ 84 93 static inline int kernel_termios_to_user_termio(struct termio __user *termio, 85 - struct ktermios *termios) 94 + struct ktermios *termios) 86 95 { 87 - put_user((termios)->c_iflag, &(termio)->c_iflag); 88 - put_user((termios)->c_oflag, &(termio)->c_oflag); 89 - put_user((termios)->c_cflag, &(termio)->c_cflag); 90 - put_user((termios)->c_lflag, &(termio)->c_lflag); 91 - put_user((termios)->c_line, &(termio)->c_line); 92 - return copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); 96 + if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || 97 + put_user(termios->c_oflag, &termio->c_oflag) < 0 || 98 + put_user(termios->c_cflag, &termio->c_cflag) < 0 || 99 + put_user(termios->c_lflag, &termio->c_lflag) < 0 || 100 + put_user(termios->c_line, &termio->c_line) < 0 || 101 + copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0) 102 + return -EFAULT; 103 + 104 + return 0; 93 105 } 94 106 107 + #ifdef TCGETS2 95 108 static inline int user_termios_to_kernel_termios(struct ktermios *k, 96 109 struct termios2 __user *u) 97 110 { ··· 135 108 { 136 109 return copy_to_user(u, k, sizeof(struct termios)); 137 110 } 111 + #else /* TCGETS2 */ 112 + static inline int user_termios_to_kernel_termios(struct ktermios *k, 113 + struct termios __user *u) 114 + { 115 + return copy_from_user(k, u, sizeof(struct termios)); 116 + } 117 + 118 + static inline int kernel_termios_to_user_termios(struct termios __user *u, 119 + struct ktermios *k) 120 + { 121 + return copy_to_user(u, k, sizeof(struct termios)); 122 + } 123 + #endif /* TCGETS2 */ 138 124 139 125 #endif /* __KERNEL__ */ 140 126 141 - #endif /* _ASM_X86_TERMIOS_H */ 127 + #endif /* _ASM_GENERIC_TERMIOS_H */