PPPIOCSPASS and PPPIOCSACTIVE are implemented in ppp_generic and isdn_ppp,
but the latter one doesn't work for compat mode in general, so we can
move these two into the generic code.

Again, the best implementation I could come up with was to merge
the compat handling into the regular ppp_ioctl() function and
treating all ioctl commands as compatible.

Signed-off-by: Arnd Bergmann <a...@arndb.de>
---
 drivers/net/ppp/ppp_generic.c | 39 ++++++++++++++++++++++++++++++-----
 fs/compat_ioctl.c             | 37 ---------------------------------
 2 files changed, 34 insertions(+), 42 deletions(-)

diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 8d211c9c2e4e..b8a867fdd5ad 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -22,6 +22,7 @@
  * ==FILEVERSION 20041108==
  */
 
+#include <linux/compat.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched/signal.h>
@@ -567,14 +568,36 @@ struct ppp_option_data32 {
 #endif
 
 #ifdef CONFIG_PPP_FILTER
-static int get_filter(void __user *arg, struct sock_filter **p)
+#ifdef CONFIG_COMPAT
+struct sock_fprog32 {
+       unsigned short  len;
+       compat_caddr_t  filter;
+};
+#define PPPIOCSPASS32  _IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32        _IOW('t', 70, struct sock_fprog32)
+#endif
+
+static int get_filter(void __user *arg, struct sock_filter **p, bool compat)
 {
        struct sock_fprog uprog;
        struct sock_filter *code = NULL;
        int len;
 
-       if (copy_from_user(&uprog, arg, sizeof(uprog)))
-               return -EFAULT;
+#ifdef CONFIG_COMPAT
+       if (compat) {
+               struct sock_fprog32 uprog32;
+
+               if (copy_from_user(&uprog32, arg, sizeof(uprog32)))
+                       return -EFAULT;
+
+               uprog.len = uprog32.len;
+               uprog.filter = compat_ptr(uprog32.filter);
+       } else
+#endif
+       {
+               if (copy_from_user(&uprog, arg, sizeof(uprog)))
+                       return -EFAULT;
+       }
 
        if (!uprog.len) {
                *p = NULL;
@@ -772,10 +795,13 @@ static long ppp_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
 
 #ifdef CONFIG_PPP_FILTER
        case PPPIOCSPASS:
+#ifdef CONFIG_COMPAT
+       case PPPIOCSPASS32:
+#endif
        {
                struct sock_filter *code;
 
-               err = get_filter(argp, &code);
+               err = get_filter(argp, &code, cmd != PPPIOCSPASS);
                if (err >= 0) {
                        struct bpf_prog *pass_filter = NULL;
                        struct sock_fprog_kern fprog = {
@@ -798,10 +824,13 @@ static long ppp_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
                break;
        }
        case PPPIOCSACTIVE:
+#ifdef CONFIG_COMPAT
+       case PPPIOCSACTIVE32:
+#endif
        {
                struct sock_filter *code;
 
-               err = get_filter(argp, &code);
+               err = get_filter(argp, &code, cmd != PPPIOCSACTIVE);
                if (err >= 0) {
                        struct bpf_prog *active_filter = NULL;
                        struct sock_fprog_kern fprog = {
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a7cea8f9c771..d507b7189958 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -271,40 +271,6 @@ static int sg_grt_trans(struct file *file,
 }
 #endif /* CONFIG_BLOCK */
 
-struct sock_fprog32 {
-       unsigned short  len;
-       compat_caddr_t  filter;
-};
-
-#define PPPIOCSPASS32  _IOW('t', 71, struct sock_fprog32)
-#define PPPIOCSACTIVE32        _IOW('t', 70, struct sock_fprog32)
-
-static int ppp_sock_fprog_ioctl_trans(struct file *file,
-               unsigned int cmd, struct sock_fprog32 __user *u_fprog32)
-{
-       struct sock_fprog __user *u_fprog64 = 
compat_alloc_user_space(sizeof(struct sock_fprog));
-       void __user *fptr64;
-       u32 fptr32;
-       u16 flen;
-
-       if (get_user(flen, &u_fprog32->len) ||
-           get_user(fptr32, &u_fprog32->filter))
-               return -EFAULT;
-
-       fptr64 = compat_ptr(fptr32);
-
-       if (put_user(flen, &u_fprog64->len) ||
-           put_user(fptr64, &u_fprog64->filter))
-               return -EFAULT;
-
-       if (cmd == PPPIOCSPASS32)
-               cmd = PPPIOCSPASS;
-       else
-               cmd = PPPIOCSACTIVE;
-
-       return do_ioctl(file, cmd, (unsigned long) u_fprog64);
-}
-
 struct ppp_idle32 {
        compat_time_t xmit_idle;
        compat_time_t recv_idle;
@@ -874,9 +840,6 @@ static long do_ioctl_trans(unsigned int cmd,
        switch (cmd) {
        case PPPIOCGIDLE32:
                return ppp_gidle(file, cmd, argp);
-       case PPPIOCSPASS32:
-       case PPPIOCSACTIVE32:
-               return ppp_sock_fprog_ioctl_trans(file, cmd, argp);
 #ifdef CONFIG_BLOCK
        case SG_IO:
                return sg_ioctl_trans(file, cmd, argp);
-- 
2.20.0

Reply via email to