Commit 50f35158 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client

* git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client:
  libceph: Create a new key type "ceph".
  libceph: Get secret from the kernel keys api when mounting with key=NAME.
  ceph: Move secret key parsing earlier.
  libceph: fix null dereference when unregistering linger requests
  ceph: unlock on error in ceph_osdc_start_request()
  ceph: fix possible NULL pointer dereference
  ceph: flush msgr_wq during mds_client shutdown
parents 6aba74f2 4b2a58ab
...@@ -3215,9 +3215,15 @@ void ceph_mdsc_destroy(struct ceph_fs_client *fsc) ...@@ -3215,9 +3215,15 @@ void ceph_mdsc_destroy(struct ceph_fs_client *fsc)
{ {
struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_client *mdsc = fsc->mdsc;
dout("mdsc_destroy %p\n", mdsc);
ceph_mdsc_stop(mdsc); ceph_mdsc_stop(mdsc);
/* flush out any connection work with references to us */
ceph_msgr_flush();
fsc->mdsc = NULL; fsc->mdsc = NULL;
kfree(mdsc); kfree(mdsc);
dout("mdsc_destroy %p done\n", mdsc);
} }
......
...@@ -353,7 +353,7 @@ static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -353,7 +353,7 @@ static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
if (opt->name) if (opt->name)
seq_printf(m, ",name=%s", opt->name); seq_printf(m, ",name=%s", opt->name);
if (opt->secret) if (opt->key)
seq_puts(m, ",secret=<hidden>"); seq_puts(m, ",secret=<hidden>");
if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
......
#ifndef _KEYS_CEPH_TYPE_H
#define _KEYS_CEPH_TYPE_H
#include <linux/key.h>
extern struct key_type key_type_ceph;
#endif
...@@ -67,12 +67,12 @@ struct ceph_auth_client { ...@@ -67,12 +67,12 @@ struct ceph_auth_client {
bool negotiating; /* true if negotiating protocol */ bool negotiating; /* true if negotiating protocol */
const char *name; /* entity name */ const char *name; /* entity name */
u64 global_id; /* our unique id in system */ u64 global_id; /* our unique id in system */
const char *secret; /* our secret key */ const struct ceph_crypto_key *key; /* our secret key */
unsigned want_keys; /* which services we want */ unsigned want_keys; /* which services we want */
}; };
extern struct ceph_auth_client *ceph_auth_init(const char *name, extern struct ceph_auth_client *ceph_auth_init(const char *name,
const char *secret); const struct ceph_crypto_key *key);
extern void ceph_auth_destroy(struct ceph_auth_client *ac); extern void ceph_auth_destroy(struct ceph_auth_client *ac);
extern void ceph_auth_reset(struct ceph_auth_client *ac); extern void ceph_auth_reset(struct ceph_auth_client *ac);
......
...@@ -61,7 +61,7 @@ struct ceph_options { ...@@ -61,7 +61,7 @@ struct ceph_options {
pointer type of args */ pointer type of args */
int num_mon; int num_mon;
char *name; char *name;
char *secret; struct ceph_crypto_key *key;
}; };
/* /*
......
...@@ -4,6 +4,7 @@ config CEPH_LIB ...@@ -4,6 +4,7 @@ config CEPH_LIB
select LIBCRC32C select LIBCRC32C
select CRYPTO_AES select CRYPTO_AES
select CRYPTO select CRYPTO
select KEYS
default n default n
help help
Choose Y or M here to include cephlib, which provides the Choose Y or M here to include cephlib, which provides the
......
...@@ -35,12 +35,12 @@ static int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol) ...@@ -35,12 +35,12 @@ static int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol)
/* /*
* setup, teardown. * 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; struct ceph_auth_client *ac;
int ret; int ret;
dout("auth_init name '%s' secret '%s'\n", name, secret); dout("auth_init name '%s'\n", name);
ret = -ENOMEM; ret = -ENOMEM;
ac = kzalloc(sizeof(*ac), GFP_NOFS); ac = kzalloc(sizeof(*ac), GFP_NOFS);
...@@ -52,8 +52,8 @@ struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret) ...@@ -52,8 +52,8 @@ struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
ac->name = name; ac->name = name;
else else
ac->name = CEPH_AUTH_NAME_DEFAULT; ac->name = CEPH_AUTH_NAME_DEFAULT;
dout("auth_init name %s secret %s\n", ac->name, secret); dout("auth_init name %s\n", ac->name);
ac->secret = secret; ac->key = key;
return ac; return ac;
out: out:
......
...@@ -662,14 +662,16 @@ int ceph_x_init(struct ceph_auth_client *ac) ...@@ -662,14 +662,16 @@ int ceph_x_init(struct ceph_auth_client *ac)
goto out; goto out;
ret = -EINVAL; ret = -EINVAL;
if (!ac->secret) { if (!ac->key) {
pr_err("no secret set (for auth_x protocol)\n"); pr_err("no secret set (for auth_x protocol)\n");
goto out_nomem; goto out_nomem;
} }
ret = ceph_crypto_key_unarmor(&xi->secret, ac->secret); ret = ceph_crypto_key_clone(&xi->secret, ac->key);
if (ret) if (ret < 0) {
pr_err("cannot clone key: %d\n", ret);
goto out_nomem; goto out_nomem;
}
xi->starting = true; xi->starting = true;
xi->ticket_handlers = RB_ROOT; xi->ticket_handlers = RB_ROOT;
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/key.h>
#include <keys/ceph-type.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/parser.h> #include <linux/parser.h>
...@@ -20,6 +22,7 @@ ...@@ -20,6 +22,7 @@
#include <linux/ceph/decode.h> #include <linux/ceph/decode.h>
#include <linux/ceph/mon_client.h> #include <linux/ceph/mon_client.h>
#include <linux/ceph/auth.h> #include <linux/ceph/auth.h>
#include "crypto.h"
...@@ -117,9 +120,29 @@ int ceph_compare_options(struct ceph_options *new_opt, ...@@ -117,9 +120,29 @@ int ceph_compare_options(struct ceph_options *new_opt,
if (ret) if (ret)
return ret; return ret;
ret = strcmp_null(opt1->secret, opt2->secret); 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) if (ret)
return ret; return ret;
}
}
/* any matching mon ip implies a match */ /* any matching mon ip implies a match */
for (i = 0; i < opt1->num_mon; i++) { for (i = 0; i < opt1->num_mon; i++) {
...@@ -176,6 +199,7 @@ enum { ...@@ -176,6 +199,7 @@ enum {
Opt_fsid, Opt_fsid,
Opt_name, Opt_name,
Opt_secret, Opt_secret,
Opt_key,
Opt_ip, Opt_ip,
Opt_last_string, Opt_last_string,
/* string args above */ /* string args above */
...@@ -192,6 +216,7 @@ static match_table_t opt_tokens = { ...@@ -192,6 +216,7 @@ static match_table_t opt_tokens = {
{Opt_fsid, "fsid=%s"}, {Opt_fsid, "fsid=%s"},
{Opt_name, "name=%s"}, {Opt_name, "name=%s"},
{Opt_secret, "secret=%s"}, {Opt_secret, "secret=%s"},
{Opt_key, "key=%s"},
{Opt_ip, "ip=%s"}, {Opt_ip, "ip=%s"},
/* string args above */ /* string args above */
{Opt_noshare, "noshare"}, {Opt_noshare, "noshare"},
...@@ -203,11 +228,56 @@ void ceph_destroy_options(struct ceph_options *opt) ...@@ -203,11 +228,56 @@ void ceph_destroy_options(struct ceph_options *opt)
{ {
dout("destroy_options %p\n", opt); dout("destroy_options %p\n", opt);
kfree(opt->name); kfree(opt->name);
kfree(opt->secret); if (opt->key) {
ceph_crypto_key_destroy(opt->key);
kfree(opt->key);
}
kfree(opt); kfree(opt);
} }
EXPORT_SYMBOL(ceph_destroy_options); 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, int ceph_parse_options(struct ceph_options **popt, char *options,
const char *dev_name, const char *dev_name_end, const char *dev_name, const char *dev_name_end,
int (*parse_extra_token)(char *c, void *private), int (*parse_extra_token)(char *c, void *private),
...@@ -295,9 +365,24 @@ int ceph_parse_options(struct ceph_options **popt, char *options, ...@@ -295,9 +365,24 @@ int ceph_parse_options(struct ceph_options **popt, char *options,
GFP_KERNEL); GFP_KERNEL);
break; break;
case Opt_secret: case Opt_secret:
opt->secret = kstrndup(argstr[0].from, opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
argstr[0].to-argstr[0].from, if (!opt->key) {
GFP_KERNEL); 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; break;
/* misc */ /* misc */
...@@ -394,8 +479,8 @@ void ceph_destroy_client(struct ceph_client *client) ...@@ -394,8 +479,8 @@ void ceph_destroy_client(struct ceph_client *client)
ceph_osdc_stop(&client->osdc); ceph_osdc_stop(&client->osdc);
/* /*
* make sure mds and osd connections close out before destroying * make sure osd connections close out before destroying the
* the auth module, which is needed to free those connections' * auth module, which is needed to free those connections'
* ceph_authorizers. * ceph_authorizers.
*/ */
ceph_msgr_flush(); ceph_msgr_flush();
...@@ -496,10 +581,14 @@ static int __init init_ceph_lib(void) ...@@ -496,10 +581,14 @@ static int __init init_ceph_lib(void)
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = ceph_msgr_init(); ret = ceph_crypto_init();
if (ret < 0) if (ret < 0)
goto out_debugfs; 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", pr_info("loaded (mon/osd proto %d/%d, osdmap %d/%d %d/%d)\n",
CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL, CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL,
CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT, CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT,
...@@ -507,6 +596,8 @@ static int __init init_ceph_lib(void) ...@@ -507,6 +596,8 @@ static int __init init_ceph_lib(void)
return 0; return 0;
out_crypto:
ceph_crypto_shutdown();
out_debugfs: out_debugfs:
ceph_debugfs_cleanup(); ceph_debugfs_cleanup();
out: out:
...@@ -517,6 +608,7 @@ static void __exit exit_ceph_lib(void) ...@@ -517,6 +608,7 @@ static void __exit exit_ceph_lib(void)
{ {
dout("exit_ceph_lib\n"); dout("exit_ceph_lib\n");
ceph_msgr_exit(); ceph_msgr_exit();
ceph_crypto_shutdown();
ceph_debugfs_cleanup(); ceph_debugfs_cleanup();
} }
......
...@@ -5,10 +5,23 @@ ...@@ -5,10 +5,23 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include <linux/key-type.h>
#include <keys/ceph-type.h>
#include <linux/ceph/decode.h> #include <linux/ceph/decode.h>
#include "crypto.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) int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
{ {
if (*p + sizeof(u16) + sizeof(key->created) + 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, ...@@ -410,3 +423,63 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
return -EINVAL; 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);
}
...@@ -19,6 +19,8 @@ static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key) ...@@ -19,6 +19,8 @@ static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
kfree(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, extern int ceph_crypto_key_encode(struct ceph_crypto_key *key,
void **p, void *end); void **p, void *end);
extern int ceph_crypto_key_decode(struct ceph_crypto_key *key, extern int ceph_crypto_key_decode(struct ceph_crypto_key *key,
...@@ -40,6 +42,8 @@ extern int ceph_encrypt2(struct ceph_crypto_key *secret, ...@@ -40,6 +42,8 @@ extern int ceph_encrypt2(struct ceph_crypto_key *secret,
void *dst, size_t *dst_len, void *dst, size_t *dst_len,
const void *src1, size_t src1_len, const void *src1, size_t src1_len,
const void *src2, size_t src2_len); const void *src2, size_t src2_len);
extern int ceph_crypto_init(void);
extern void ceph_crypto_shutdown(void);
/* armor.c */ /* armor.c */
extern int ceph_armor(char *dst, const char *src, const char *end); extern int ceph_armor(char *dst, const char *src, const char *end);
......
...@@ -759,7 +759,7 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl) ...@@ -759,7 +759,7 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
/* authentication */ /* authentication */
monc->auth = ceph_auth_init(cl->options->name, monc->auth = ceph_auth_init(cl->options->name,
cl->options->secret); cl->options->key);
if (IS_ERR(monc->auth)) if (IS_ERR(monc->auth))
return PTR_ERR(monc->auth); return PTR_ERR(monc->auth);
monc->auth->want_keys = monc->auth->want_keys =
......
...@@ -837,8 +837,7 @@ static void __unregister_request(struct ceph_osd_client *osdc, ...@@ -837,8 +837,7 @@ static void __unregister_request(struct ceph_osd_client *osdc,
dout("moving osd to %p lru\n", req->r_osd); dout("moving osd to %p lru\n", req->r_osd);
__move_osd_to_lru(osdc, req->r_osd); __move_osd_to_lru(osdc, req->r_osd);
} }
if (list_empty(&req->r_osd_item) && if (list_empty(&req->r_linger_item))
list_empty(&req->r_linger_item))
req->r_osd = NULL; req->r_osd = NULL;
} }
...@@ -883,6 +882,7 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc, ...@@ -883,6 +882,7 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc,
dout("moving osd to %p lru\n", req->r_osd); dout("moving osd to %p lru\n", req->r_osd);
__move_osd_to_lru(osdc, req->r_osd); __move_osd_to_lru(osdc, req->r_osd);
} }
if (list_empty(&req->r_osd_item))
req->r_osd = NULL; req->r_osd = NULL;
} }
} }
...@@ -1602,11 +1602,11 @@ void handle_watch_notify(struct ceph_osd_client *osdc, struct ceph_msg *msg) ...@@ -1602,11 +1602,11 @@ void handle_watch_notify(struct ceph_osd_client *osdc, struct ceph_msg *msg)
cookie, ver, event); cookie, ver, event);
if (event) { if (event) {
event_work = kmalloc(sizeof(*event_work), GFP_NOIO); event_work = kmalloc(sizeof(*event_work), GFP_NOIO);
INIT_WORK(&event_work->work, do_event_work);
if (!event_work) { if (!event_work) {
dout("ERROR: could not allocate event_work\n"); dout("ERROR: could not allocate event_work\n");
goto done_err; goto done_err;
} }
INIT_WORK(&event_work->work, do_event_work);
event_work->event = event; event_work->event = event;
event_work->ver = ver; event_work->ver = ver;
event_work->notify_id = notify_id; event_work->notify_id = notify_id;
...@@ -1672,7 +1672,7 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc, ...@@ -1672,7 +1672,7 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
if (req->r_sent == 0) { if (req->r_sent == 0) {
rc = __map_request(osdc, req); rc = __map_request(osdc, req);
if (rc < 0) if (rc < 0)
return rc; goto out_unlock;
if (req->r_osd == NULL) { if (req->r_osd == NULL) {
dout("send_request %p no up osds in pg\n", req); dout("send_request %p no up osds in pg\n", req);
ceph_monc_request_next_osdmap(&osdc->client->monc); ceph_monc_request_next_osdmap(&osdc->client->monc);
...@@ -1689,6 +1689,8 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc, ...@@ -1689,6 +1689,8 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
} }
} }
} }
out_unlock:
mutex_unlock(&osdc->request_mutex); mutex_unlock(&osdc->request_mutex);
up_read(&osdc->map_sem); up_read(&osdc->map_sem);
return rc; return rc;
......
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