summaryrefslogtreecommitdiff
path: root/drivers/net/ppp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ppp')
-rw-r--r--drivers/net/ppp/Kconfig37
-rw-r--r--drivers/net/ppp/bsd_comp.c5
-rw-r--r--drivers/net/ppp/ppp_async.c37
-rw-r--r--drivers/net/ppp/ppp_deflate.c3
-rw-r--r--drivers/net/ppp/ppp_generic.c340
-rw-r--r--drivers/net/ppp/ppp_mppe.c110
-rw-r--r--drivers/net/ppp/ppp_synctty.c40
-rw-r--r--drivers/net/ppp/pppoe.c171
-rw-r--r--drivers/net/ppp/pptp.c64
9 files changed, 412 insertions, 395 deletions
diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig
index ac4d162d9455..a1806b4b84be 100644
--- a/drivers/net/ppp/Kconfig
+++ b/drivers/net/ppp/Kconfig
@@ -85,9 +85,8 @@ config PPP_FILTER
config PPP_MPPE
tristate "PPP MPPE compression (encryption)"
depends on PPP
- select CRYPTO
- select CRYPTO_SHA1
select CRYPTO_LIB_ARC4
+ select CRYPTO_LIB_SHA1
help
Support for the MPPE Encryption protocol, as employed by the
Microsoft Point-to-Point Tunneling Protocol.
@@ -129,6 +128,40 @@ config PPPOE
which contains instruction on how to use this driver (under
the heading "Kernel mode PPPoE").
+choice
+ prompt "Number of PPPoE hash bits"
+ default PPPOE_HASH_BITS_4
+ depends on PPPOE
+ help
+ Select the number of bits used for hashing PPPoE interfaces.
+
+ Larger sizes reduces the risk of hash collisions at the cost
+ of slightly increased memory usage.
+
+ This hash table is on a per outer ethernet interface.
+
+config PPPOE_HASH_BITS_1
+ bool "1 bit (2 buckets)"
+
+config PPPOE_HASH_BITS_2
+ bool "2 bits (4 buckets)"
+
+config PPPOE_HASH_BITS_4
+ bool "4 bits (16 buckets)"
+
+config PPPOE_HASH_BITS_8
+ bool "8 bits (256 buckets)"
+
+endchoice
+
+config PPPOE_HASH_BITS
+ int
+ default 1 if PPPOE_HASH_BITS_1
+ default 2 if PPPOE_HASH_BITS_2
+ default 4 if PPPOE_HASH_BITS_4
+ default 8 if PPPOE_HASH_BITS_8
+ default 4
+
config PPTP
tristate "PPP over IPv4 (PPTP)"
depends on PPP && NET_IPGRE_DEMUX
diff --git a/drivers/net/ppp/bsd_comp.c b/drivers/net/ppp/bsd_comp.c
index db0dc36d12e3..f385b759d5cf 100644
--- a/drivers/net/ppp/bsd_comp.c
+++ b/drivers/net/ppp/bsd_comp.c
@@ -406,7 +406,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
* Allocate space for the dictionary. This may be more than one page in
* length.
*/
- db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict)));
+ db->dict = vmalloc_array(hsize, sizeof(struct bsd_dict));
if (!db->dict)
{
bsd_free (db);
@@ -425,7 +425,7 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
*/
else
{
- db->lens = vmalloc(array_size(sizeof(db->lens[0]), (maxmaxcode + 1)));
+ db->lens = vmalloc_array(maxmaxcode + 1, sizeof(db->lens[0]));
if (!db->lens)
{
bsd_free (db);
@@ -1166,5 +1166,6 @@ static void __exit bsdcomp_cleanup(void)
module_init(bsdcomp_init);
module_exit(bsdcomp_cleanup);
+MODULE_DESCRIPTION("PPP BSD-Compress compression module");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_BSD_COMPRESS));
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index 15a179631903..c97406c6004d 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -29,7 +29,7 @@
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/uaccess.h>
#include <asm/string.h>
@@ -87,6 +87,7 @@ struct asyncppp {
static int flag_time = HZ;
module_param(flag_time, int, 0);
MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)");
+MODULE_DESCRIPTION("PPP async serial channel module");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_PPP);
@@ -98,7 +99,7 @@ static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb);
static int ppp_async_push(struct asyncppp *ap);
static void ppp_async_flush_output(struct asyncppp *ap);
static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
- const char *flags, int count);
+ const u8 *flags, int count);
static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd,
unsigned long arg);
static void ppp_async_process(struct tasklet_struct *t);
@@ -257,9 +258,8 @@ static void ppp_asynctty_hangup(struct tty_struct *tty)
* Pppd reads and writes packets via /dev/ppp instead.
*/
static ssize_t
-ppp_asynctty_read(struct tty_struct *tty, struct file *file,
- unsigned char *buf, size_t count,
- void **cookie, unsigned long offset)
+ppp_asynctty_read(struct tty_struct *tty, struct file *file, u8 *buf,
+ size_t count, void **cookie, unsigned long offset)
{
return -EAGAIN;
}
@@ -269,8 +269,8 @@ ppp_asynctty_read(struct tty_struct *tty, struct file *file,
* from the ppp generic stuff.
*/
static ssize_t
-ppp_asynctty_write(struct tty_struct *tty, struct file *file,
- const unsigned char *buf, size_t count)
+ppp_asynctty_write(struct tty_struct *tty, struct file *file, const u8 *buf,
+ size_t count)
{
return -EAGAIN;
}
@@ -328,17 +328,10 @@ ppp_asynctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
return err;
}
-/* No kernel lock - fine */
-static __poll_t
-ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
-{
- return 0;
-}
-
/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
-ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
- const char *cflags, int count)
+ppp_asynctty_receive(struct tty_struct *tty, const u8 *buf, const u8 *cflags,
+ size_t count)
{
struct asyncppp *ap = ap_get(tty);
unsigned long flags;
@@ -378,7 +371,6 @@ static struct tty_ldisc_ops ppp_ldisc = {
.read = ppp_asynctty_read,
.write = ppp_asynctty_write,
.ioctl = ppp_asynctty_ioctl,
- .poll = ppp_asynctty_poll,
.receive_buf = ppp_asynctty_receive,
.write_wakeup = ppp_asynctty_wakeup,
};
@@ -469,6 +461,10 @@ ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
case PPPIOCSMRU:
if (get_user(val, p))
break;
+ if (val > U16_MAX) {
+ err = -EINVAL;
+ break;
+ }
if (val < PPP_MRU)
val = PPP_MRU;
ap->mru = val;
@@ -542,11 +538,11 @@ ppp_async_encode(struct asyncppp *ap)
proto = get_unaligned_be16(data);
/*
- * LCP packets with code values between 1 (configure-reqest)
+ * LCP packets with code values between 1 (configure-request)
* and 7 (code-reject) must be sent as though no options
* had been negotiated.
*/
- islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7;
+ islcp = proto == PPP_LCP && count >= 3 && 1 <= data[2] && data[2] <= 7;
if (i == 0) {
if (islcp)
@@ -827,8 +823,7 @@ process_input_packet(struct asyncppp *ap)
other ldisc functions but will not be re-entered */
static void
-ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
- const char *flags, int count)
+ppp_async_input(struct asyncppp *ap, const u8 *buf, const u8 *flags, int count)
{
struct sk_buff *skb;
int c, i, j, n, s, f;
diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c
index e6d48e5c65a3..d93aeacc0dba 100644
--- a/drivers/net/ppp/ppp_deflate.c
+++ b/drivers/net/ppp/ppp_deflate.c
@@ -16,7 +16,7 @@
#include <linux/ppp-comp.h>
#include <linux/zlib.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/*
* State for a Deflate (de)compressor.
@@ -630,6 +630,7 @@ static void __exit deflate_cleanup(void)
module_init(deflate_init);
module_exit(deflate_cleanup);
+MODULE_DESCRIPTION("PPP Deflate compression module");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE));
MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT));
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 1d71f5276241..f9f0f16c41d1 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -33,6 +33,7 @@
#include <linux/ppp_channel.h>
#include <linux/ppp-comp.h>
#include <linux/skbuff.h>
+#include <linux/rculist.h>
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
@@ -44,7 +45,8 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/file.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
+#include <net/netdev_lock.h>
#include <net/slhc_vj.h>
#include <linux/atomic.h>
#include <linux/refcount.h>
@@ -70,6 +72,18 @@
#define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */
#define PPP_PROTO_LEN 2
+#define PPP_LCP_HDRLEN 4
+
+/* The filter instructions generated by libpcap are constructed
+ * assuming a four-byte PPP header on each packet, where the last
+ * 2 bytes are the protocol field defined in the RFC and the first
+ * byte of the first 2 bytes indicates the direction.
+ * The second byte is currently unused, but we still need to initialize
+ * it to prevent crafted BPF programs from reading them which would
+ * cause reading of uninitialized data.
+ */
+#define PPP_FILTER_OUTBOUND_TAG 0x0100
+#define PPP_FILTER_INBOUND_TAG 0x0000
/*
* An instance of /dev/ppp can be associated with either a ppp
@@ -94,16 +108,9 @@ struct ppp_file {
#define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp)
#define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel)
-/*
- * Data structure to hold primary network stats for which
- * we want to use 64 bit storage. Other network stats
- * are stored in dev->stats of the ppp strucute.
- */
-struct ppp_link_stats {
- u64 rx_packets;
- u64 tx_packets;
- u64 rx_bytes;
- u64 tx_bytes;
+struct ppp_xmit_recursion {
+ struct task_struct *owner;
+ local_lock_t bh_lock;
};
/*
@@ -119,7 +126,7 @@ struct ppp {
int n_channels; /* how many channels are attached 54 */
spinlock_t rlock; /* lock for receive side 58 */
spinlock_t wlock; /* lock for transmit side 5c */
- int __percpu *xmit_recursion; /* xmit recursion detect */
+ struct ppp_xmit_recursion __percpu *xmit_recursion; /* xmit recursion detect */
int mru; /* max receive unit 60 */
unsigned int flags; /* control bits 64 */
unsigned int xstate; /* transmit state bits 68 */
@@ -149,7 +156,6 @@ struct ppp {
struct bpf_prog *active_filter; /* filter for pkts to reset idle */
#endif /* CONFIG_PPP_FILTER */
struct net *ppp_net; /* the net we belong to */
- struct ppp_link_stats stats64; /* 64 bit network stats */
};
/*
@@ -173,11 +179,11 @@ struct channel {
struct ppp_channel *chan; /* public channel data structure */
struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */
spinlock_t downl; /* protects `chan', file.xq dequeue */
- struct ppp *ppp; /* ppp unit we're connected to */
+ struct ppp __rcu *ppp; /* ppp unit we're connected to */
struct net *chan_net; /* the net channel belongs to */
netns_tracker ns_tracker;
struct list_head clist; /* link in list of channels per unit */
- rwlock_t upl; /* protects `ppp' and 'bridge' */
+ spinlock_t upl; /* protects `ppp' and 'bridge' */
struct channel __rcu *bridge; /* "bridged" ppp channel */
#ifdef CONFIG_PPP_MULTILINK
u8 avail; /* flag used in multilink stuff */
@@ -295,7 +301,9 @@ static void ppp_setup(struct net_device *dev);
static const struct net_device_ops ppp_netdev_ops;
-static struct class *ppp_class;
+static const struct class ppp_class = {
+ .name = "ppp",
+};
/* per net-namespace data */
static inline struct ppp_net *ppp_pernet(struct net *net)
@@ -491,6 +499,15 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
return ret;
}
+static bool ppp_check_packet(struct sk_buff *skb, size_t count)
+{
+ /* LCP packets must include LCP header which 4 bytes long:
+ * 1-byte code, 1-byte identifier, and 2-byte length.
+ */
+ return get_unaligned_be16(skb->data) != PPP_LCP ||
+ count >= PPP_PROTO_LEN + PPP_LCP_HDRLEN;
+}
+
static ssize_t ppp_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -513,6 +530,11 @@ static ssize_t ppp_write(struct file *file, const char __user *buf,
kfree_skb(skb);
goto out;
}
+ ret = -EINVAL;
+ if (unlikely(!ppp_check_packet(skb, count))) {
+ kfree_skb(skb);
+ goto out;
+ }
switch (pf->kind) {
case INTERFACE:
@@ -570,8 +592,8 @@ static struct bpf_prog *get_filter(struct sock_fprog *uprog)
/* uprog->len is unsigned short, so no overflow here */
fprog.len = uprog->len;
- fprog.filter = memdup_user(uprog->filter,
- uprog->len * sizeof(struct sock_filter));
+ fprog.filter = memdup_array_user(uprog->filter,
+ uprog->len, sizeof(struct sock_filter));
if (IS_ERR(fprog.filter))
return ERR_CAST(fprog.filter);
@@ -623,34 +645,34 @@ static struct bpf_prog *compat_ppp_get_filter(struct sock_fprog32 __user *p)
*/
static int ppp_bridge_channels(struct channel *pch, struct channel *pchb)
{
- write_lock_bh(&pch->upl);
- if (pch->ppp ||
+ spin_lock(&pch->upl);
+ if (rcu_dereference_protected(pch->ppp, lockdep_is_held(&pch->upl)) ||
rcu_dereference_protected(pch->bridge, lockdep_is_held(&pch->upl))) {
- write_unlock_bh(&pch->upl);
+ spin_unlock(&pch->upl);
return -EALREADY;
}
refcount_inc(&pchb->file.refcnt);
rcu_assign_pointer(pch->bridge, pchb);
- write_unlock_bh(&pch->upl);
+ spin_unlock(&pch->upl);
- write_lock_bh(&pchb->upl);
- if (pchb->ppp ||
+ spin_lock(&pchb->upl);
+ if (rcu_dereference_protected(pchb->ppp, lockdep_is_held(&pchb->upl)) ||
rcu_dereference_protected(pchb->bridge, lockdep_is_held(&pchb->upl))) {
- write_unlock_bh(&pchb->upl);
+ spin_unlock(&pchb->upl);
goto err_unset;
}
refcount_inc(&pch->file.refcnt);
rcu_assign_pointer(pchb->bridge, pch);
- write_unlock_bh(&pchb->upl);
+ spin_unlock(&pchb->upl);
return 0;
err_unset:
- write_lock_bh(&pch->upl);
+ spin_lock(&pch->upl);
/* Re-read pch->bridge with upl held in case it was modified concurrently */
pchb = rcu_dereference_protected(pch->bridge, lockdep_is_held(&pch->upl));
RCU_INIT_POINTER(pch->bridge, NULL);
- write_unlock_bh(&pch->upl);
+ spin_unlock(&pch->upl);
synchronize_rcu();
if (pchb)
@@ -664,25 +686,25 @@ static int ppp_unbridge_channels(struct channel *pch)
{
struct channel *pchb, *pchbb;
- write_lock_bh(&pch->upl);
+ spin_lock(&pch->upl);
pchb = rcu_dereference_protected(pch->bridge, lockdep_is_held(&pch->upl));
if (!pchb) {
- write_unlock_bh(&pch->upl);
+ spin_unlock(&pch->upl);
return -EINVAL;
}
RCU_INIT_POINTER(pch->bridge, NULL);
- write_unlock_bh(&pch->upl);
+ spin_unlock(&pch->upl);
/* Only modify pchb if phcb->bridge points back to pch.
* If not, it implies that there has been a race unbridging (and possibly
* even rebridging) pchb. We should leave pchb alone to avoid either a
* refcount underflow, or breaking another established bridge instance.
*/
- write_lock_bh(&pchb->upl);
+ spin_lock(&pchb->upl);
pchbb = rcu_dereference_protected(pchb->bridge, lockdep_is_held(&pchb->upl));
if (pchbb == pch)
RCU_INIT_POINTER(pchb->bridge, NULL);
- write_unlock_bh(&pchb->upl);
+ spin_unlock(&pchb->upl);
synchronize_rcu();
@@ -1102,6 +1124,8 @@ static const struct file_operations ppp_device_fops = {
.llseek = noop_llseek,
};
+static void ppp_nl_dellink(struct net_device *dev, struct list_head *head);
+
static __net_init int ppp_init_net(struct net *net)
{
struct ppp_net *pn = net_generic(net, ppp_net_id);
@@ -1117,28 +1141,20 @@ static __net_init int ppp_init_net(struct net *net)
return 0;
}
-static __net_exit void ppp_exit_net(struct net *net)
+static __net_exit void ppp_exit_rtnl_net(struct net *net,
+ struct list_head *dev_to_kill)
{
struct ppp_net *pn = net_generic(net, ppp_net_id);
- struct net_device *dev;
- struct net_device *aux;
struct ppp *ppp;
- LIST_HEAD(list);
int id;
- rtnl_lock();
- for_each_netdev_safe(net, dev, aux) {
- if (dev->netdev_ops == &ppp_netdev_ops)
- unregister_netdevice_queue(dev, &list);
- }
-
idr_for_each_entry(&pn->units_idr, ppp, id)
- /* Skip devices already unregistered by previous loop */
- if (!net_eq(dev_net(ppp->dev), net))
- unregister_netdevice_queue(ppp->dev, &list);
+ ppp_nl_dellink(ppp->dev, dev_to_kill);
+}
- unregister_netdevice_many(&list);
- rtnl_unlock();
+static __net_exit void ppp_exit_net(struct net *net)
+{
+ struct ppp_net *pn = net_generic(net, ppp_net_id);
mutex_destroy(&pn->all_ppp_mutex);
idr_destroy(&pn->units_idr);
@@ -1148,6 +1164,7 @@ static __net_exit void ppp_exit_net(struct net *net)
static struct pernet_operations ppp_net_ops = {
.init = ppp_init_net,
+ .exit_rtnl = ppp_exit_rtnl_net,
.exit = ppp_exit_net,
.id = &ppp_net_id,
.size = sizeof(struct ppp_net),
@@ -1238,13 +1255,18 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
spin_lock_init(&ppp->rlock);
spin_lock_init(&ppp->wlock);
- ppp->xmit_recursion = alloc_percpu(int);
+ ppp->xmit_recursion = alloc_percpu(struct ppp_xmit_recursion);
if (!ppp->xmit_recursion) {
err = -ENOMEM;
goto err1;
}
- for_each_possible_cpu(cpu)
- (*per_cpu_ptr(ppp->xmit_recursion, cpu)) = 0;
+ for_each_possible_cpu(cpu) {
+ struct ppp_xmit_recursion *xmit_recursion;
+
+ xmit_recursion = per_cpu_ptr(ppp->xmit_recursion, cpu);
+ xmit_recursion->owner = NULL;
+ local_lock_init(&xmit_recursion->bh_lock);
+ }
#ifdef CONFIG_PPP_MULTILINK
ppp->minseq = -1;
@@ -1286,10 +1308,13 @@ static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[],
return 0;
}
-static int ppp_nl_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[],
+static int ppp_nl_newlink(struct net_device *dev,
+ struct rtnl_newlink_params *params,
struct netlink_ext_ack *extack)
{
+ struct net *link_net = rtnl_newlink_link_net(params);
+ struct nlattr **data = params->data;
+ struct nlattr **tb = params->tb;
struct ppp_config conf = {
.unit = -1,
.ifname_is_set = true,
@@ -1326,7 +1351,7 @@ static int ppp_nl_newlink(struct net *src_net, struct net_device *dev,
if (!tb[IFLA_IFNAME] || !nla_len(tb[IFLA_IFNAME]) || !*(char *)nla_data(tb[IFLA_IFNAME]))
conf.ifname_is_set = false;
- err = ppp_dev_configure(src_net, dev, &conf);
+ err = ppp_dev_configure(link_net, dev, &conf);
out_unlock:
mutex_unlock(&ppp_mutex);
@@ -1355,7 +1380,7 @@ static struct net *ppp_nl_get_link_net(const struct net_device *dev)
{
struct ppp *ppp = netdev_priv(dev);
- return ppp->ppp_net;
+ return READ_ONCE(ppp->ppp_net);
}
static struct rtnl_link_ops ppp_link_ops __read_mostly = {
@@ -1394,11 +1419,9 @@ static int __init ppp_init(void)
goto out_net;
}
- ppp_class = class_create(THIS_MODULE, "ppp");
- if (IS_ERR(ppp_class)) {
- err = PTR_ERR(ppp_class);
+ err = class_register(&ppp_class);
+ if (err)
goto out_chrdev;
- }
err = rtnl_link_register(&ppp_link_ops);
if (err) {
@@ -1407,12 +1430,12 @@ static int __init ppp_init(void)
}
/* not a big deal if we fail here :-) */
- device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
+ device_create(&ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
return 0;
out_class:
- class_destroy(ppp_class);
+ class_unregister(&ppp_class);
out_chrdev:
unregister_chrdev(PPP_MAJOR, "ppp");
out_net:
@@ -1514,23 +1537,12 @@ ppp_net_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
static void
ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64)
{
- struct ppp *ppp = netdev_priv(dev);
-
- ppp_recv_lock(ppp);
- stats64->rx_packets = ppp->stats64.rx_packets;
- stats64->rx_bytes = ppp->stats64.rx_bytes;
- ppp_recv_unlock(ppp);
-
- ppp_xmit_lock(ppp);
- stats64->tx_packets = ppp->stats64.tx_packets;
- stats64->tx_bytes = ppp->stats64.tx_bytes;
- ppp_xmit_unlock(ppp);
-
stats64->rx_errors = dev->stats.rx_errors;
stats64->tx_errors = dev->stats.tx_errors;
stats64->rx_dropped = dev->stats.rx_dropped;
stats64->tx_dropped = dev->stats.tx_dropped;
stats64->rx_length_errors = dev->stats.rx_length_errors;
+ dev_fetch_sw_netstats(stats64, dev->tstats);
}
static int ppp_dev_init(struct net_device *dev)
@@ -1587,11 +1599,14 @@ static int ppp_fill_forward_path(struct net_device_path_ctx *ctx,
if (ppp->flags & SC_MULTILINK)
return -EOPNOTSUPP;
- if (list_empty(&ppp->channels))
+ pch = list_first_or_null_rcu(&ppp->channels, struct channel, clist);
+ if (!pch)
+ return -ENODEV;
+
+ chan = READ_ONCE(pch->chan);
+ if (!chan)
return -ENODEV;
- pch = list_first_entry(&ppp->channels, struct channel, clist);
- chan = pch->chan;
if (!chan->ops->fill_forward_path)
return -EOPNOTSUPP;
@@ -1607,7 +1622,7 @@ static const struct net_device_ops ppp_netdev_ops = {
.ndo_fill_forward_path = ppp_fill_forward_path,
};
-static struct device_type ppp_type = {
+static const struct device_type ppp_type = {
.name = "ppp",
};
@@ -1616,7 +1631,7 @@ static void ppp_setup(struct net_device *dev)
dev->netdev_ops = &ppp_netdev_ops;
SET_NETDEV_DEVTYPE(dev, &ppp_type);
- dev->features |= NETIF_F_LLTX;
+ dev->lltx = true;
dev->hard_header_len = PPP_HDRLEN;
dev->mtu = PPP_MRU;
@@ -1625,6 +1640,7 @@ static void ppp_setup(struct net_device *dev)
dev->type = ARPHRD_PPP;
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
dev->priv_destructor = ppp_dev_priv_destructor;
+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
netif_keep_dst(dev);
}
@@ -1658,15 +1674,20 @@ static void __ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb)
static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb)
{
+ struct ppp_xmit_recursion *xmit_recursion;
+
local_bh_disable();
- if (unlikely(*this_cpu_ptr(ppp->xmit_recursion)))
+ xmit_recursion = this_cpu_ptr(ppp->xmit_recursion);
+ if (xmit_recursion->owner == current)
goto err;
+ local_lock_nested_bh(&ppp->xmit_recursion->bh_lock);
+ xmit_recursion->owner = current;
- (*this_cpu_ptr(ppp->xmit_recursion))++;
__ppp_xmit_process(ppp, skb);
- (*this_cpu_ptr(ppp->xmit_recursion))--;
+ xmit_recursion->owner = NULL;
+ local_unlock_nested_bh(&ppp->xmit_recursion->bh_lock);
local_bh_enable();
return;
@@ -1723,7 +1744,6 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
*/
if (net_ratelimit())
netdev_err(ppp->dev, "ppp: compressor dropped pkt\n");
- kfree_skb(skb);
consume_skb(new_skb);
new_skb = NULL;
}
@@ -1747,10 +1767,10 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
if (proto < 0x8000) {
#ifdef CONFIG_PPP_FILTER
- /* check if we should pass this packet */
- /* the filter instructions are constructed assuming
- a four-byte PPP header on each packet */
- *(u8 *)skb_push(skb, 2) = 1;
+ /* check if the packet passes the pass and active filters.
+ * See comment for PPP_FILTER_OUTBOUND_TAG above.
+ */
+ *(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_OUTBOUND_TAG);
if (ppp->pass_filter &&
bpf_prog_run(ppp->pass_filter, skb) == 0) {
if (ppp->debug & 1)
@@ -1771,8 +1791,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
#endif /* CONFIG_PPP_FILTER */
}
- ++ppp->stats64.tx_packets;
- ppp->stats64.tx_bytes += skb->len - PPP_PROTO_LEN;
+ dev_sw_netstats_tx_add(ppp->dev, 1, skb->len - PPP_PROTO_LEN);
switch (proto) {
case PPP_IP:
@@ -1825,9 +1844,10 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
"down - pkt dropped.\n");
goto drop;
}
- skb = pad_compress_skb(ppp, skb);
- if (!skb)
+ new_skb = pad_compress_skb(ppp, skb);
+ if (!new_skb)
goto drop;
+ skb = new_skb;
}
/*
@@ -2138,10 +2158,9 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
#endif /* CONFIG_PPP_MULTILINK */
/* Try to send data out on a channel */
-static void __ppp_channel_push(struct channel *pch)
+static void __ppp_channel_push(struct channel *pch, struct ppp *ppp)
{
struct sk_buff *skb;
- struct ppp *ppp;
spin_lock(&pch->downl);
if (pch->chan) {
@@ -2160,7 +2179,6 @@ static void __ppp_channel_push(struct channel *pch)
spin_unlock(&pch->downl);
/* see if there is anything from the attached unit to be sent */
if (skb_queue_empty(&pch->file.xq)) {
- ppp = pch->ppp;
if (ppp)
__ppp_xmit_process(ppp, NULL);
}
@@ -2168,15 +2186,22 @@ static void __ppp_channel_push(struct channel *pch)
static void ppp_channel_push(struct channel *pch)
{
- read_lock_bh(&pch->upl);
- if (pch->ppp) {
- (*this_cpu_ptr(pch->ppp->xmit_recursion))++;
- __ppp_channel_push(pch);
- (*this_cpu_ptr(pch->ppp->xmit_recursion))--;
+ struct ppp_xmit_recursion *xmit_recursion;
+ struct ppp *ppp;
+
+ rcu_read_lock_bh();
+ ppp = rcu_dereference_bh(pch->ppp);
+ if (ppp) {
+ xmit_recursion = this_cpu_ptr(ppp->xmit_recursion);
+ local_lock_nested_bh(&ppp->xmit_recursion->bh_lock);
+ xmit_recursion->owner = current;
+ __ppp_channel_push(pch, ppp);
+ xmit_recursion->owner = NULL;
+ local_unlock_nested_bh(&ppp->xmit_recursion->bh_lock);
} else {
- __ppp_channel_push(pch);
+ __ppp_channel_push(pch, NULL);
}
- read_unlock_bh(&pch->upl);
+ rcu_read_unlock_bh();
}
/*
@@ -2254,7 +2279,7 @@ static bool ppp_channel_bridge_input(struct channel *pch, struct sk_buff *skb)
if (!pchb)
goto out_rcu;
- spin_lock(&pchb->downl);
+ spin_lock_bh(&pchb->downl);
if (!pchb->chan) {
/* channel got unregistered */
kfree_skb(skb);
@@ -2266,7 +2291,7 @@ static bool ppp_channel_bridge_input(struct channel *pch, struct sk_buff *skb)
kfree_skb(skb);
outl:
- spin_unlock(&pchb->downl);
+ spin_unlock_bh(&pchb->downl);
out_rcu:
rcu_read_unlock();
@@ -2278,6 +2303,7 @@ void
ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
{
struct channel *pch = chan->ppp;
+ struct ppp *ppp;
int proto;
if (!pch) {
@@ -2289,18 +2315,19 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
if (ppp_channel_bridge_input(pch, skb))
return;
- read_lock_bh(&pch->upl);
+ rcu_read_lock_bh();
+ ppp = rcu_dereference_bh(pch->ppp);
if (!ppp_decompress_proto(skb)) {
kfree_skb(skb);
- if (pch->ppp) {
- ++pch->ppp->dev->stats.rx_length_errors;
- ppp_receive_error(pch->ppp);
+ if (ppp) {
+ ++ppp->dev->stats.rx_length_errors;
+ ppp_receive_error(ppp);
}
goto done;
}
proto = PPP_PROTO(skb);
- if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) {
+ if (!ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) {
/* put it on the channel queue */
skb_queue_tail(&pch->file.rq, skb);
/* drop old frames if queue too long */
@@ -2309,11 +2336,11 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
kfree_skb(skb);
wake_up_interruptible(&pch->file.rwait);
} else {
- ppp_do_recv(pch->ppp, skb, pch);
+ ppp_do_recv(ppp, skb, pch);
}
done:
- read_unlock_bh(&pch->upl);
+ rcu_read_unlock_bh();
}
/* Put a 0-length skb in the receive queue as an error indication */
@@ -2322,20 +2349,22 @@ ppp_input_error(struct ppp_channel *chan, int code)
{
struct channel *pch = chan->ppp;
struct sk_buff *skb;
+ struct ppp *ppp;
if (!pch)
return;
- read_lock_bh(&pch->upl);
- if (pch->ppp) {
+ rcu_read_lock_bh();
+ ppp = rcu_dereference_bh(pch->ppp);
+ if (ppp) {
skb = alloc_skb(0, GFP_ATOMIC);
if (skb) {
skb->len = 0; /* probably unnecessary */
skb->cb[0] = code;
- ppp_do_recv(pch->ppp, skb, pch);
+ ppp_do_recv(ppp, skb, pch);
}
}
- read_unlock_bh(&pch->upl);
+ rcu_read_unlock_bh();
}
/*
@@ -2449,8 +2478,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
break;
}
- ++ppp->stats64.rx_packets;
- ppp->stats64.rx_bytes += skb->len - 2;
+ dev_sw_netstats_rx_add(ppp->dev, skb->len - PPP_PROTO_LEN);
npi = proto_to_npindex(proto);
if (npi < 0) {
@@ -2467,14 +2495,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* network protocol frame - give it to the kernel */
#ifdef CONFIG_PPP_FILTER
- /* check if the packet passes the pass and active filters */
- /* the filter instructions are constructed assuming
- a four-byte PPP header on each packet */
if (ppp->pass_filter || ppp->active_filter) {
if (skb_unclone(skb, GFP_ATOMIC))
goto err;
-
- *(u8 *)skb_push(skb, 2) = 0;
+ /* Check if the packet passes the pass and active filters.
+ * See comment for PPP_FILTER_INBOUND_TAG above.
+ */
+ *(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_INBOUND_TAG);
if (ppp->pass_filter &&
bpf_prog_run(ppp->pass_filter, skb) == 0) {
if (ppp->debug & 1)
@@ -2885,7 +2912,6 @@ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan)
pn = ppp_pernet(net);
- pch->ppp = NULL;
pch->chan = chan;
pch->chan_net = get_net_track(net, &pch->ns_tracker, GFP_KERNEL);
chan->ppp = pch;
@@ -2896,7 +2922,7 @@ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan)
#endif /* CONFIG_PPP_MULTILINK */
init_rwsem(&pch->chan_sem);
spin_lock_init(&pch->downl);
- rwlock_init(&pch->upl);
+ spin_lock_init(&pch->upl);
spin_lock_bh(&pn->all_channels_lock);
pch->file.index = ++pn->last_channel_index;
@@ -2925,13 +2951,15 @@ int ppp_channel_index(struct ppp_channel *chan)
int ppp_unit_number(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
+ struct ppp *ppp;
int unit = -1;
if (pch) {
- read_lock_bh(&pch->upl);
- if (pch->ppp)
- unit = pch->ppp->file.index;
- read_unlock_bh(&pch->upl);
+ rcu_read_lock();
+ ppp = rcu_dereference(pch->ppp);
+ if (ppp)
+ unit = ppp->file.index;
+ rcu_read_unlock();
}
return unit;
}
@@ -2943,12 +2971,14 @@ char *ppp_dev_name(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
char *name = NULL;
+ struct ppp *ppp;
if (pch) {
- read_lock_bh(&pch->upl);
- if (pch->ppp && pch->ppp->dev)
- name = pch->ppp->dev->name;
- read_unlock_bh(&pch->upl);
+ rcu_read_lock();
+ ppp = rcu_dereference(pch->ppp);
+ if (ppp && ppp->dev)
+ name = ppp->dev->name;
+ rcu_read_unlock();
}
return name;
}
@@ -2975,7 +3005,7 @@ ppp_unregister_channel(struct ppp_channel *chan)
*/
down_write(&pch->chan_sem);
spin_lock_bh(&pch->downl);
- pch->chan = NULL;
+ WRITE_ONCE(pch->chan, NULL);
spin_unlock_bh(&pch->downl);
up_write(&pch->chan_sem);
ppp_disconnect_channel(pch);
@@ -3279,14 +3309,25 @@ static void
ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
{
struct slcompress *vj = ppp->vj;
+ int cpu;
memset(st, 0, sizeof(*st));
- st->p.ppp_ipackets = ppp->stats64.rx_packets;
+ for_each_possible_cpu(cpu) {
+ struct pcpu_sw_netstats *p = per_cpu_ptr(ppp->dev->tstats, cpu);
+ u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+
+ rx_packets = u64_stats_read(&p->rx_packets);
+ rx_bytes = u64_stats_read(&p->rx_bytes);
+ tx_packets = u64_stats_read(&p->tx_packets);
+ tx_bytes = u64_stats_read(&p->tx_bytes);
+
+ st->p.ppp_ipackets += rx_packets;
+ st->p.ppp_ibytes += rx_bytes;
+ st->p.ppp_opackets += tx_packets;
+ st->p.ppp_obytes += tx_bytes;
+ }
st->p.ppp_ierrors = ppp->dev->stats.rx_errors;
- st->p.ppp_ibytes = ppp->stats64.rx_bytes;
- st->p.ppp_opackets = ppp->stats64.tx_packets;
st->p.ppp_oerrors = ppp->dev->stats.tx_errors;
- st->p.ppp_obytes = ppp->stats64.tx_bytes;
if (!vj)
return;
st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;
@@ -3460,9 +3501,9 @@ ppp_connect_channel(struct channel *pch, int unit)
ppp = ppp_find_unit(pn, unit);
if (!ppp)
goto out;
- write_lock_bh(&pch->upl);
+ spin_lock(&pch->upl);
ret = -EINVAL;
- if (pch->ppp ||
+ if (rcu_dereference_protected(pch->ppp, lockdep_is_held(&pch->upl)) ||
rcu_dereference_protected(pch->bridge, lockdep_is_held(&pch->upl)))
goto outl;
@@ -3475,21 +3516,25 @@ ppp_connect_channel(struct channel *pch, int unit)
ret = -ENOTCONN;
goto outl;
}
+ if (pch->chan->direct_xmit)
+ ppp->dev->priv_flags |= IFF_NO_QUEUE;
+ else
+ ppp->dev->priv_flags &= ~IFF_NO_QUEUE;
spin_unlock_bh(&pch->downl);
if (pch->file.hdrlen > ppp->file.hdrlen)
ppp->file.hdrlen = pch->file.hdrlen;
hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */
if (hdrlen > ppp->dev->hard_header_len)
ppp->dev->hard_header_len = hdrlen;
- list_add_tail(&pch->clist, &ppp->channels);
+ list_add_tail_rcu(&pch->clist, &ppp->channels);
++ppp->n_channels;
- pch->ppp = ppp;
+ rcu_assign_pointer(pch->ppp, ppp);
refcount_inc(&ppp->file.refcnt);
ppp_unlock(ppp);
ret = 0;
outl:
- write_unlock_bh(&pch->upl);
+ spin_unlock(&pch->upl);
out:
mutex_unlock(&pn->all_ppp_mutex);
return ret;
@@ -3504,17 +3549,17 @@ ppp_disconnect_channel(struct channel *pch)
struct ppp *ppp;
int err = -EINVAL;
- write_lock_bh(&pch->upl);
- ppp = pch->ppp;
- pch->ppp = NULL;
- write_unlock_bh(&pch->upl);
+ spin_lock(&pch->upl);
+ ppp = rcu_replace_pointer(pch->ppp, NULL, lockdep_is_held(&pch->upl));
+ spin_unlock(&pch->upl);
if (ppp) {
/* remove it from the ppp unit's list */
ppp_lock(ppp);
- list_del(&pch->clist);
+ list_del_rcu(&pch->clist);
if (--ppp->n_channels == 0)
wake_up_interruptible(&ppp->file.rwait);
ppp_unlock(ppp);
+ synchronize_net();
if (refcount_dec_and_test(&ppp->file.refcnt))
ppp_destroy_interface(ppp);
err = 0;
@@ -3549,8 +3594,8 @@ static void __exit ppp_cleanup(void)
pr_err("PPP: removing module but units remain!\n");
rtnl_link_unregister(&ppp_link_ops);
unregister_chrdev(PPP_MAJOR, "ppp");
- device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
- class_destroy(ppp_class);
+ device_destroy(&ppp_class, MKDEV(PPP_MAJOR, 0));
+ class_unregister(&ppp_class);
unregister_pernet_device(&ppp_net_ops);
}
@@ -3604,6 +3649,7 @@ EXPORT_SYMBOL(ppp_input_error);
EXPORT_SYMBOL(ppp_output_wakeup);
EXPORT_SYMBOL(ppp_register_compressor);
EXPORT_SYMBOL(ppp_unregister_compressor);
+MODULE_DESCRIPTION("Generic PPP layer driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
MODULE_ALIAS_RTNL_LINK("ppp");
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index 208f6e24f37c..630cbf71c147 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -43,7 +43,7 @@
*/
#include <crypto/arc4.h>
-#include <crypto/hash.h>
+#include <crypto/sha1.h>
#include <linux/err.h>
#include <linux/fips.h>
#include <linux/module.h>
@@ -55,8 +55,7 @@
#include <linux/mm.h>
#include <linux/ppp_defs.h>
#include <linux/ppp-comp.h>
-#include <linux/scatterlist.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "ppp_mppe.h"
@@ -67,31 +66,15 @@ MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
MODULE_VERSION("1.0.2");
#define SHA1_PAD_SIZE 40
-
-/*
- * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module
- * static data area. That means sha_pad needs to be kmalloc'd.
- */
-
-struct sha_pad {
- unsigned char sha_pad1[SHA1_PAD_SIZE];
- unsigned char sha_pad2[SHA1_PAD_SIZE];
-};
-static struct sha_pad *sha_pad;
-
-static inline void sha_pad_init(struct sha_pad *shapad)
-{
- memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1));
- memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2));
-}
+static const u8 sha_pad1[SHA1_PAD_SIZE] = { 0 };
+static const u8 sha_pad2[SHA1_PAD_SIZE] = { [0 ... SHA1_PAD_SIZE - 1] = 0xF2 };
/*
* State for an MPPE (de)compressor.
*/
struct ppp_mppe_state {
struct arc4_ctx arc4;
- struct shash_desc *sha1;
- unsigned char *sha1_digest;
+ unsigned char sha1_digest[SHA1_DIGEST_SIZE];
unsigned char master_key[MPPE_MAX_KEY_LEN];
unsigned char session_key[MPPE_MAX_KEY_LEN];
unsigned keylen; /* key length in bytes */
@@ -130,16 +113,14 @@ struct ppp_mppe_state {
*/
static void get_new_key_from_sha(struct ppp_mppe_state * state)
{
- crypto_shash_init(state->sha1);
- crypto_shash_update(state->sha1, state->master_key,
- state->keylen);
- crypto_shash_update(state->sha1, sha_pad->sha_pad1,
- sizeof(sha_pad->sha_pad1));
- crypto_shash_update(state->sha1, state->session_key,
- state->keylen);
- crypto_shash_update(state->sha1, sha_pad->sha_pad2,
- sizeof(sha_pad->sha_pad2));
- crypto_shash_final(state->sha1, state->sha1_digest);
+ struct sha1_ctx ctx;
+
+ sha1_init(&ctx);
+ sha1_update(&ctx, state->master_key, state->keylen);
+ sha1_update(&ctx, sha_pad1, sizeof(sha_pad1));
+ sha1_update(&ctx, state->session_key, state->keylen);
+ sha1_update(&ctx, sha_pad2, sizeof(sha_pad2));
+ sha1_final(&ctx, state->sha1_digest);
}
/*
@@ -171,39 +152,15 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
static void *mppe_alloc(unsigned char *options, int optlen)
{
struct ppp_mppe_state *state;
- struct crypto_shash *shash;
- unsigned int digestsize;
if (optlen != CILEN_MPPE + sizeof(state->master_key) ||
options[0] != CI_MPPE || options[1] != CILEN_MPPE ||
fips_enabled)
- goto out;
+ return NULL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
- goto out;
-
-
- shash = crypto_alloc_shash("sha1", 0, 0);
- if (IS_ERR(shash))
- goto out_free;
-
- state->sha1 = kmalloc(sizeof(*state->sha1) +
- crypto_shash_descsize(shash),
- GFP_KERNEL);
- if (!state->sha1) {
- crypto_free_shash(shash);
- goto out_free;
- }
- state->sha1->tfm = shash;
-
- digestsize = crypto_shash_digestsize(shash);
- if (digestsize < MPPE_MAX_KEY_LEN)
- goto out_free;
-
- state->sha1_digest = kmalloc(digestsize, GFP_KERNEL);
- if (!state->sha1_digest)
- goto out_free;
+ return NULL;
/* Save keys. */
memcpy(state->master_key, &options[CILEN_MPPE],
@@ -217,16 +174,6 @@ static void *mppe_alloc(unsigned char *options, int optlen)
*/
return (void *)state;
-
-out_free:
- kfree(state->sha1_digest);
- if (state->sha1) {
- crypto_free_shash(state->sha1->tfm);
- kfree_sensitive(state->sha1);
- }
- kfree(state);
-out:
- return NULL;
}
/*
@@ -235,12 +182,8 @@ out:
static void mppe_free(void *arg)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
- if (state) {
- kfree(state->sha1_digest);
- crypto_free_shash(state->sha1->tfm);
- kfree_sensitive(state->sha1);
- kfree_sensitive(state);
- }
+
+ kfree_sensitive(state);
}
/*
@@ -649,31 +592,17 @@ static struct compressor ppp_mppe = {
.comp_extra = MPPE_PAD,
};
-/*
- * ppp_mppe_init()
- *
- * Prior to allowing load, try to load the arc4 and sha1 crypto
- * libraries. The actual use will be allocated later, but
- * this way the module will fail to insmod if they aren't available.
- */
-
static int __init ppp_mppe_init(void)
{
int answer;
- if (fips_enabled || !crypto_has_ahash("sha1", 0, CRYPTO_ALG_ASYNC))
- return -ENODEV;
- sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
- if (!sha_pad)
- return -ENOMEM;
- sha_pad_init(sha_pad);
+ if (fips_enabled)
+ return -ENODEV;
answer = ppp_register_compressor(&ppp_mppe);
if (answer == 0)
printk(KERN_INFO "PPP MPPE Compression module registered\n");
- else
- kfree(sha_pad);
return answer;
}
@@ -681,7 +610,6 @@ static int __init ppp_mppe_init(void)
static void __exit ppp_mppe_cleanup(void)
{
ppp_unregister_compressor(&ppp_mppe);
- kfree(sha_pad);
}
module_init(ppp_mppe_init);
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index 18283b7b94bc..9c4932198931 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -43,7 +43,7 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/refcount.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/uaccess.h>
#define PPP_VERSION "2.4.2"
@@ -93,8 +93,8 @@ static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd,
static void ppp_sync_process(struct tasklet_struct *t);
static int ppp_sync_push(struct syncppp *ap);
static void ppp_sync_flush_output(struct syncppp *ap);
-static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
- const char *flags, int count);
+static void ppp_sync_input(struct syncppp *ap, const u8 *buf, const u8 *flags,
+ int count);
static const struct ppp_channel_ops sync_ops = {
.start_xmit = ppp_sync_send,
@@ -255,8 +255,7 @@ static void ppp_sync_hangup(struct tty_struct *tty)
* Pppd reads and writes packets via /dev/ppp instead.
*/
static ssize_t
-ppp_sync_read(struct tty_struct *tty, struct file *file,
- unsigned char *buf, size_t count,
+ppp_sync_read(struct tty_struct *tty, struct file *file, u8 *buf, size_t count,
void **cookie, unsigned long offset)
{
return -EAGAIN;
@@ -267,8 +266,8 @@ ppp_sync_read(struct tty_struct *tty, struct file *file,
* from the ppp generic stuff.
*/
static ssize_t
-ppp_sync_write(struct tty_struct *tty, struct file *file,
- const unsigned char *buf, size_t count)
+ppp_sync_write(struct tty_struct *tty, struct file *file, const u8 *buf,
+ size_t count)
{
return -EAGAIN;
}
@@ -321,17 +320,10 @@ ppp_synctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
return err;
}
-/* No kernel lock - fine */
-static __poll_t
-ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
-{
- return 0;
-}
-
/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
-ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
- const char *cflags, int count)
+ppp_sync_receive(struct tty_struct *tty, const u8 *buf, const u8 *cflags,
+ size_t count)
{
struct syncppp *ap = sp_get(tty);
unsigned long flags;
@@ -371,7 +363,6 @@ static struct tty_ldisc_ops ppp_sync_ldisc = {
.read = ppp_sync_read,
.write = ppp_sync_write,
.ioctl = ppp_synctty_ioctl,
- .poll = ppp_sync_poll,
.receive_buf = ppp_sync_receive,
.write_wakeup = ppp_sync_wakeup,
};
@@ -462,6 +453,10 @@ ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
case PPPIOCSMRU:
if (get_user(val, (int __user *) argp))
break;
+ if (val > U16_MAX) {
+ err = -EINVAL;
+ break;
+ }
if (val < PPP_MRU)
val = PPP_MRU;
ap->mru = val;
@@ -511,6 +506,11 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
unsigned char *data;
int islcp;
+ /* Ensure we can safely access protocol field and LCP code */
+ if (!pskb_may_pull(skb, 3)) {
+ kfree_skb(skb);
+ return NULL;
+ }
data = skb->data;
proto = get_unaligned_be16(data);
@@ -663,8 +663,7 @@ ppp_sync_flush_output(struct syncppp *ap)
* frame is considered to be in error and is tossed.
*/
static void
-ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
- const char *flags, int count)
+ppp_sync_input(struct syncppp *ap, const u8 *buf, const u8 *flags, int count)
{
struct sk_buff *skb;
unsigned char *p;
@@ -697,7 +696,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
/* strip address/control field if present */
p = skb->data;
- if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+ if (skb->len >= 2 && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
/* chop off address/control */
if (skb->len < 3)
goto err;
@@ -730,5 +729,6 @@ ppp_sync_cleanup(void)
module_init(ppp_sync_init);
module_exit(ppp_sync_cleanup);
+MODULE_DESCRIPTION("PPP synchronous TTY channel module");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_SYNC_PPP);
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index ce2cbb5903d7..4275b393a454 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -80,7 +80,7 @@
#include <linux/uaccess.h>
-#define PPPOE_HASH_BITS 4
+#define PPPOE_HASH_BITS CONFIG_PPPOE_HASH_BITS
#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS)
#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1)
@@ -100,8 +100,8 @@ struct pppoe_net {
* as well, moreover in case of SMP less locking
* controversy here
*/
- struct pppox_sock *hash_table[PPPOE_HASH_SIZE];
- rwlock_t hash_lock;
+ struct pppox_sock __rcu *hash_table[PPPOE_HASH_SIZE];
+ spinlock_t hash_lock;
};
/*
@@ -162,13 +162,13 @@ static struct pppox_sock *__get_item(struct pppoe_net *pn, __be16 sid,
int hash = hash_item(sid, addr);
struct pppox_sock *ret;
- ret = pn->hash_table[hash];
+ ret = rcu_dereference(pn->hash_table[hash]);
while (ret) {
if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
ret->pppoe_ifindex == ifindex)
return ret;
- ret = ret->next;
+ ret = rcu_dereference(ret->next);
}
return NULL;
@@ -177,19 +177,20 @@ static struct pppox_sock *__get_item(struct pppoe_net *pn, __be16 sid,
static int __set_item(struct pppoe_net *pn, struct pppox_sock *po)
{
int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
- struct pppox_sock *ret;
+ struct pppox_sock *ret, *first;
- ret = pn->hash_table[hash];
+ first = rcu_dereference_protected(pn->hash_table[hash], lockdep_is_held(&pn->hash_lock));
+ ret = first;
while (ret) {
if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa) &&
ret->pppoe_ifindex == po->pppoe_ifindex)
return -EALREADY;
- ret = ret->next;
+ ret = rcu_dereference_protected(ret->next, lockdep_is_held(&pn->hash_lock));
}
- po->next = pn->hash_table[hash];
- pn->hash_table[hash] = po;
+ RCU_INIT_POINTER(po->next, first);
+ rcu_assign_pointer(pn->hash_table[hash], po);
return 0;
}
@@ -198,20 +199,24 @@ static void __delete_item(struct pppoe_net *pn, __be16 sid,
char *addr, int ifindex)
{
int hash = hash_item(sid, addr);
- struct pppox_sock *ret, **src;
+ struct pppox_sock *ret, __rcu **src;
- ret = pn->hash_table[hash];
+ ret = rcu_dereference_protected(pn->hash_table[hash], lockdep_is_held(&pn->hash_lock));
src = &pn->hash_table[hash];
while (ret) {
if (cmp_addr(&ret->pppoe_pa, sid, addr) &&
ret->pppoe_ifindex == ifindex) {
- *src = ret->next;
+ struct pppox_sock *next;
+
+ next = rcu_dereference_protected(ret->next,
+ lockdep_is_held(&pn->hash_lock));
+ rcu_assign_pointer(*src, next);
break;
}
src = &ret->next;
- ret = ret->next;
+ ret = rcu_dereference_protected(ret->next, lockdep_is_held(&pn->hash_lock));
}
}
@@ -225,17 +230,15 @@ static inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid,
{
struct pppox_sock *po;
- read_lock_bh(&pn->hash_lock);
po = __get_item(pn, sid, addr, ifindex);
- if (po)
- sock_hold(sk_pppox(po));
- read_unlock_bh(&pn->hash_lock);
+ if (po && !refcount_inc_not_zero(&sk_pppox(po)->sk_refcnt))
+ po = NULL;
return po;
}
-static inline struct pppox_sock *get_item_by_addr(struct net *net,
- struct sockaddr_pppox *sp)
+static inline struct pppox_sock *__get_item_by_addr(struct net *net,
+ struct sockaddr_pppox *sp)
{
struct net_device *dev;
struct pppoe_net *pn;
@@ -243,24 +246,22 @@ static inline struct pppox_sock *get_item_by_addr(struct net *net,
int ifindex;
- rcu_read_lock();
dev = dev_get_by_name_rcu(net, sp->sa_addr.pppoe.dev);
if (dev) {
ifindex = dev->ifindex;
pn = pppoe_pernet(net);
- pppox_sock = get_item(pn, sp->sa_addr.pppoe.sid,
- sp->sa_addr.pppoe.remote, ifindex);
+ pppox_sock = __get_item(pn, sp->sa_addr.pppoe.sid,
+ sp->sa_addr.pppoe.remote, ifindex);
}
- rcu_read_unlock();
return pppox_sock;
}
static inline void delete_item(struct pppoe_net *pn, __be16 sid,
char *addr, int ifindex)
{
- write_lock_bh(&pn->hash_lock);
+ spin_lock(&pn->hash_lock);
__delete_item(pn, sid, addr, ifindex);
- write_unlock_bh(&pn->hash_lock);
+ spin_unlock(&pn->hash_lock);
}
/***************************************************************************
@@ -276,14 +277,16 @@ static void pppoe_flush_dev(struct net_device *dev)
int i;
pn = pppoe_pernet(dev_net(dev));
- write_lock_bh(&pn->hash_lock);
+ spin_lock(&pn->hash_lock);
for (i = 0; i < PPPOE_HASH_SIZE; i++) {
- struct pppox_sock *po = pn->hash_table[i];
+ struct pppox_sock *po = rcu_dereference_protected(pn->hash_table[i],
+ lockdep_is_held(&pn->hash_lock));
struct sock *sk;
while (po) {
while (po && po->pppoe_dev != dev) {
- po = po->next;
+ po = rcu_dereference_protected(po->next,
+ lockdep_is_held(&pn->hash_lock));
}
if (!po)
@@ -300,7 +303,7 @@ static void pppoe_flush_dev(struct net_device *dev)
*/
sock_hold(sk);
- write_unlock_bh(&pn->hash_lock);
+ spin_unlock(&pn->hash_lock);
lock_sock(sk);
if (po->pppoe_dev == dev &&
@@ -320,11 +323,12 @@ static void pppoe_flush_dev(struct net_device *dev)
*/
BUG_ON(pppoe_pernet(dev_net(dev)) == NULL);
- write_lock_bh(&pn->hash_lock);
- po = pn->hash_table[i];
+ spin_lock(&pn->hash_lock);
+ po = rcu_dereference_protected(pn->hash_table[i],
+ lockdep_is_held(&pn->hash_lock));
}
}
- write_unlock_bh(&pn->hash_lock);
+ spin_unlock(&pn->hash_lock);
}
static int pppoe_device_event(struct notifier_block *this,
@@ -372,24 +376,19 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
* can't change.
*/
- if (skb->pkt_type == PACKET_OTHERHOST)
- goto abort_kfree;
-
if (sk->sk_state & PPPOX_BOUND) {
ppp_input(&po->chan, skb);
} else if (sk->sk_state & PPPOX_RELAY) {
- relay_po = get_item_by_addr(sock_net(sk),
- &po->pppoe_relay);
+ relay_po = __get_item_by_addr(sock_net(sk),
+ &po->pppoe_relay);
if (relay_po == NULL)
goto abort_kfree;
if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0)
- goto abort_put;
+ goto abort_kfree;
if (!__pppoe_xmit(sk_pppox(relay_po), skb))
- goto abort_put;
-
- sock_put(sk_pppox(relay_po));
+ goto abort_kfree;
} else {
if (sock_queue_rcv_skb(sk, skb))
goto abort_kfree;
@@ -397,9 +396,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
return NET_RX_SUCCESS;
-abort_put:
- sock_put(sk_pppox(relay_po));
-
abort_kfree:
kfree_skb(skb);
return NET_RX_DROP;
@@ -418,6 +414,9 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
struct pppoe_net *pn;
int len;
+ if (skb->pkt_type == PACKET_OTHERHOST)
+ goto drop;
+
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto out;
@@ -441,14 +440,11 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
ph = pppoe_hdr(skb);
pn = pppoe_pernet(dev_net(dev));
- /* Note that get_item does a sock_hold(), so sk_pppox(po)
- * is known to be safe.
- */
- po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+ po = __get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (!po)
goto drop;
- return sk_receive_skb(sk_pppox(po), skb, 0);
+ return __sk_receive_skb(sk_pppox(po), skb, 0, 1, false);
drop:
kfree_skb(skb);
@@ -528,6 +524,11 @@ static struct proto pppoe_sk_proto __read_mostly = {
.obj_size = sizeof(struct pppox_sock),
};
+static void pppoe_destruct(struct sock *sk)
+{
+ skb_queue_purge(&sk->sk_receive_queue);
+}
+
/***********************************************************************
*
* Initialize a new struct sock.
@@ -542,11 +543,13 @@ static int pppoe_create(struct net *net, struct socket *sock, int kern)
return -ENOMEM;
sock_init_data(sock, sk);
+ sock_set_flag(sk, SOCK_RCU_FREE);
sock->state = SS_UNCONNECTED;
sock->ops = &pppoe_ops;
sk->sk_backlog_rcv = pppoe_rcv_core;
+ sk->sk_destruct = pppoe_destruct;
sk->sk_state = PPPOX_NONE;
sk->sk_type = SOCK_STREAM;
sk->sk_family = PF_PPPOX;
@@ -599,15 +602,14 @@ static int pppoe_release(struct socket *sock)
sock_orphan(sk);
sock->sk = NULL;
- skb_queue_purge(&sk->sk_receive_queue);
release_sock(sk);
sock_put(sk);
return 0;
}
-static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags)
+static int pppoe_connect(struct socket *sock, struct sockaddr_unsized *uservaddr,
+ int sockaddr_len, int flags)
{
struct sock *sk = sock->sk;
struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr;
@@ -681,9 +683,9 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
&sp->sa_addr.pppoe,
sizeof(struct pppoe_addr));
- write_lock_bh(&pn->hash_lock);
+ spin_lock(&pn->hash_lock);
error = __set_item(pn, po);
- write_unlock_bh(&pn->hash_lock);
+ spin_unlock(&pn->hash_lock);
if (error < 0)
goto err_put;
@@ -693,6 +695,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
po->chan.private = sk;
po->chan.ops = &pppoe_chan_ops;
+ po->chan.direct_xmit = true;
error = ppp_register_net_channel(dev_net(dev), &po->chan);
if (error) {
@@ -807,11 +810,12 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd,
/* Check that the socket referenced by the address
actually exists. */
- relay_po = get_item_by_addr(sock_net(sk), &po->pppoe_relay);
+ rcu_read_lock();
+ relay_po = __get_item_by_addr(sock_net(sk), &po->pppoe_relay);
+ rcu_read_unlock();
if (!relay_po)
break;
- sock_put(sk_pppox(relay_po));
sk->sk_state |= PPPOX_RELAY;
err = 0;
break;
@@ -877,7 +881,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
skb->dev = dev;
- skb->priority = sk->sk_priority;
+ skb->priority = READ_ONCE(sk->sk_priority);
skb->protocol = cpu_to_be16(ETH_P_PPP_SES);
ph = skb_put(skb, total_len + sizeof(struct pppoe_hdr));
@@ -968,7 +972,7 @@ abort:
***********************************************************************/
static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
- struct sock *sk = (struct sock *)chan->private;
+ struct sock *sk = chan->private;
return __pppoe_xmit(sk, skb);
}
@@ -976,7 +980,7 @@ static int pppoe_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path *path,
const struct ppp_channel *chan)
{
- struct sock *sk = (struct sock *)chan->private;
+ struct sock *sk = chan->private;
struct pppox_sock *po = pppox_sk(sk);
struct net_device *dev = po->pppoe_dev;
@@ -1007,26 +1011,21 @@ static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
struct sk_buff *skb;
int error = 0;
- if (sk->sk_state & PPPOX_BOUND) {
- error = -EIO;
- goto end;
- }
+ if (sk->sk_state & PPPOX_BOUND)
+ return -EIO;
skb = skb_recv_datagram(sk, flags, &error);
- if (error < 0)
- goto end;
+ if (!skb)
+ return error;
- if (skb) {
- total_len = min_t(size_t, total_len, skb->len);
- error = skb_copy_datagram_msg(skb, 0, m, total_len);
- if (error == 0) {
- consume_skb(skb);
- return total_len;
- }
+ total_len = min_t(size_t, total_len, skb->len);
+ error = skb_copy_datagram_msg(skb, 0, m, total_len);
+ if (error == 0) {
+ consume_skb(skb);
+ return total_len;
}
kfree_skb(skb);
-end:
return error;
}
@@ -1056,11 +1055,11 @@ static inline struct pppox_sock *pppoe_get_idx(struct pppoe_net *pn, loff_t pos)
int i;
for (i = 0; i < PPPOE_HASH_SIZE; i++) {
- po = pn->hash_table[i];
+ po = rcu_dereference(pn->hash_table[i]);
while (po) {
if (!pos--)
goto out;
- po = po->next;
+ po = rcu_dereference(po->next);
}
}
@@ -1069,19 +1068,19 @@ out:
}
static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(pn->hash_lock)
+ __acquires(RCU)
{
struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq));
loff_t l = *pos;
- read_lock_bh(&pn->hash_lock);
+ rcu_read_lock();
return l ? pppoe_get_idx(pn, --l) : SEQ_START_TOKEN;
}
static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq));
- struct pppox_sock *po;
+ struct pppox_sock *po, *next;
++*pos;
if (v == SEQ_START_TOKEN) {
@@ -1089,14 +1088,15 @@ static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
goto out;
}
po = v;
- if (po->next)
- po = po->next;
+ next = rcu_dereference(po->next);
+ if (next)
+ po = next;
else {
int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
po = NULL;
while (++hash < PPPOE_HASH_SIZE) {
- po = pn->hash_table[hash];
+ po = rcu_dereference(pn->hash_table[hash]);
if (po)
break;
}
@@ -1107,10 +1107,9 @@ out:
}
static void pppoe_seq_stop(struct seq_file *seq, void *v)
- __releases(pn->hash_lock)
+ __releases(RCU)
{
- struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq));
- read_unlock_bh(&pn->hash_lock);
+ rcu_read_unlock();
}
static const struct seq_operations pppoe_seq_ops = {
@@ -1153,7 +1152,7 @@ static __net_init int pppoe_init_net(struct net *net)
struct pppoe_net *pn = pppoe_pernet(net);
struct proc_dir_entry *pde;
- rwlock_init(&pn->hash_lock);
+ spin_lock_init(&pn->hash_lock);
pde = proc_create_net("pppoe", 0444, net->proc_net,
&pppoe_seq_ops, sizeof(struct seq_net_private));
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 0fe78826c8fa..b18acd810561 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -24,6 +24,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/rcupdate.h>
+#include <linux/security.h>
#include <linux/spinlock.h>
#include <net/sock.h>
@@ -128,9 +129,26 @@ static void del_chan(struct pppox_sock *sock)
spin_unlock(&chan_lock);
}
+static struct rtable *pptp_route_output(const struct pppox_sock *po,
+ struct flowi4 *fl4)
+{
+ const struct sock *sk = &po->sk;
+ struct net *net;
+
+ net = sock_net(sk);
+ flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, 0,
+ RT_SCOPE_UNIVERSE, IPPROTO_GRE, 0,
+ po->proto.pptp.dst_addr.sin_addr.s_addr,
+ po->proto.pptp.src_addr.sin_addr.s_addr,
+ 0, 0, sock_net_uid(net, sk));
+ security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4));
+
+ return ip_route_output_flow(net, fl4, sk);
+}
+
static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
- struct sock *sk = (struct sock *) chan->private;
+ struct sock *sk = chan->private;
struct pppox_sock *po = pppox_sk(sk);
struct net *net = sock_net(sk);
struct pptp_opt *opt = &po->proto.pptp;
@@ -141,23 +159,17 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
int len;
unsigned char *data;
__u32 seq_recv;
-
-
struct rtable *rt;
struct net_device *tdev;
struct iphdr *iph;
int max_headroom;
if (sk_pppox(po)->sk_state & PPPOX_DEAD)
- goto tx_error;
+ goto tx_drop;
- rt = ip_route_output_ports(net, &fl4, NULL,
- opt->dst_addr.sin_addr.s_addr,
- opt->src_addr.sin_addr.s_addr,
- 0, 0, IPPROTO_GRE,
- RT_TOS(0), sk->sk_bound_dev_if);
+ rt = pptp_route_output(po, &fl4);
if (IS_ERR(rt))
- goto tx_error;
+ goto tx_drop;
tdev = rt->dst.dev;
@@ -165,16 +177,20 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
- if (!new_skb) {
- ip_rt_put(rt);
+
+ if (!new_skb)
goto tx_error;
- }
+
if (skb->sk)
skb_set_owner_w(new_skb, skb->sk);
consume_skb(skb);
skb = new_skb;
}
+ /* Ensure we can safely access protocol field and LCP code */
+ if (!pskb_may_pull(skb, 3))
+ goto tx_error;
+
data = skb->data;
islcp = ((data[0] << 8) + data[1]) == PPP_LCP && 1 <= data[2] && data[2] <= 7;
@@ -248,6 +264,8 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
return 1;
tx_error:
+ ip_rt_put(rt);
+tx_drop:
kfree_skb(skb);
return 1;
}
@@ -364,8 +382,8 @@ drop:
return NET_RX_DROP;
}
-static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len)
+static int pptp_bind(struct socket *sock, struct sockaddr_unsized *uservaddr,
+ int sockaddr_len)
{
struct sock *sk = sock->sk;
struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
@@ -397,8 +415,8 @@ out:
return error;
}
-static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags)
+static int pptp_connect(struct socket *sock, struct sockaddr_unsized *uservaddr,
+ int sockaddr_len, int flags)
{
struct sock *sk = sock->sk;
struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
@@ -438,12 +456,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.private = sk;
po->chan.ops = &pptp_chan_ops;
- rt = ip_route_output_ports(sock_net(sk), &fl4, sk,
- opt->dst_addr.sin_addr.s_addr,
- opt->src_addr.sin_addr.s_addr,
- 0, 0,
- IPPROTO_GRE, RT_CONN_FLAGS(sk),
- sk->sk_bound_dev_if);
+ rt = pptp_route_output(po, &fl4);
if (IS_ERR(rt)) {
error = -EHOSTUNREACH;
goto end;
@@ -456,6 +469,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.mtu -= PPTP_HEADER_OVERHEAD;
po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
+ po->chan.direct_xmit = true;
error = ppp_register_channel(&po->chan);
if (error) {
pr_err("PPTP: failed to register PPP channel (%d)\n", error);
@@ -566,7 +580,7 @@ out:
static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
unsigned long arg)
{
- struct sock *sk = (struct sock *) chan->private;
+ struct sock *sk = chan->private;
struct pppox_sock *po = pppox_sk(sk);
struct pptp_opt *opt = &po->proto.pptp;
void __user *argp = (void __user *)arg;
@@ -685,6 +699,6 @@ module_init(pptp_init_module);
module_exit(pptp_exit_module);
MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol");
-MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_AUTHOR("D. Kozlov <xeb@mail.ru>");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_PPTP);