aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ppp
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-12-01 13:46:15 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-12-01 13:46:15 -0800
commit0da522107e5d9c000a4871d52e570912aa1225a2 (patch)
tree104de063105f1a3ea80f55721c92d1b3d9073af9 /drivers/net/ppp
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace (diff)
parentscsi: sd: enable compat ioctls for sed-opal (diff)
downloadlinux-dev-0da522107e5d9c000a4871d52e570912aa1225a2.tar.xz
linux-dev-0da522107e5d9c000a4871d52e570912aa1225a2.zip
Merge tag 'compat-ioctl-5.5' of git://git.kernel.org:/pub/scm/linux/kernel/git/arnd/playground
Pull removal of most of fs/compat_ioctl.c from Arnd Bergmann: "As part of the cleanup of some remaining y2038 issues, I came to fs/compat_ioctl.c, which still has a couple of commands that need support for time64_t. In completely unrelated work, I spent time on cleaning up parts of this file in the past, moving things out into drivers instead. After Al Viro reviewed an earlier version of this series and did a lot more of that cleanup, I decided to try to completely eliminate the rest of it and move it all into drivers. This series incorporates some of Al's work and many patches of my own, but in the end stops short of actually removing the last part, which is the scsi ioctl handlers. I have patches for those as well, but they need more testing or possibly a rewrite" * tag 'compat-ioctl-5.5' of git://git.kernel.org:/pub/scm/linux/kernel/git/arnd/playground: (42 commits) scsi: sd: enable compat ioctls for sed-opal pktcdvd: add compat_ioctl handler compat_ioctl: move SG_GET_REQUEST_TABLE handling compat_ioctl: ppp: move simple commands into ppp_generic.c compat_ioctl: handle PPPIOCGIDLE for 64-bit time_t compat_ioctl: move PPPIOCSCOMPRESS to ppp_generic compat_ioctl: unify copy-in of ppp filters tty: handle compat PPP ioctls compat_ioctl: move SIOCOUTQ out of compat_ioctl.c compat_ioctl: handle SIOCOUTQNSD af_unix: add compat_ioctl support compat_ioctl: reimplement SG_IO handling compat_ioctl: move WDIOC handling into wdt drivers fs: compat_ioctl: move FITRIM emulation into file systems gfs2: add compat_ioctl support compat_ioctl: remove unused convert_in_user macro compat_ioctl: remove last RAID handling code compat_ioctl: remove /dev/raw ioctl translation compat_ioctl: remove PCI ioctl translation compat_ioctl: remove joystick ioctl translation ...
Diffstat (limited to 'drivers/net/ppp')
-rw-r--r--drivers/net/ppp/ppp_generic.c245
1 files changed, 164 insertions, 81 deletions
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 61824bbb5588..0cb1c2d0a8bc 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -270,7 +270,7 @@ static void ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb);
static struct sk_buff *ppp_mp_reconstruct(struct ppp *ppp);
static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb);
#endif /* CONFIG_PPP_MULTILINK */
-static int ppp_set_compress(struct ppp *ppp, unsigned long arg);
+static int ppp_set_compress(struct ppp *ppp, struct ppp_option_data *data);
static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound);
static void ppp_ccp_closed(struct ppp *ppp);
static struct compressor *find_compressor(int type);
@@ -554,36 +554,66 @@ static __poll_t ppp_poll(struct file *file, poll_table *wait)
}
#ifdef CONFIG_PPP_FILTER
-static int get_filter(void __user *arg, struct sock_filter **p)
+static struct bpf_prog *get_filter(struct sock_fprog *uprog)
+{
+ struct sock_fprog_kern fprog;
+ struct bpf_prog *res = NULL;
+ int err;
+
+ if (!uprog->len)
+ return NULL;
+
+ /* uprog->len is unsigned short, so no overflow here */
+ fprog.len = uprog->len * sizeof(struct sock_filter);
+ fprog.filter = memdup_user(uprog->filter, fprog.len);
+ if (IS_ERR(fprog.filter))
+ return ERR_CAST(fprog.filter);
+
+ err = bpf_prog_create(&res, &fprog);
+ kfree(fprog.filter);
+
+ return err ? ERR_PTR(err) : res;
+}
+
+static struct bpf_prog *ppp_get_filter(struct sock_fprog __user *p)
{
struct sock_fprog uprog;
- struct sock_filter *code = NULL;
- int len;
- if (copy_from_user(&uprog, arg, sizeof(uprog)))
- return -EFAULT;
+ if (copy_from_user(&uprog, p, sizeof(struct sock_fprog)))
+ return ERR_PTR(-EFAULT);
+ return get_filter(&uprog);
+}
- if (!uprog.len) {
- *p = NULL;
- return 0;
- }
+#ifdef CONFIG_COMPAT
+struct sock_fprog32 {
+ unsigned short len;
+ compat_caddr_t filter;
+};
- len = uprog.len * sizeof(struct sock_filter);
- code = memdup_user(uprog.filter, len);
- if (IS_ERR(code))
- return PTR_ERR(code);
+#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
+
+static struct bpf_prog *compat_ppp_get_filter(struct sock_fprog32 __user *p)
+{
+ struct sock_fprog32 uprog32;
+ struct sock_fprog uprog;
- *p = code;
- return uprog.len;
+ if (copy_from_user(&uprog32, p, sizeof(struct sock_fprog32)))
+ return ERR_PTR(-EFAULT);
+ uprog.len = uprog32.len;
+ uprog.filter = compat_ptr(uprog32.filter);
+ return get_filter(&uprog);
}
-#endif /* CONFIG_PPP_FILTER */
+#endif
+#endif
static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ppp_file *pf;
struct ppp *ppp;
int err = -EFAULT, val, val2, i;
- struct ppp_idle idle;
+ struct ppp_idle32 idle32;
+ struct ppp_idle64 idle64;
struct npioctl npi;
int unit, cflags;
struct slcompress *vj;
@@ -679,9 +709,14 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
case PPPIOCSCOMPRESS:
- err = ppp_set_compress(ppp, arg);
+ {
+ struct ppp_option_data data;
+ if (copy_from_user(&data, argp, sizeof(data)))
+ err = -EFAULT;
+ else
+ err = ppp_set_compress(ppp, &data);
break;
-
+ }
case PPPIOCGUNIT:
if (put_user(ppp->file.index, p))
break;
@@ -701,10 +736,18 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = 0;
break;
- case PPPIOCGIDLE:
- idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
- idle.recv_idle = (jiffies - ppp->last_recv) / HZ;
- if (copy_to_user(argp, &idle, sizeof(idle)))
+ case PPPIOCGIDLE32:
+ idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ idle32.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ if (copy_to_user(argp, &idle32, sizeof(idle32)))
+ break;
+ err = 0;
+ break;
+
+ case PPPIOCGIDLE64:
+ idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ idle64.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ if (copy_to_user(argp, &idle64, sizeof(idle64)))
break;
err = 0;
break;
@@ -753,55 +796,25 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_PPP_FILTER
case PPPIOCSPASS:
- {
- struct sock_filter *code;
-
- err = get_filter(argp, &code);
- if (err >= 0) {
- struct bpf_prog *pass_filter = NULL;
- struct sock_fprog_kern fprog = {
- .len = err,
- .filter = code,
- };
-
- err = 0;
- if (fprog.filter)
- err = bpf_prog_create(&pass_filter, &fprog);
- if (!err) {
- ppp_lock(ppp);
- if (ppp->pass_filter)
- bpf_prog_destroy(ppp->pass_filter);
- ppp->pass_filter = pass_filter;
- ppp_unlock(ppp);
- }
- kfree(code);
- }
- break;
- }
case PPPIOCSACTIVE:
{
- struct sock_filter *code;
-
- err = get_filter(argp, &code);
- if (err >= 0) {
- struct bpf_prog *active_filter = NULL;
- struct sock_fprog_kern fprog = {
- .len = err,
- .filter = code,
- };
+ struct bpf_prog *filter = ppp_get_filter(argp);
+ struct bpf_prog **which;
- err = 0;
- if (fprog.filter)
- err = bpf_prog_create(&active_filter, &fprog);
- if (!err) {
- ppp_lock(ppp);
- if (ppp->active_filter)
- bpf_prog_destroy(ppp->active_filter);
- ppp->active_filter = active_filter;
- ppp_unlock(ppp);
- }
- kfree(code);
+ if (IS_ERR(filter)) {
+ err = PTR_ERR(filter);
+ break;
}
+ if (cmd == PPPIOCSPASS)
+ which = &ppp->pass_filter;
+ else
+ which = &ppp->active_filter;
+ ppp_lock(ppp);
+ if (*which)
+ bpf_prog_destroy(*which);
+ *which = filter;
+ ppp_unlock(ppp);
+ err = 0;
break;
}
#endif /* CONFIG_PPP_FILTER */
@@ -827,6 +840,77 @@ out:
return err;
}
+#ifdef CONFIG_COMPAT
+struct ppp_option_data32 {
+ compat_uptr_t ptr;
+ u32 length;
+ compat_int_t transmit;
+};
+#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32)
+
+static long ppp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct ppp_file *pf;
+ int err = -ENOIOCTLCMD;
+ void __user *argp = (void __user *)arg;
+
+ mutex_lock(&ppp_mutex);
+
+ pf = file->private_data;
+ if (pf && pf->kind == INTERFACE) {
+ struct ppp *ppp = PF_TO_PPP(pf);
+ switch (cmd) {
+#ifdef CONFIG_PPP_FILTER
+ case PPPIOCSPASS32:
+ case PPPIOCSACTIVE32:
+ {
+ struct bpf_prog *filter = compat_ppp_get_filter(argp);
+ struct bpf_prog **which;
+
+ if (IS_ERR(filter)) {
+ err = PTR_ERR(filter);
+ break;
+ }
+ if (cmd == PPPIOCSPASS32)
+ which = &ppp->pass_filter;
+ else
+ which = &ppp->active_filter;
+ ppp_lock(ppp);
+ if (*which)
+ bpf_prog_destroy(*which);
+ *which = filter;
+ ppp_unlock(ppp);
+ err = 0;
+ break;
+ }
+#endif /* CONFIG_PPP_FILTER */
+ case PPPIOCSCOMPRESS32:
+ {
+ struct ppp_option_data32 data32;
+ if (copy_from_user(&data32, argp, sizeof(data32))) {
+ err = -EFAULT;
+ } else {
+ struct ppp_option_data data = {
+ .ptr = compat_ptr(data32.ptr),
+ .length = data32.length,
+ .transmit = data32.transmit
+ };
+ err = ppp_set_compress(ppp, &data);
+ }
+ break;
+ }
+ }
+ }
+ mutex_unlock(&ppp_mutex);
+
+ /* all other commands have compatible arguments */
+ if (err == -ENOIOCTLCMD)
+ err = ppp_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+
+ return err;
+}
+#endif
+
static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -895,6 +979,9 @@ static const struct file_operations ppp_device_fops = {
.write = ppp_write,
.poll = ppp_poll,
.unlocked_ioctl = ppp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ppp_compat_ioctl,
+#endif
.open = ppp_open,
.release = ppp_release,
.llseek = noop_llseek,
@@ -2734,24 +2821,20 @@ ppp_output_wakeup(struct ppp_channel *chan)
/* Process the PPPIOCSCOMPRESS ioctl. */
static int
-ppp_set_compress(struct ppp *ppp, unsigned long arg)
+ppp_set_compress(struct ppp *ppp, struct ppp_option_data *data)
{
- int err;
+ int err = -EFAULT;
struct compressor *cp, *ocomp;
- struct ppp_option_data data;
void *state, *ostate;
unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];
- err = -EFAULT;
- if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
- goto out;
- if (data.length > CCP_MAX_OPTION_LENGTH)
+ if (data->length > CCP_MAX_OPTION_LENGTH)
goto out;
- if (copy_from_user(ccp_option, (void __user *) data.ptr, data.length))
+ if (copy_from_user(ccp_option, data->ptr, data->length))
goto out;
err = -EINVAL;
- if (data.length < 2 || ccp_option[1] < 2 || ccp_option[1] > data.length)
+ if (data->length < 2 || ccp_option[1] < 2 || ccp_option[1] > data->length)
goto out;
cp = try_then_request_module(
@@ -2761,8 +2844,8 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
goto out;
err = -ENOBUFS;
- if (data.transmit) {
- state = cp->comp_alloc(ccp_option, data.length);
+ if (data->transmit) {
+ state = cp->comp_alloc(ccp_option, data->length);
if (state) {
ppp_xmit_lock(ppp);
ppp->xstate &= ~SC_COMP_RUN;
@@ -2780,7 +2863,7 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
module_put(cp->owner);
} else {
- state = cp->decomp_alloc(ccp_option, data.length);
+ state = cp->decomp_alloc(ccp_option, data->length);
if (state) {
ppp_recv_lock(ppp);
ppp->rstate &= ~SC_DECOMP_RUN;