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

change semantics of ldisc ->compat_ioctl()

First of all, make it return int. Returning long when native method
had never allowed that is ridiculous and inconvenient.

More importantly, change the caller; if ldisc ->compat_ioctl() is NULL
or returns -ENOIOCTLCMD, tty_compat_ioctl() will try to feed cmd and
compat_ptr(arg) to ldisc's native ->ioctl().

That simplifies ->compat_ioctl() instances quite a bit - they only
need to deal with ioctls that are neither generic tty ones (those
would get shunted off to tty_ioctl()) nor simple compat pointer ones.

Note that something like TCFLSH won't reach ->compat_ioctl(),
even if ldisc ->ioctl() does handle it - it will be recognized
earlier and passed to tty_ioctl() (and ultimately - ldisc ->ioctl()).

For many ldiscs it means that NULL ->compat_ioctl() does the
right thing. Those where it won't serve (see e.g. n_r3964.c) are
also easily dealt with - we need to handle the numeric-argument
ioctls (calling the native instance) and, if such would exist,
the ioctls that need layout conversion, etc.

All in-tree ldiscs dealt with.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro f0193d3e 7ee32965

+36 -100
+1
drivers/bluetooth/hci_ldisc.c
··· 821 821 hci_uart_ldisc.read = hci_uart_tty_read; 822 822 hci_uart_ldisc.write = hci_uart_tty_write; 823 823 hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; 824 + hci_uart_ldisc.compat_ioctl = hci_uart_tty_ioctl; 824 825 hci_uart_ldisc.poll = hci_uart_tty_poll; 825 826 hci_uart_ldisc.receive_buf = hci_uart_tty_receive; 826 827 hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup;
+1 -1
drivers/input/serio/serport.c
··· 226 226 227 227 #ifdef CONFIG_COMPAT 228 228 #define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t) 229 - static long serport_ldisc_compat_ioctl(struct tty_struct *tty, 229 + static int serport_ldisc_compat_ioctl(struct tty_struct *tty, 230 230 struct file *file, 231 231 unsigned int cmd, unsigned long arg) 232 232 {
-21
drivers/net/hamradio/6pack.c
··· 34 34 #include <linux/ip.h> 35 35 #include <linux/tcp.h> 36 36 #include <linux/semaphore.h> 37 - #include <linux/compat.h> 38 37 #include <linux/refcount.h> 39 38 40 39 #define SIXPACK_VERSION "Revision: 0.3.0" ··· 751 752 return err; 752 753 } 753 754 754 - #ifdef CONFIG_COMPAT 755 - static long sixpack_compat_ioctl(struct tty_struct * tty, struct file * file, 756 - unsigned int cmd, unsigned long arg) 757 - { 758 - switch (cmd) { 759 - case SIOCGIFNAME: 760 - case SIOCGIFENCAP: 761 - case SIOCSIFENCAP: 762 - case SIOCSIFHWADDR: 763 - return sixpack_ioctl(tty, file, cmd, 764 - (unsigned long)compat_ptr(arg)); 765 - } 766 - 767 - return -ENOIOCTLCMD; 768 - } 769 - #endif 770 - 771 755 static struct tty_ldisc_ops sp_ldisc = { 772 756 .owner = THIS_MODULE, 773 757 .magic = TTY_LDISC_MAGIC, ··· 758 776 .open = sixpack_open, 759 777 .close = sixpack_close, 760 778 .ioctl = sixpack_ioctl, 761 - #ifdef CONFIG_COMPAT 762 - .compat_ioctl = sixpack_compat_ioctl, 763 - #endif 764 779 .receive_buf = sixpack_receive_buf, 765 780 .write_wakeup = sixpack_write_wakeup, 766 781 };
-21
drivers/net/hamradio/mkiss.c
··· 35 35 #include <linux/skbuff.h> 36 36 #include <linux/if_arp.h> 37 37 #include <linux/jiffies.h> 38 - #include <linux/compat.h> 39 38 40 39 #include <net/ax25.h> 41 40 ··· 874 875 return err; 875 876 } 876 877 877 - #ifdef CONFIG_COMPAT 878 - static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file, 879 - unsigned int cmd, unsigned long arg) 880 - { 881 - switch (cmd) { 882 - case SIOCGIFNAME: 883 - case SIOCGIFENCAP: 884 - case SIOCSIFENCAP: 885 - case SIOCSIFHWADDR: 886 - return mkiss_ioctl(tty, file, cmd, 887 - (unsigned long)compat_ptr(arg)); 888 - } 889 - 890 - return -ENOIOCTLCMD; 891 - } 892 - #endif 893 - 894 878 /* 895 879 * Handle the 'receiver data ready' interrupt. 896 880 * This function is called by the 'tty_io' module in the kernel when ··· 948 966 .open = mkiss_open, 949 967 .close = mkiss_close, 950 968 .ioctl = mkiss_ioctl, 951 - #ifdef CONFIG_COMPAT 952 - .compat_ioctl = mkiss_compat_ioctl, 953 - #endif 954 969 .receive_buf = mkiss_receive_buf, 955 970 .write_wakeup = mkiss_write_wakeup 956 971 };
-25
drivers/net/slip/slip.c
··· 79 79 #include <linux/rtnetlink.h> 80 80 #include <linux/if_arp.h> 81 81 #include <linux/if_slip.h> 82 - #include <linux/compat.h> 83 82 #include <linux/delay.h> 84 83 #include <linux/init.h> 85 84 #include <linux/slab.h> ··· 1166 1167 } 1167 1168 } 1168 1169 1169 - #ifdef CONFIG_COMPAT 1170 - static long slip_compat_ioctl(struct tty_struct *tty, struct file *file, 1171 - unsigned int cmd, unsigned long arg) 1172 - { 1173 - switch (cmd) { 1174 - case SIOCGIFNAME: 1175 - case SIOCGIFENCAP: 1176 - case SIOCSIFENCAP: 1177 - case SIOCSIFHWADDR: 1178 - case SIOCSKEEPALIVE: 1179 - case SIOCGKEEPALIVE: 1180 - case SIOCSOUTFILL: 1181 - case SIOCGOUTFILL: 1182 - return slip_ioctl(tty, file, cmd, 1183 - (unsigned long)compat_ptr(arg)); 1184 - } 1185 - 1186 - return -ENOIOCTLCMD; 1187 - } 1188 - #endif 1189 - 1190 1170 /* VSV changes start here */ 1191 1171 #ifdef CONFIG_SLIP_SMART 1192 1172 /* function do_ioctl called from net/core/dev.c ··· 1258 1280 .close = slip_close, 1259 1281 .hangup = slip_hangup, 1260 1282 .ioctl = slip_ioctl, 1261 - #ifdef CONFIG_COMPAT 1262 - .compat_ioctl = slip_compat_ioctl, 1263 - #endif 1264 1283 .receive_buf = slip_receive_buf, 1265 1284 .write_wakeup = slip_write_wakeup, 1266 1285 };
-19
drivers/net/wan/x25_asy.c
··· 33 33 #include <linux/lapb.h> 34 34 #include <linux/init.h> 35 35 #include <linux/rtnetlink.h> 36 - #include <linux/compat.h> 37 36 #include <linux/slab.h> 38 37 #include <net/x25device.h> 39 38 #include "x25_asy.h" ··· 702 703 } 703 704 } 704 705 705 - #ifdef CONFIG_COMPAT 706 - static long x25_asy_compat_ioctl(struct tty_struct *tty, struct file *file, 707 - unsigned int cmd, unsigned long arg) 708 - { 709 - switch (cmd) { 710 - case SIOCGIFNAME: 711 - case SIOCSIFHWADDR: 712 - return x25_asy_ioctl(tty, file, cmd, 713 - (unsigned long)compat_ptr(arg)); 714 - } 715 - 716 - return -ENOIOCTLCMD; 717 - } 718 - #endif 719 - 720 706 static int x25_asy_open_dev(struct net_device *dev) 721 707 { 722 708 struct x25_asy *sl = netdev_priv(dev); ··· 753 769 .open = x25_asy_open_tty, 754 770 .close = x25_asy_close_tty, 755 771 .ioctl = x25_asy_ioctl, 756 - #ifdef CONFIG_COMPAT 757 - .compat_ioctl = x25_asy_compat_ioctl, 758 - #endif 759 772 .receive_buf = x25_asy_receive_buf, 760 773 .write_wakeup = x25_asy_write_wakeup, 761 774 };
-11
drivers/tty/n_gsm.c
··· 2614 2614 } 2615 2615 } 2616 2616 2617 - #ifdef CONFIG_COMPAT 2618 - static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file, 2619 - unsigned int cmd, unsigned long arg) 2620 - { 2621 - return gsmld_ioctl(tty, file, cmd, arg); 2622 - } 2623 - #endif 2624 - 2625 2617 /* 2626 2618 * Network interface 2627 2619 * ··· 2825 2833 .flush_buffer = gsmld_flush_buffer, 2826 2834 .read = gsmld_read, 2827 2835 .write = gsmld_write, 2828 - #ifdef CONFIG_COMPAT 2829 - .compat_ioctl = gsmld_compat_ioctl, 2830 - #endif 2831 2836 .ioctl = gsmld_ioctl, 2832 2837 .poll = gsmld_poll, 2833 2838 .receive_buf = gsmld_receive_buf,
+22
drivers/tty/n_r3964.c
··· 134 134 const unsigned char *buf, size_t nr); 135 135 static int r3964_ioctl(struct tty_struct *tty, struct file *file, 136 136 unsigned int cmd, unsigned long arg); 137 + #ifdef CONFIG_COMPAT 138 + static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, 139 + unsigned int cmd, unsigned long arg); 140 + #endif 137 141 static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); 138 142 static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, 139 143 struct poll_table_struct *wait); ··· 153 149 .read = r3964_read, 154 150 .write = r3964_write, 155 151 .ioctl = r3964_ioctl, 152 + #ifdef CONFIG_COMPAT 153 + .compat_ioctl = r3964_compat_ioctl, 154 + #endif 156 155 .set_termios = r3964_set_termios, 157 156 .poll = r3964_poll, 158 157 .receive_buf = r3964_receive_buf, ··· 1216 1209 return -ENOIOCTLCMD; 1217 1210 } 1218 1211 } 1212 + 1213 + #ifdef CONFIG_COMPAT 1214 + static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, 1215 + unsigned int cmd, unsigned long arg) 1216 + { 1217 + switch (cmd) { 1218 + case R3964_ENABLE_SIGNALS: 1219 + case R3964_SETPRIORITY: 1220 + case R3964_USE_BCC: 1221 + return r3964_ioctl(tty, file, cmd, arg); 1222 + default: 1223 + return -ENOIOCTLCMD; 1224 + } 1225 + } 1226 + #endif 1219 1227 1220 1228 static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) 1221 1229 {
+3
drivers/tty/tty_io.c
··· 2824 2824 return hung_up_tty_compat_ioctl(file, cmd, arg); 2825 2825 if (ld->ops->compat_ioctl) 2826 2826 retval = ld->ops->compat_ioctl(tty, file, cmd, arg); 2827 + if (retval == -ENOIOCTLCMD && ld->ops->ioctl) 2828 + retval = ld->ops->ioctl(tty, file, 2829 + (unsigned long)compat_ptr(cmd), arg); 2827 2830 tty_ldisc_deref(ld); 2828 2831 2829 2832 return retval;
+8 -2
include/linux/tty_ldisc.h
··· 54 54 * low-level driver can "grab" an ioctl request before the line 55 55 * discpline has a chance to see it. 56 56 * 57 - * long (*compat_ioctl)(struct tty_struct * tty, struct file * file, 57 + * int (*compat_ioctl)(struct tty_struct * tty, struct file * file, 58 58 * unsigned int cmd, unsigned long arg); 59 59 * 60 60 * Process ioctl calls from 32-bit process on 64-bit system 61 + * 62 + * NOTE: only ioctls that are neither "pointer to compatible 63 + * structure" nor tty-generic. Something private that takes 64 + * an integer or a pointer to wordsize-sensitive structure 65 + * belongs here, but most of ldiscs will happily leave 66 + * it NULL. 61 67 * 62 68 * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); 63 69 * ··· 190 184 const unsigned char *buf, size_t nr); 191 185 int (*ioctl)(struct tty_struct *tty, struct file *file, 192 186 unsigned int cmd, unsigned long arg); 193 - long (*compat_ioctl)(struct tty_struct *tty, struct file *file, 187 + int (*compat_ioctl)(struct tty_struct *tty, struct file *file, 194 188 unsigned int cmd, unsigned long arg); 195 189 void (*set_termios)(struct tty_struct *tty, struct ktermios *old); 196 190 __poll_t (*poll)(struct tty_struct *, struct file *,
+1
net/nfc/nci/uart.c
··· 465 465 .receive_buf = nci_uart_tty_receive, 466 466 .write_wakeup = nci_uart_tty_wakeup, 467 467 .ioctl = nci_uart_tty_ioctl, 468 + .compat_ioctl = nci_uart_tty_ioctl, 468 469 }; 469 470 470 471 static int __init nci_uart_init(void)