Commit e8eaa326 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] sparse: sock_fprog sanitized

sock_fprog instances that had kernel pointer in ->filter (both of them -
in ppp_generic and isdn_ppp) replaced with explicit pairs len + kernel
pointer.  Copying of userland sock_fprog (with its __user ->filter)
cleaned up and sanitized.

Trivial annotation done in the rest of ->ioctl() in ppp_generic and
isdn_ppp.
parent 95a02b3c
...@@ -320,8 +320,8 @@ isdn_ppp_open(int min, struct file *file) ...@@ -320,8 +320,8 @@ isdn_ppp_open(int min, struct file *file)
is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
#endif #endif
#ifdef CONFIG_IPPP_FILTER #ifdef CONFIG_IPPP_FILTER
is->pass_filter.filter = NULL; is->pass_filter = NULL;
is->active_filter.filter = NULL; is->active_filter = NULL;
#endif #endif
is->state = IPPP_OPEN; is->state = IPPP_OPEN;
...@@ -378,13 +378,13 @@ isdn_ppp_release(int min, struct file *file) ...@@ -378,13 +378,13 @@ isdn_ppp_release(int min, struct file *file)
is->slcomp = NULL; is->slcomp = NULL;
#endif #endif
#ifdef CONFIG_IPPP_FILTER #ifdef CONFIG_IPPP_FILTER
if (is->pass_filter.filter) { if (is->pass_filter) {
kfree(is->pass_filter.filter); kfree(is->pass_filter);
is->pass_filter.filter = NULL; is->pass_filter = NULL;
} }
if (is->active_filter.filter) { if (is->active_filter) {
kfree(is->active_filter.filter); kfree(is->active_filter);
is->active_filter.filter = NULL; is->active_filter = NULL;
} }
#endif #endif
...@@ -414,11 +414,11 @@ isdn_ppp_release(int min, struct file *file) ...@@ -414,11 +414,11 @@ isdn_ppp_release(int min, struct file *file)
* get_arg .. ioctl helper * get_arg .. ioctl helper
*/ */
static int static int
get_arg(void *b, void *val, int len) get_arg(void __user *b, void *val, int len)
{ {
if (len <= 0) if (len <= 0)
len = sizeof(void *); len = sizeof(void *);
if (copy_from_user((void *) val, b, len)) if (copy_from_user(val, b, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -427,15 +427,50 @@ get_arg(void *b, void *val, int len) ...@@ -427,15 +427,50 @@ get_arg(void *b, void *val, int len)
* set arg .. ioctl helper * set arg .. ioctl helper
*/ */
static int static int
set_arg(void *b, void *val,int len) set_arg(void __user *b, void *val,int len)
{ {
if(len <= 0) if(len <= 0)
len = sizeof(void *); len = sizeof(void *);
if (copy_to_user(b, (void *) val, len)) if (copy_to_user(b, val, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
static int get_filter(void __user *arg, struct sock_filter **p)
{
struct sock_fprog uprog;
struct sock_filter *code = NULL;
int len, err;
if (copy_from_user(&uprog, arg, sizeof(uprog)))
return -EFAULT;
if (!uprog.len) {
*p = NULL;
return 0;
}
/* uprog.len is unsigned short, so no overflow here */
len = uprog.len * sizeof(struct sock_filter);
code = kmalloc(len, GFP_KERNEL);
if (code == NULL)
return -ENOMEM;
if (copy_from_user(code, uprog.filter, len)) {
kfree(code);
return -EFAULT;
}
err = sk_chk_filter(code, uprog.len);
if (err) {
kfree(code);
return err;
}
*p = code;
return uprog.len;
}
/* /*
* ippp device ioctl * ippp device ioctl
*/ */
...@@ -447,6 +482,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -447,6 +482,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
struct ippp_struct *is; struct ippp_struct *is;
isdn_net_local *lp; isdn_net_local *lp;
struct isdn_ppp_comp_data data; struct isdn_ppp_comp_data data;
void __user *argp = (void __user *)arg;
is = (struct ippp_struct *) file->private_data; is = (struct ippp_struct *) file->private_data;
lp = is->lp; lp = is->lp;
...@@ -462,7 +498,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -462,7 +498,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if (!(is->state & IPPP_CONNECT)) if (!(is->state & IPPP_CONNECT))
return -EINVAL; return -EINVAL;
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) if ((r = get_arg(argp, &val, sizeof(val) )))
return r; return r;
printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
(int) min, (int) is->unit, (int) val); (int) min, (int) is->unit, (int) val);
...@@ -472,30 +508,30 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -472,30 +508,30 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
#endif #endif
break; break;
case PPPIOCGUNIT: /* get ppp/isdn unit number */ case PPPIOCGUNIT: /* get ppp/isdn unit number */
if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) ))) if ((r = set_arg(argp, &is->unit, sizeof(is->unit) )))
return r; return r;
break; break;
case PPPIOCGIFNAME: case PPPIOCGIFNAME:
if(!lp) if(!lp)
return -EINVAL; return -EINVAL;
if ((r = set_arg((void *) arg, lp->name, strlen(lp->name)))) if ((r = set_arg(argp, lp->name, strlen(lp->name))))
return r; return r;
break; break;
case PPPIOCGMPFLAGS: /* get configuration flags */ case PPPIOCGMPFLAGS: /* get configuration flags */
if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) ))) if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg) )))
return r; return r;
break; break;
case PPPIOCSMPFLAGS: /* set configuration flags */ case PPPIOCSMPFLAGS: /* set configuration flags */
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) if ((r = get_arg(argp, &val, sizeof(val) )))
return r; return r;
is->mpppcfg = val; is->mpppcfg = val;
break; break;
case PPPIOCGFLAGS: /* get configuration flags */ case PPPIOCGFLAGS: /* get configuration flags */
if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) ))) if ((r = set_arg(argp, &is->pppcfg,sizeof(is->pppcfg) )))
return r; return r;
break; break;
case PPPIOCSFLAGS: /* set configuration flags */ case PPPIOCSFLAGS: /* set configuration flags */
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) { if ((r = get_arg(argp, &val, sizeof(val) ))) {
return r; return r;
} }
if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
...@@ -512,12 +548,12 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -512,12 +548,12 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
if (lp) { if (lp) {
struct ppp_idle pidle; struct ppp_idle pidle;
pidle.xmit_idle = pidle.recv_idle = lp->huptimer; pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle)))) if ((r = set_arg(argp, &pidle,sizeof(struct ppp_idle))))
return r; return r;
} }
break; break;
case PPPIOCSMRU: /* set receive unit size for PPP */ case PPPIOCSMRU: /* set receive unit size for PPP */
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) if ((r = get_arg(argp, &val, sizeof(val) )))
return r; return r;
is->mru = val; is->mru = val;
break; break;
...@@ -526,7 +562,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -526,7 +562,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCSMPMTU: case PPPIOCSMPMTU:
break; break;
case PPPIOCSMAXCID: /* set the maximum compression slot id */ case PPPIOCSMAXCID: /* set the maximum compression slot id */
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) if ((r = get_arg(argp, &val, sizeof(val) )))
return r; return r;
val++; val++;
if (is->maxcid != val) { if (is->maxcid != val) {
...@@ -549,11 +585,11 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -549,11 +585,11 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
} }
break; break;
case PPPIOCGDEBUG: case PPPIOCGDEBUG:
if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) ))) if ((r = set_arg(argp, &is->debug, sizeof(is->debug) )))
return r; return r;
break; break;
case PPPIOCSDEBUG: case PPPIOCSDEBUG:
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) if ((r = get_arg(argp, &val, sizeof(val) )))
return r; return r;
is->debug = val; is->debug = val;
break; break;
...@@ -568,12 +604,12 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -568,12 +604,12 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
protos[j] |= (0x1<<i); protos[j] |= (0x1<<i);
ipc = ipc->next; ipc = ipc->next;
} }
if ((r = set_arg((void *) arg,protos,8*sizeof(long) ))) if ((r = set_arg(argp,protos,8*sizeof(long) )))
return r; return r;
} }
break; break;
case PPPIOCSCOMPRESSOR: case PPPIOCSCOMPRESSOR:
if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data)))) if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
return r; return r;
return isdn_ppp_set_compressor(is, &data); return isdn_ppp_set_compressor(is, &data);
case PPPIOCGCALLINFO: case PPPIOCGCALLINFO:
...@@ -594,38 +630,29 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) ...@@ -594,38 +630,29 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
if(lp->flags & ISDN_NET_CALLBACK) if(lp->flags & ISDN_NET_CALLBACK)
pci.calltype |= CALLTYPE_CALLBACK; pci.calltype |= CALLTYPE_CALLBACK;
} }
return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo)); return set_arg(argp,&pci,sizeof(struct pppcallinfo));
} }
#ifdef CONFIG_IPPP_FILTER #ifdef CONFIG_IPPP_FILTER
case PPPIOCSPASS: case PPPIOCSPASS:
{
struct sock_filter *code;
int len = get_filter(argp, &code);
if (len < 0)
return len;
kfree(is->pass_filter);
is->pass_filter = code;
is->pass_len = len;
break;
}
case PPPIOCSACTIVE: case PPPIOCSACTIVE:
{ {
struct sock_fprog uprog, *filtp; struct sock_filter *code;
struct sock_filter *code = NULL; int len = get_filter(argp, &code);
int len, err; if (len < 0)
return len;
if (copy_from_user(&uprog, (void *) arg, sizeof(uprog))) kfree(is->active_filter);
return -EFAULT; is->active_filter = code;
if (uprog.len > 0) { is->active_len = len;
len = uprog.len * sizeof(struct sock_filter);
code = kmalloc(len, GFP_KERNEL);
if (code == NULL)
return -ENOMEM;
if (copy_from_user(code, uprog.filter, len)) {
kfree(code);
return -EFAULT;
}
err = sk_chk_filter(code, uprog.len);
if (err) {
kfree(code);
return err;
}
}
filtp = (cmd == PPPIOCSPASS) ? &is->pass_filter : &is->active_filter;
if (filtp->filter)
kfree(filtp->filter);
filtp->filter = code;
filtp->len = uprog.len;
break; break;
} }
#endif /* CONFIG_IPPP_FILTER */ #endif /* CONFIG_IPPP_FILTER */
...@@ -733,7 +760,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) ...@@ -733,7 +760,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
*/ */
int int
isdn_ppp_read(int min, struct file *file, char *buf, int count) isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
{ {
struct ippp_struct *is; struct ippp_struct *is;
struct ippp_buf_queue *b; struct ippp_buf_queue *b;
...@@ -746,7 +773,7 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count) ...@@ -746,7 +773,7 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
if (!(is->state & IPPP_OPEN)) if (!(is->state & IPPP_OPEN))
return 0; return 0;
if ((r = verify_area(VERIFY_WRITE, (void *) buf, count))) if ((r = verify_area(VERIFY_WRITE, buf, count)))
return r; return r;
spin_lock_irqsave(&is->buflock, flags); spin_lock_irqsave(&is->buflock, flags);
...@@ -773,7 +800,7 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count) ...@@ -773,7 +800,7 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
*/ */
int int
isdn_ppp_write(int min, struct file *file, const char *buf, int count) isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
{ {
isdn_net_local *lp; isdn_net_local *lp;
struct ippp_struct *is; struct ippp_struct *is;
...@@ -1128,17 +1155,16 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff ...@@ -1128,17 +1155,16 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
*p = 0; /* indicate inbound in DLT_LINUX_SLL */ *p = 0; /* indicate inbound in DLT_LINUX_SLL */
} }
if (is->pass_filter.filter if (is->pass_filter
&& sk_run_filter(skb, is->pass_filter.filter, && sk_run_filter(skb, is->pass_filter, is->pass_len) == 0) {
is->pass_filter.len) == 0) {
if (is->debug & 0x2) if (is->debug & 0x2)
printk(KERN_DEBUG "IPPP: inbound frame filtered.\n"); printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
if (!(is->active_filter.filter if (!(is->active_filter
&& sk_run_filter(skb, is->active_filter.filter, && sk_run_filter(skb, is->active_filter,
is->active_filter.len) == 0)) { is->active_len) == 0)) {
if (is->debug & 0x2) if (is->debug & 0x2)
printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n"); printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
lp->huptimer = 0; lp->huptimer = 0;
...@@ -1276,17 +1302,16 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -1276,17 +1302,16 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
*p = htons(proto); *p = htons(proto);
} }
if (ipt->pass_filter.filter if (ipt->pass_filter
&& sk_run_filter(skb, ipt->pass_filter.filter, && sk_run_filter(skb, ipt->pass_filter, ipt->pass_len) == 0) {
ipt->pass_filter.len) == 0) {
if (ipt->debug & 0x4) if (ipt->debug & 0x4)
printk(KERN_DEBUG "IPPP: outbound frame filtered.\n"); printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
kfree_skb(skb); kfree_skb(skb);
goto unlock; goto unlock;
} }
if (!(ipt->active_filter.filter if (!(ipt->active_filter
&& sk_run_filter(skb, ipt->active_filter.filter, && sk_run_filter(skb, ipt->active_filter,
ipt->active_filter.len) == 0)) { ipt->active_len) == 0)) {
if (ipt->debug & 0x4) if (ipt->debug & 0x4)
printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n"); printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
lp->huptimer = 0; lp->huptimer = 0;
...@@ -1475,12 +1500,10 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) ...@@ -1475,12 +1500,10 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
*p = htons(proto); *p = htons(proto);
} }
drop |= is->pass_filter.filter drop |= is->pass_filter
&& sk_run_filter(skb, is->pass_filter.filter, && sk_run_filter(skb, is->pass_filter, is->pass_len) == 0;
is->pass_filter.len) == 0; drop |= is->active_filter
drop |= is->active_filter.filter && sk_run_filter(skb, is->active_filter, is->active_len) == 0;
&& sk_run_filter(skb, is->active_filter.filter,
is->active_filter.len) == 0;
skb_push(skb, IPPP_MAX_HEADER - 4); skb_push(skb, IPPP_MAX_HEADER - 4);
return drop; return drop;
...@@ -1969,12 +1992,11 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit) ...@@ -1969,12 +1992,11 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
static int static int
isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
{ {
struct ppp_stats *res, struct ppp_stats __user *res = ifr->ifr_data;
t; struct ppp_stats t;
isdn_net_local *lp = (isdn_net_local *) dev->priv; isdn_net_local *lp = (isdn_net_local *) dev->priv;
int err; int err;
res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats)); err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats));
if (err) if (err)
...@@ -2004,7 +2026,8 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) ...@@ -2004,7 +2026,8 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
} }
#endif #endif
} }
if( copy_to_user(res, &t, sizeof(struct ppp_stats))) return -EFAULT; if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
return -EFAULT;
return 0; return 0;
} }
...@@ -2012,7 +2035,6 @@ int ...@@ -2012,7 +2035,6 @@ int
isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
int error=0; int error=0;
char *r;
int len; int len;
isdn_net_local *lp = (isdn_net_local *) dev->priv; isdn_net_local *lp = (isdn_net_local *) dev->priv;
...@@ -2023,9 +2045,8 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -2023,9 +2045,8 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) { switch (cmd) {
#define PPP_VERSION "2.3.7" #define PPP_VERSION "2.3.7"
case SIOCGPPPVER: case SIOCGPPPVER:
r = (char *) ifr->ifr_ifru.ifru_data;
len = strlen(PPP_VERSION) + 1; len = strlen(PPP_VERSION) + 1;
if (copy_to_user(r, PPP_VERSION, len)) if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
error = -EFAULT; error = -EFAULT;
break; break;
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */ #include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
#include <linux/isdn_ppp.h> /* for isdn_ppp info */ #include <linux/isdn_ppp.h> /* for isdn_ppp info */
extern int isdn_ppp_read(int, struct file *, char *, int); extern int isdn_ppp_read(int, struct file *, char __user *, int);
extern int isdn_ppp_write(int, struct file *, const char *, int); extern int isdn_ppp_write(int, struct file *, const char __user *, int);
extern int isdn_ppp_open(int, struct file *); extern int isdn_ppp_open(int, struct file *);
extern int isdn_ppp_init(void); extern int isdn_ppp_init(void);
extern void isdn_ppp_cleanup(void); extern void isdn_ppp_cleanup(void);
......
...@@ -129,8 +129,9 @@ struct ppp { ...@@ -129,8 +129,9 @@ struct ppp {
#endif /* CONFIG_PPP_MULTILINK */ #endif /* CONFIG_PPP_MULTILINK */
struct net_device_stats stats; /* statistics */ struct net_device_stats stats; /* statistics */
#ifdef CONFIG_PPP_FILTER #ifdef CONFIG_PPP_FILTER
struct sock_fprog pass_filter; /* filter for packets to pass */ struct sock_filter *pass_filter; /* filter for packets to pass */
struct sock_fprog active_filter;/* filter for pkts to reset idle */ struct sock_filter *active_filter;/* filter for pkts to reset idle */
unsigned pass_len, active_len;
#endif /* CONFIG_PPP_FILTER */ #endif /* CONFIG_PPP_FILTER */
}; };
...@@ -493,6 +494,43 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait) ...@@ -493,6 +494,43 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait)
return mask; return mask;
} }
static int get_filter(void __user *arg, struct sock_filter **p)
{
struct sock_fprog uprog;
struct sock_filter *code = NULL;
int len, err;
if (copy_from_user(&uprog, arg, sizeof(uprog)))
return -EFAULT;
if (uprog.len > BPF_MAXINSNS)
return -EINVAL;
if (!uprog.len) {
*p = NULL;
return 0;
}
len = uprog.len * sizeof(struct sock_filter);
code = kmalloc(len, GFP_KERNEL);
if (code == NULL)
return -ENOMEM;
if (copy_from_user(code, uprog.filter, len)) {
kfree(code);
return -EFAULT;
}
err = sk_chk_filter(code, uprog.len);
if (err) {
kfree(code);
return err;
}
*p = code;
return uprog.len;
}
static int ppp_ioctl(struct inode *inode, struct file *file, static int ppp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
...@@ -503,6 +541,8 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -503,6 +541,8 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
struct npioctl npi; struct npioctl npi;
int unit, cflags; int unit, cflags;
struct slcompress *vj; struct slcompress *vj;
void __user *argp = (void __user *)arg;
int __user *p = argp;
if (pf == 0) if (pf == 0)
return ppp_unattached_ioctl(pf, file, cmd, arg); return ppp_unattached_ioctl(pf, file, cmd, arg);
...@@ -540,7 +580,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -540,7 +580,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
case PPPIOCCONNECT: case PPPIOCCONNECT:
if (get_user(unit, (int *) arg)) if (get_user(unit, p))
break; break;
err = ppp_connect_channel(pch, unit); err = ppp_connect_channel(pch, unit);
break; break;
...@@ -569,14 +609,14 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -569,14 +609,14 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
ppp = PF_TO_PPP(pf); ppp = PF_TO_PPP(pf);
switch (cmd) { switch (cmd) {
case PPPIOCSMRU: case PPPIOCSMRU:
if (get_user(val, (int *) arg)) if (get_user(val, p))
break; break;
ppp->mru = val; ppp->mru = val;
err = 0; err = 0;
break; break;
case PPPIOCSFLAGS: case PPPIOCSFLAGS:
if (get_user(val, (int *) arg)) if (get_user(val, p))
break; break;
ppp_lock(ppp); ppp_lock(ppp);
cflags = ppp->flags & ~val; cflags = ppp->flags & ~val;
...@@ -589,7 +629,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -589,7 +629,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
case PPPIOCGFLAGS: case PPPIOCGFLAGS:
val = ppp->flags | ppp->xstate | ppp->rstate; val = ppp->flags | ppp->xstate | ppp->rstate;
if (put_user(val, (int *) arg)) if (put_user(val, p))
break; break;
err = 0; err = 0;
break; break;
...@@ -599,20 +639,20 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -599,20 +639,20 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
break; break;
case PPPIOCGUNIT: case PPPIOCGUNIT:
if (put_user(ppp->file.index, (int *) arg)) if (put_user(ppp->file.index, p))
break; break;
err = 0; err = 0;
break; break;
case PPPIOCSDEBUG: case PPPIOCSDEBUG:
if (get_user(val, (int *) arg)) if (get_user(val, p))
break; break;
ppp->debug = val; ppp->debug = val;
err = 0; err = 0;
break; break;
case PPPIOCGDEBUG: case PPPIOCGDEBUG:
if (put_user(ppp->debug, (int *) arg)) if (put_user(ppp->debug, p))
break; break;
err = 0; err = 0;
break; break;
...@@ -620,13 +660,13 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -620,13 +660,13 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
case PPPIOCGIDLE: case PPPIOCGIDLE:
idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ; idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
idle.recv_idle = (jiffies - ppp->last_recv) / HZ; idle.recv_idle = (jiffies - ppp->last_recv) / HZ;
if (copy_to_user((void __user *) arg, &idle, sizeof(idle))) if (copy_to_user(argp, &idle, sizeof(idle)))
break; break;
err = 0; err = 0;
break; break;
case PPPIOCSMAXCID: case PPPIOCSMAXCID:
if (get_user(val, (int *) arg)) if (get_user(val, p))
break; break;
val2 = 15; val2 = 15;
if ((val >> 16) != 0) { if ((val >> 16) != 0) {
...@@ -649,7 +689,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -649,7 +689,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
case PPPIOCGNPMODE: case PPPIOCGNPMODE:
case PPPIOCSNPMODE: case PPPIOCSNPMODE:
if (copy_from_user(&npi, (void __user *) arg, sizeof(npi))) if (copy_from_user(&npi, argp, sizeof(npi)))
break; break;
err = proto_to_npindex(npi.protocol); err = proto_to_npindex(npi.protocol);
if (err < 0) if (err < 0)
...@@ -658,7 +698,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -658,7 +698,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
if (cmd == PPPIOCGNPMODE) { if (cmd == PPPIOCGNPMODE) {
err = -EFAULT; err = -EFAULT;
npi.mode = ppp->npmode[i]; npi.mode = ppp->npmode[i];
if (copy_to_user((void __user *) arg, &npi, sizeof(npi))) if (copy_to_user(argp, &npi, sizeof(npi)))
break; break;
} else { } else {
ppp->npmode[i] = npi.mode; ppp->npmode[i] = npi.mode;
...@@ -670,49 +710,38 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ...@@ -670,49 +710,38 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
#ifdef CONFIG_PPP_FILTER #ifdef CONFIG_PPP_FILTER
case PPPIOCSPASS: case PPPIOCSPASS:
{
struct sock_filter *code;
err = get_filter(argp, &code);
if (err >= 0) {
ppp_lock(ppp);
kfree(ppp->pass_filter);
ppp->pass_filter = code;
ppp->pass_len = err;
ppp_unlock(ppp);
err = 0;
}
break;
}
case PPPIOCSACTIVE: case PPPIOCSACTIVE:
{ {
struct sock_fprog uprog, *filtp; struct sock_filter *code;
struct sock_filter *code = NULL; err = get_filter(argp, &code);
int len; if (err >= 0) {
ppp_lock(ppp);
if (copy_from_user(&uprog, (void __user *) arg, sizeof(uprog))) kfree(ppp->active_filter);
break; ppp->active_filter = code;
err = -EINVAL; ppp->active_len = err;
if (uprog.len > BPF_MAXINSNS) ppp_unlock(ppp);
break; err = 0;
err = -ENOMEM;
if (uprog.len > 0) {
len = uprog.len * sizeof(struct sock_filter);
code = kmalloc(len, GFP_KERNEL);
if (code == NULL)
break;
err = -EFAULT;
if (copy_from_user(code, (void __user *) uprog.filter, len)) {
kfree(code);
break;
}
err = sk_chk_filter(code, uprog.len);
if (err) {
kfree(code);
break;
}
} }
filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter;
ppp_lock(ppp);
if (filtp->filter)
kfree(filtp->filter);
filtp->filter = code;
filtp->len = uprog.len;
ppp_unlock(ppp);
err = 0;
break; break;
} }
#endif /* CONFIG_PPP_FILTER */ #endif /* CONFIG_PPP_FILTER */
#ifdef CONFIG_PPP_MULTILINK #ifdef CONFIG_PPP_MULTILINK
case PPPIOCSMRRU: case PPPIOCSMRRU:
if (get_user(val, (int *) arg)) if (get_user(val, p))
break; break;
ppp_recv_lock(ppp); ppp_recv_lock(ppp);
ppp->mrru = val; ppp->mrru = val;
...@@ -734,11 +763,12 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, ...@@ -734,11 +763,12 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
int unit, err = -EFAULT; int unit, err = -EFAULT;
struct ppp *ppp; struct ppp *ppp;
struct channel *chan; struct channel *chan;
int __user *p = (int __user *)arg;
switch (cmd) { switch (cmd) {
case PPPIOCNEWUNIT: case PPPIOCNEWUNIT:
/* Create a new ppp unit */ /* Create a new ppp unit */
if (get_user(unit, (int *) arg)) if (get_user(unit, p))
break; break;
ppp = ppp_create_interface(unit, &err); ppp = ppp_create_interface(unit, &err);
if (ppp == 0) if (ppp == 0)
...@@ -746,14 +776,14 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, ...@@ -746,14 +776,14 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
file->private_data = &ppp->file; file->private_data = &ppp->file;
ppp->owner = file; ppp->owner = file;
err = -EFAULT; err = -EFAULT;
if (put_user(ppp->file.index, (int *) arg)) if (put_user(ppp->file.index, p))
break; break;
err = 0; err = 0;
break; break;
case PPPIOCATTACH: case PPPIOCATTACH:
/* Attach to an existing ppp unit */ /* Attach to an existing ppp unit */
if (get_user(unit, (int *) arg)) if (get_user(unit, p))
break; break;
down(&all_ppp_sem); down(&all_ppp_sem);
err = -ENXIO; err = -ENXIO;
...@@ -767,7 +797,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, ...@@ -767,7 +797,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
break; break;
case PPPIOCATTCHAN: case PPPIOCATTCHAN:
if (get_user(unit, (int *) arg)) if (get_user(unit, p))
break; break;
spin_lock_bh(&all_channels_lock); spin_lock_bh(&all_channels_lock);
err = -ENXIO; err = -ENXIO;
...@@ -999,18 +1029,18 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -999,18 +1029,18 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
*p = htons(4); /* indicate outbound in DLT_LINUX_SLL */; *p = htons(4); /* indicate outbound in DLT_LINUX_SLL */;
} }
if (ppp->pass_filter.filter if (ppp->pass_filter
&& sk_run_filter(skb, ppp->pass_filter.filter, && sk_run_filter(skb, ppp->pass_filter,
ppp->pass_filter.len) == 0) { ppp->pass_len) == 0) {
if (ppp->debug & 1) if (ppp->debug & 1)
printk(KERN_DEBUG "PPP: outbound frame not passed\n"); printk(KERN_DEBUG "PPP: outbound frame not passed\n");
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
/* if this packet passes the active filter, record the time */ /* if this packet passes the active filter, record the time */
if (!(ppp->active_filter.filter if (!(ppp->active_filter
&& sk_run_filter(skb, ppp->active_filter.filter, && sk_run_filter(skb, ppp->active_filter,
ppp->active_filter.len) == 0)) ppp->active_len) == 0))
ppp->last_xmit = jiffies; ppp->last_xmit = jiffies;
skb_pull(skb, 2); skb_pull(skb, 2);
#else #else
...@@ -1546,17 +1576,17 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1546,17 +1576,17 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
*p = 0; /* indicate inbound in DLT_LINUX_SLL */ *p = 0; /* indicate inbound in DLT_LINUX_SLL */
} }
if (ppp->pass_filter.filter if (ppp->pass_filter
&& sk_run_filter(skb, ppp->pass_filter.filter, && sk_run_filter(skb, ppp->pass_filter,
ppp->pass_filter.len) == 0) { ppp->pass_len) == 0) {
if (ppp->debug & 1) if (ppp->debug & 1)
printk(KERN_DEBUG "PPP: inbound frame not passed\n"); printk(KERN_DEBUG "PPP: inbound frame not passed\n");
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
if (!(ppp->active_filter.filter if (!(ppp->active_filter
&& sk_run_filter(skb, ppp->active_filter.filter, && sk_run_filter(skb, ppp->active_filter,
ppp->active_filter.len) == 0)) ppp->active_len) == 0))
ppp->last_recv = jiffies; ppp->last_recv = jiffies;
skb_pull(skb, 2); skb_pull(skb, 2);
#else #else
...@@ -2423,13 +2453,13 @@ static void ppp_destroy_interface(struct ppp *ppp) ...@@ -2423,13 +2453,13 @@ static void ppp_destroy_interface(struct ppp *ppp)
skb_queue_purge(&ppp->mrq); skb_queue_purge(&ppp->mrq);
#endif /* CONFIG_PPP_MULTILINK */ #endif /* CONFIG_PPP_MULTILINK */
#ifdef CONFIG_PPP_FILTER #ifdef CONFIG_PPP_FILTER
if (ppp->pass_filter.filter) { if (ppp->pass_filter) {
kfree(ppp->pass_filter.filter); kfree(ppp->pass_filter);
ppp->pass_filter.filter = NULL; ppp->pass_filter = NULL;
} }
if (ppp->active_filter.filter) { if (ppp->active_filter) {
kfree(ppp->active_filter.filter); kfree(ppp->active_filter);
ppp->active_filter.filter = 0; ppp->active_filter = 0;
} }
#endif /* CONFIG_PPP_FILTER */ #endif /* CONFIG_PPP_FILTER */
......
...@@ -233,8 +233,9 @@ struct ippp_struct { ...@@ -233,8 +233,9 @@ struct ippp_struct {
struct slcompress *slcomp; struct slcompress *slcomp;
#endif #endif
#ifdef CONFIG_IPPP_FILTER #ifdef CONFIG_IPPP_FILTER
struct sock_fprog pass_filter; /* filter for packets to pass */ struct sock_filter *pass_filter; /* filter for packets to pass */
struct sock_fprog active_filter; /* filter for pkts to reset idle */ struct sock_filter *active_filter; /* filter for pkts to reset idle */
unsigned pass_len, active_len;
#endif #endif
unsigned long debug; unsigned long debug;
struct isdn_ppp_compressor *compressor,*decompressor; struct isdn_ppp_compressor *compressor,*decompressor;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment