summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/appletalk/ddp.c11
-rw-r--r--net/atm/common.c1
-rw-r--r--net/bridge/br_multicast.c2
-rw-r--r--net/bridge/br_stp_if.c2
-rw-r--r--net/ceph/Kconfig1
-rw-r--r--net/ceph/auth.c8
-rw-r--r--net/ceph/auth_x.c8
-rw-r--r--net/ceph/ceph_common.c112
-rw-r--r--net/ceph/crypto.c73
-rw-r--r--net/ceph/crypto.h4
-rw-r--r--net/ceph/mon_client.c2
-rw-r--r--net/ceph/osd_client.c12
-rw-r--r--net/core/dev.c24
-rw-r--r--net/ipv4/arp.c3
-rw-r--r--net/ipv4/fib_frontend.c2
-rw-r--r--net/ipv6/ndisc.c2
-rw-r--r--net/sctp/protocol.c4
17 files changed, 237 insertions, 34 deletions
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 206e771e82d1..956a5302002a 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1051,16 +1051,17 @@ static int atalk_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- sock_hold(sk);
- lock_sock(sk);
if (sk) {
+ sock_hold(sk);
+ lock_sock(sk);
+
sock_orphan(sk);
sock->sk = NULL;
atalk_destroy_socket(sk);
- }
- release_sock(sk);
- sock_put(sk);
+ release_sock(sk);
+ sock_put(sk);
+ }
return 0;
}
diff --git a/net/atm/common.c b/net/atm/common.c
index 1b9c52a02cd3..22b963d06a10 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -252,6 +252,7 @@ void atm_dev_release_vccs(struct atm_dev *dev)
}
write_unlock_irq(&vcc_sklist_lock);
}
+EXPORT_SYMBOL(atm_dev_release_vccs);
static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
{
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index f61eb2eff3fd..59660c909a7c 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1475,7 +1475,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
ip6h->payload_len == 0)
return 0;
- len = ntohs(ip6h->payload_len);
+ len = ntohs(ip6h->payload_len) + sizeof(*ip6h);
if (skb->len < len)
return -EINVAL;
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 5593f5aec942..9b61d09de9b9 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -213,7 +213,7 @@ bool br_stp_recalculate_bridge_id(struct net_bridge *br)
/* user has chosen a value so keep it */
if (br->flags & BR_SET_MAC_ADDR)
- return;
+ return false;
list_for_each_entry(p, &br->port_list, list) {
if (addr == br_mac_zero ||
diff --git a/net/ceph/Kconfig b/net/ceph/Kconfig
index ad424049b0cf..be683f2d401f 100644
--- a/net/ceph/Kconfig
+++ b/net/ceph/Kconfig
@@ -4,6 +4,7 @@ config CEPH_LIB
select LIBCRC32C
select CRYPTO_AES
select CRYPTO
+ select KEYS
default n
help
Choose Y or M here to include cephlib, which provides the
diff --git a/net/ceph/auth.c b/net/ceph/auth.c
index 549c1f43e1d5..b4bf4ac090f1 100644
--- a/net/ceph/auth.c
+++ b/net/ceph/auth.c
@@ -35,12 +35,12 @@ static int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol)
/*
* setup, teardown.
*/
-struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
+struct ceph_auth_client *ceph_auth_init(const char *name, const struct ceph_crypto_key *key)
{
struct ceph_auth_client *ac;
int ret;
- dout("auth_init name '%s' secret '%s'\n", name, secret);
+ dout("auth_init name '%s'\n", name);
ret = -ENOMEM;
ac = kzalloc(sizeof(*ac), GFP_NOFS);
@@ -52,8 +52,8 @@ struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
ac->name = name;
else
ac->name = CEPH_AUTH_NAME_DEFAULT;
- dout("auth_init name %s secret %s\n", ac->name, secret);
- ac->secret = secret;
+ dout("auth_init name %s\n", ac->name);
+ ac->key = key;
return ac;
out:
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
index 7fd5dfcf6e18..1587dc6010c6 100644
--- a/net/ceph/auth_x.c
+++ b/net/ceph/auth_x.c
@@ -662,14 +662,16 @@ int ceph_x_init(struct ceph_auth_client *ac)
goto out;
ret = -EINVAL;
- if (!ac->secret) {
+ if (!ac->key) {
pr_err("no secret set (for auth_x protocol)\n");
goto out_nomem;
}
- ret = ceph_crypto_key_unarmor(&xi->secret, ac->secret);
- if (ret)
+ ret = ceph_crypto_key_clone(&xi->secret, ac->key);
+ if (ret < 0) {
+ pr_err("cannot clone key: %d\n", ret);
goto out_nomem;
+ }
xi->starting = true;
xi->ticket_handlers = RB_ROOT;
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 95f96ab94bba..132963abc266 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -5,6 +5,8 @@
#include <linux/fs.h>
#include <linux/inet.h>
#include <linux/in6.h>
+#include <linux/key.h>
+#include <keys/ceph-type.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/parser.h>
@@ -20,6 +22,7 @@
#include <linux/ceph/decode.h>
#include <linux/ceph/mon_client.h>
#include <linux/ceph/auth.h>
+#include "crypto.h"
@@ -117,9 +120,29 @@ int ceph_compare_options(struct ceph_options *new_opt,
if (ret)
return ret;
- ret = strcmp_null(opt1->secret, opt2->secret);
- if (ret)
- return ret;
+ if (opt1->key && !opt2->key)
+ return -1;
+ if (!opt1->key && opt2->key)
+ return 1;
+ if (opt1->key && opt2->key) {
+ if (opt1->key->type != opt2->key->type)
+ return -1;
+ if (opt1->key->created.tv_sec != opt2->key->created.tv_sec)
+ return -1;
+ if (opt1->key->created.tv_nsec != opt2->key->created.tv_nsec)
+ return -1;
+ if (opt1->key->len != opt2->key->len)
+ return -1;
+ if (opt1->key->key && !opt2->key->key)
+ return -1;
+ if (!opt1->key->key && opt2->key->key)
+ return 1;
+ if (opt1->key->key && opt2->key->key) {
+ ret = memcmp(opt1->key->key, opt2->key->key, opt1->key->len);
+ if (ret)
+ return ret;
+ }
+ }
/* any matching mon ip implies a match */
for (i = 0; i < opt1->num_mon; i++) {
@@ -176,6 +199,7 @@ enum {
Opt_fsid,
Opt_name,
Opt_secret,
+ Opt_key,
Opt_ip,
Opt_last_string,
/* string args above */
@@ -192,6 +216,7 @@ static match_table_t opt_tokens = {
{Opt_fsid, "fsid=%s"},
{Opt_name, "name=%s"},
{Opt_secret, "secret=%s"},
+ {Opt_key, "key=%s"},
{Opt_ip, "ip=%s"},
/* string args above */
{Opt_noshare, "noshare"},
@@ -203,11 +228,56 @@ void ceph_destroy_options(struct ceph_options *opt)
{
dout("destroy_options %p\n", opt);
kfree(opt->name);
- kfree(opt->secret);
+ if (opt->key) {
+ ceph_crypto_key_destroy(opt->key);
+ kfree(opt->key);
+ }
kfree(opt);
}
EXPORT_SYMBOL(ceph_destroy_options);
+/* get secret from key store */
+static int get_secret(struct ceph_crypto_key *dst, const char *name) {
+ struct key *ukey;
+ int key_err;
+ int err = 0;
+ struct ceph_crypto_key *ckey;
+
+ ukey = request_key(&key_type_ceph, name, NULL);
+ if (!ukey || IS_ERR(ukey)) {
+ /* request_key errors don't map nicely to mount(2)
+ errors; don't even try, but still printk */
+ key_err = PTR_ERR(ukey);
+ switch (key_err) {
+ case -ENOKEY:
+ pr_warning("ceph: Mount failed due to key not found: %s\n", name);
+ break;
+ case -EKEYEXPIRED:
+ pr_warning("ceph: Mount failed due to expired key: %s\n", name);
+ break;
+ case -EKEYREVOKED:
+ pr_warning("ceph: Mount failed due to revoked key: %s\n", name);
+ break;
+ default:
+ pr_warning("ceph: Mount failed due to unknown key error"
+ " %d: %s\n", key_err, name);
+ }
+ err = -EPERM;
+ goto out;
+ }
+
+ ckey = ukey->payload.data;
+ err = ceph_crypto_key_clone(dst, ckey);
+ if (err)
+ goto out_key;
+ /* pass through, err is 0 */
+
+out_key:
+ key_put(ukey);
+out:
+ return err;
+}
+
int ceph_parse_options(struct ceph_options **popt, char *options,
const char *dev_name, const char *dev_name_end,
int (*parse_extra_token)(char *c, void *private),
@@ -295,9 +365,24 @@ int ceph_parse_options(struct ceph_options **popt, char *options,
GFP_KERNEL);
break;
case Opt_secret:
- opt->secret = kstrndup(argstr[0].from,
- argstr[0].to-argstr[0].from,
- GFP_KERNEL);
+ opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
+ if (!opt->key) {
+ err = -ENOMEM;
+ goto out;
+ }
+ err = ceph_crypto_key_unarmor(opt->key, argstr[0].from);
+ if (err < 0)
+ goto out;
+ break;
+ case Opt_key:
+ opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
+ if (!opt->key) {
+ err = -ENOMEM;
+ goto out;
+ }
+ err = get_secret(opt->key, argstr[0].from);
+ if (err < 0)
+ goto out;
break;
/* misc */
@@ -394,8 +479,8 @@ void ceph_destroy_client(struct ceph_client *client)
ceph_osdc_stop(&client->osdc);
/*
- * make sure mds and osd connections close out before destroying
- * the auth module, which is needed to free those connections'
+ * make sure osd connections close out before destroying the
+ * auth module, which is needed to free those connections'
* ceph_authorizers.
*/
ceph_msgr_flush();
@@ -496,10 +581,14 @@ static int __init init_ceph_lib(void)
if (ret < 0)
goto out;
- ret = ceph_msgr_init();
+ ret = ceph_crypto_init();
if (ret < 0)
goto out_debugfs;
+ ret = ceph_msgr_init();
+ if (ret < 0)
+ goto out_crypto;
+
pr_info("loaded (mon/osd proto %d/%d, osdmap %d/%d %d/%d)\n",
CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL,
CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT,
@@ -507,6 +596,8 @@ static int __init init_ceph_lib(void)
return 0;
+out_crypto:
+ ceph_crypto_shutdown();
out_debugfs:
ceph_debugfs_cleanup();
out:
@@ -517,6 +608,7 @@ static void __exit exit_ceph_lib(void)
{
dout("exit_ceph_lib\n");
ceph_msgr_exit();
+ ceph_crypto_shutdown();
ceph_debugfs_cleanup();
}
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
index 7b505b0c983f..5a8009c9e0cd 100644
--- a/net/ceph/crypto.c
+++ b/net/ceph/crypto.c
@@ -5,10 +5,23 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <crypto/hash.h>
+#include <linux/key-type.h>
+#include <keys/ceph-type.h>
#include <linux/ceph/decode.h>
#include "crypto.h"
+int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
+ const struct ceph_crypto_key *src)
+{
+ memcpy(dst, src, sizeof(struct ceph_crypto_key));
+ dst->key = kmalloc(src->len, GFP_NOFS);
+ if (!dst->key)
+ return -ENOMEM;
+ memcpy(dst->key, src->key, src->len);
+ return 0;
+}
+
int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
{
if (*p + sizeof(u16) + sizeof(key->created) +
@@ -410,3 +423,63 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
return -EINVAL;
}
}
+
+int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
+{
+ struct ceph_crypto_key *ckey;
+ int ret;
+ void *p;
+
+ ret = -EINVAL;
+ if (datalen <= 0 || datalen > 32767 || !data)
+ goto err;
+
+ ret = key_payload_reserve(key, datalen);
+ if (ret < 0)
+ goto err;
+
+ ret = -ENOMEM;
+ ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
+ if (!ckey)
+ goto err;
+
+ /* TODO ceph_crypto_key_decode should really take const input */
+ p = (void*)data;
+ ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
+ if (ret < 0)
+ goto err_ckey;
+
+ key->payload.data = ckey;
+ return 0;
+
+err_ckey:
+ kfree(ckey);
+err:
+ return ret;
+}
+
+int ceph_key_match(const struct key *key, const void *description)
+{
+ return strcmp(key->description, description) == 0;
+}
+
+void ceph_key_destroy(struct key *key) {
+ struct ceph_crypto_key *ckey = key->payload.data;
+
+ ceph_crypto_key_destroy(ckey);
+}
+
+struct key_type key_type_ceph = {
+ .name = "ceph",
+ .instantiate = ceph_key_instantiate,
+ .match = ceph_key_match,
+ .destroy = ceph_key_destroy,
+};
+
+int ceph_crypto_init(void) {
+ return register_key_type(&key_type_ceph);
+}
+
+void ceph_crypto_shutdown(void) {
+ unregister_key_type(&key_type_ceph);
+}
diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h
index f9eccace592b..1919d1550d75 100644
--- a/net/ceph/crypto.h
+++ b/net/ceph/crypto.h
@@ -19,6 +19,8 @@ static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
kfree(key->key);
}
+extern int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
+ const struct ceph_crypto_key *src);
extern int ceph_crypto_key_encode(struct ceph_crypto_key *key,
void **p, void *end);
extern int ceph_crypto_key_decode(struct ceph_crypto_key *key,
@@ -40,6 +42,8 @@ extern int ceph_encrypt2(struct ceph_crypto_key *secret,
void *dst, size_t *dst_len,
const void *src1, size_t src1_len,
const void *src2, size_t src2_len);
+extern int ceph_crypto_init(void);
+extern void ceph_crypto_shutdown(void);
/* armor.c */
extern int ceph_armor(char *dst, const char *src, const char *end);
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index 8a079399174a..cbe31fa45508 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -759,7 +759,7 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
/* authentication */
monc->auth = ceph_auth_init(cl->options->name,
- cl->options->secret);
+ cl->options->key);
if (IS_ERR(monc->auth))
return PTR_ERR(monc->auth);
monc->auth->want_keys =
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 02212ed50852..3b91d651fe08 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -837,8 +837,7 @@ static void __unregister_request(struct ceph_osd_client *osdc,
dout("moving osd to %p lru\n", req->r_osd);
__move_osd_to_lru(osdc, req->r_osd);
}
- if (list_empty(&req->r_osd_item) &&
- list_empty(&req->r_linger_item))
+ if (list_empty(&req->r_linger_item))
req->r_osd = NULL;
}
@@ -883,7 +882,8 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc,
dout("moving osd to %p lru\n", req->r_osd);
__move_osd_to_lru(osdc, req->r_osd);
}
- req->r_osd = NULL;
+ if (list_empty(&req->r_osd_item))
+ req->r_osd = NULL;
}
}
@@ -1602,11 +1602,11 @@ void handle_watch_notify(struct ceph_osd_client *osdc, struct ceph_msg *msg)
cookie, ver, event);
if (event) {
event_work = kmalloc(sizeof(*event_work), GFP_NOIO);
- INIT_WORK(&event_work->work, do_event_work);
if (!event_work) {
dout("ERROR: could not allocate event_work\n");
goto done_err;
}
+ INIT_WORK(&event_work->work, do_event_work);
event_work->event = event;
event_work->ver = ver;
event_work->notify_id = notify_id;
@@ -1672,7 +1672,7 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
if (req->r_sent == 0) {
rc = __map_request(osdc, req);
if (rc < 0)
- return rc;
+ goto out_unlock;
if (req->r_osd == NULL) {
dout("send_request %p no up osds in pg\n", req);
ceph_monc_request_next_osdmap(&osdc->client->monc);
@@ -1689,6 +1689,8 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
}
}
}
+
+out_unlock:
mutex_unlock(&osdc->request_mutex);
up_read(&osdc->map_sem);
return rc;
diff --git a/net/core/dev.c b/net/core/dev.c
index 563ddc28139d..3da9fb06d47a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1454,6 +1454,27 @@ static inline void net_timestamp_check(struct sk_buff *skb)
__net_timestamp(skb);
}
+static inline bool is_skb_forwardable(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ unsigned int len;
+
+ if (!(dev->flags & IFF_UP))
+ return false;
+
+ len = dev->mtu + dev->hard_header_len + VLAN_HLEN;
+ if (skb->len <= len)
+ return true;
+
+ /* if TSO is enabled, we don't care about the length as the packet
+ * could be forwarded without being segmented before
+ */
+ if (skb_is_gso(skb))
+ return true;
+
+ return false;
+}
+
/**
* dev_forward_skb - loopback an skb to another netif
*
@@ -1477,8 +1498,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
skb_orphan(skb);
nf_reset(skb);
- if (unlikely(!(dev->flags & IFF_UP) ||
- (skb->len > (dev->mtu + dev->hard_header_len + VLAN_HLEN)))) {
+ if (unlikely(!is_skb_forwardable(dev, skb))) {
atomic_long_inc(&dev->rx_dropped);
kfree_skb(skb);
return NET_RX_DROP;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 090d273d7865..1b74d3b64371 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -215,6 +215,9 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
case ARPHRD_INFINIBAND:
ip_ib_mc_map(addr, dev->broadcast, haddr);
return 0;
+ case ARPHRD_IPGRE:
+ ip_ipgre_mc_map(addr, dev->broadcast, haddr);
+ return 0;
default:
if (dir) {
memcpy(haddr, dev->broadcast, dev->addr_len);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index f116ce8f1b46..451088330bbb 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1068,6 +1068,7 @@ static void ip_fib_net_exit(struct net *net)
fib4_rules_exit(net);
#endif
+ rtnl_lock();
for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
struct fib_table *tb;
struct hlist_head *head;
@@ -1080,6 +1081,7 @@ static void ip_fib_net_exit(struct net *net)
fib_free_table(tb);
}
}
+ rtnl_unlock();
kfree(net->ipv4.fib_table_hash);
}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 0e49c9db3c98..92f952d093db 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -341,6 +341,8 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d
case ARPHRD_INFINIBAND:
ipv6_ib_mc_map(addr, dev->broadcast, buf);
return 0;
+ case ARPHRD_IPGRE:
+ return ipv6_ipgre_mc_map(addr, dev->broadcast, buf);
default:
if (dir) {
memcpy(buf, dev->broadcast, dev->addr_len);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 152976ec0b74..d5bf91d04f63 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1205,7 +1205,7 @@ SCTP_STATIC __init int sctp_init(void)
if ((sctp_assoc_hashsize > (64 * 1024)) && order > 0)
continue;
sctp_assoc_hashtable = (struct sctp_hashbucket *)
- __get_free_pages(GFP_ATOMIC, order);
+ __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, order);
} while (!sctp_assoc_hashtable && --order > 0);
if (!sctp_assoc_hashtable) {
pr_err("Failed association hash alloc\n");
@@ -1238,7 +1238,7 @@ SCTP_STATIC __init int sctp_init(void)
if ((sctp_port_hashsize > (64 * 1024)) && order > 0)
continue;
sctp_port_hashtable = (struct sctp_bind_hashbucket *)
- __get_free_pages(GFP_ATOMIC, order);
+ __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, order);
} while (!sctp_port_hashtable && --order > 0);
if (!sctp_port_hashtable) {
pr_err("Failed bind hash alloc\n");