compat_ioctl: pppoe: fix PPPOEIOCSFWD handling [Linux 4.9.189]

This Linux kernel change "compat_ioctl: pppoe: fix PPPOEIOCSFWD handling" is included in the Linux 4.9.189 release. This change is authored by Arnd Bergmann <arnd [at] arndb.de> on Tue Jul 30 21:25:20 2019 +0200. The commit for this change in Linux stable tree is 00a8794 (patch) which is from upstream commit 055d882. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 055d882.

compat_ioctl: pppoe: fix PPPOEIOCSFWD handling

[ Upstream commit 055d88242a6046a1ceac3167290f054c72571cd9 ]

Support for handling the PPPOEIOCSFWD ioctl in compat mode was added in
linux-2.5.69 along with hundreds of other commands, but was always broken
sincen only the structure is compatible, but the command number is not,
due to the size being sizeof(size_t), or at first sizeof(sizeof((struct
sockaddr_pppox)), which is different on 64-bit architectures.

Guillaume Nault adds:

  And the implementation was broken until 2016 (see 29e73269aa4d ("pppoe:
  fix reference counting in PPPoE proxy")), and nobody ever noticed. I
  should probably have removed this ioctl entirely instead of fixing it.
  Clearly, it has never been used.

Fix it by adding a compat_ioctl handler for all pppoe variants that
translates the command number and then calls the regular ioctl function.

All other ioctl commands handled by pppoe are compatible between 32-bit
and 64-bit, and require compat_ptr() conversion.

This should apply to all stable kernels.

Acked-by: Guillaume Nault <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

There are 28 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/ppp/pppoe.c  |  3 +++
 drivers/net/ppp/pppox.c  | 13 +++++++++++++
 drivers/net/ppp/pptp.c   |  3 +++
 fs/compat_ioctl.c        |  3 ---
 include/linux/if_pppox.h |  3 +++
 net/l2tp/l2tp_ppp.c      |  3 +++
 6 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 8c93ed5..fa8f7c4 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -1134,6 +1134,9 @@ static int pppoe_seq_open(struct inode *inode, struct file *file)
    .recvmsg    = pppoe_recvmsg,
    .mmap       = sock_no_mmap,
    .ioctl      = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+   .compat_ioctl   = pppox_compat_ioctl,
+#endif
 };

 static const struct pppox_proto pppoe_proto = {
diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c
index b9c8be6..50856f9 100644
--- a/drivers/net/ppp/pppox.c
+++ b/drivers/net/ppp/pppox.c
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/compat.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/net.h>
@@ -103,6 +104,18 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)

 EXPORT_SYMBOL(pppox_ioctl);

+#ifdef CONFIG_COMPAT
+int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+   if (cmd == PPPOEIOCSFWD32)
+       cmd = PPPOEIOCSFWD;
+
+   return pppox_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+}
+
+EXPORT_SYMBOL(pppox_compat_ioctl);
+#endif
+
 static int pppox_create(struct net *net, struct socket *sock, int protocol,
            int kern)
 {
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 5a8befd..fa14a67 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -638,6 +638,9 @@ static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
    .recvmsg    = sock_no_recvmsg,
    .mmap       = sock_no_mmap,
    .ioctl      = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+   .compat_ioctl = pppox_compat_ioctl,
+#endif
 };

 static const struct pppox_proto pppox_pptp_proto = {
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 93c8e4a..4b7da44 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1038,9 +1038,6 @@ static int compat_ioctl_preallocate(struct file *file,
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
 COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
 /* Big A */
 /* sparc only */
 /* Big Q for sound/OSS */
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index ba7a9b0..24e9b36 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -84,6 +84,9 @@ struct pppox_proto {
 extern void unregister_pppox_proto(int proto_num);
 extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
 extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+extern int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+
+#define PPPOEIOCSFWD32    _IOW(0xB1 ,0, compat_size_t)

 /* PPPoX socket states */
 enum {
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 9b214f3..16b63e6 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1790,6 +1790,9 @@ static __net_exit void pppol2tp_exit_net(struct net *net)
    .recvmsg    = pppol2tp_recvmsg,
    .mmap       = sock_no_mmap,
    .ioctl      = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+   .compat_ioctl = pppox_compat_ioctl,
+#endif
 };

 static const struct pppox_proto pppol2tp_proto = {

Leave a Reply

Your email address will not be published. Required fields are marked *