libceph, ceph: implement msgr2.1 protocol (crc and secure modes)

Implement msgr2.1 wire protocol, available since nautilus 14.2.11
and octopus 15.2.5.  msgr2.0 wire protocol is not implemented -- it
has several security, integrity and robustness issues and therefore
considered deprecated.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Ilya Dryomov 2020-11-19 16:59:08 +01:00
parent 00498b9941
commit cd1a677cad
15 changed files with 4356 additions and 31 deletions

View File

@ -5014,7 +5014,7 @@ void ceph_mdsc_handle_mdsmap(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
return;
}
newmap = ceph_mdsmap_decode(&p, end, false);
newmap = ceph_mdsmap_decode(&p, end, ceph_msgr2(mdsc->fsc->client));
if (IS_ERR(newmap)) {
err = PTR_ERR(newmap);
goto bad_unlock;
@ -5196,6 +5196,80 @@ static int invalidate_authorizer(struct ceph_connection *con)
return ceph_monc_validate_auth(&mdsc->fsc->client->monc);
}
static int mds_get_auth_request(struct ceph_connection *con,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len)
{
struct ceph_mds_session *s = con->private;
struct ceph_auth_client *ac = s->s_mdsc->fsc->client->monc.auth;
struct ceph_auth_handshake *auth = &s->s_auth;
int ret;
ret = ceph_auth_get_authorizer(ac, auth, CEPH_ENTITY_TYPE_MDS,
buf, buf_len);
if (ret)
return ret;
*authorizer = auth->authorizer_buf;
*authorizer_len = auth->authorizer_buf_len;
return 0;
}
static int mds_handle_auth_reply_more(struct ceph_connection *con,
void *reply, int reply_len,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len)
{
struct ceph_mds_session *s = con->private;
struct ceph_auth_client *ac = s->s_mdsc->fsc->client->monc.auth;
struct ceph_auth_handshake *auth = &s->s_auth;
int ret;
ret = ceph_auth_handle_svc_reply_more(ac, auth, reply, reply_len,
buf, buf_len);
if (ret)
return ret;
*authorizer = auth->authorizer_buf;
*authorizer_len = auth->authorizer_buf_len;
return 0;
}
static int mds_handle_auth_done(struct ceph_connection *con,
u64 global_id, void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len)
{
struct ceph_mds_session *s = con->private;
struct ceph_auth_client *ac = s->s_mdsc->fsc->client->monc.auth;
struct ceph_auth_handshake *auth = &s->s_auth;
return ceph_auth_handle_svc_reply_done(ac, auth, reply, reply_len,
session_key, session_key_len,
con_secret, con_secret_len);
}
static int mds_handle_auth_bad_method(struct ceph_connection *con,
int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt)
{
struct ceph_mds_session *s = con->private;
struct ceph_mon_client *monc = &s->s_mdsc->fsc->client->monc;
int ret;
if (ceph_auth_handle_bad_authorizer(monc->auth, CEPH_ENTITY_TYPE_MDS,
used_proto, result,
allowed_protos, proto_cnt,
allowed_modes, mode_cnt)) {
ret = ceph_monc_validate_auth(monc);
if (ret)
return ret;
}
return -EACCES;
}
static struct ceph_msg *mds_alloc_msg(struct ceph_connection *con,
struct ceph_msg_header *hdr, int *skip)
{
@ -5245,6 +5319,10 @@ static const struct ceph_connection_operations mds_con_ops = {
.alloc_msg = mds_alloc_msg,
.sign_message = mds_sign_message,
.check_message_signature = mds_check_message_signature,
.get_auth_request = mds_get_auth_request,
.handle_auth_reply_more = mds_handle_auth_reply_more,
.handle_auth_done = mds_handle_auth_done,
.handle_auth_bad_method = mds_handle_auth_bad_method,
};
/* eof */

View File

@ -120,8 +120,12 @@ int ceph_auth_entity_name_encode(const char *name, void **p, void *end);
extern int ceph_build_auth(struct ceph_auth_client *ac,
void *msg_buf, size_t msg_len);
extern int ceph_auth_is_authenticated(struct ceph_auth_client *ac);
int __ceph_auth_get_authorizer(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
int peer_type, bool force_new,
int *proto, int *pref_mode, int *fallb_mode);
extern int ceph_auth_create_authorizer(struct ceph_auth_client *ac,
int peer_type,
struct ceph_auth_handshake *auth);
@ -157,4 +161,34 @@ int ceph_auth_check_message_signature(struct ceph_auth_handshake *auth,
return auth->check_message_signature(auth, msg);
return 0;
}
int ceph_auth_get_request(struct ceph_auth_client *ac, void *buf, int buf_len);
int ceph_auth_handle_reply_more(struct ceph_auth_client *ac, void *reply,
int reply_len, void *buf, int buf_len);
int ceph_auth_handle_reply_done(struct ceph_auth_client *ac,
u64 global_id, void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len);
bool ceph_auth_handle_bad_method(struct ceph_auth_client *ac,
int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt);
int ceph_auth_get_authorizer(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
int peer_type, void *buf, int *buf_len);
int ceph_auth_handle_svc_reply_more(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
void *reply, int reply_len,
void *buf, int *buf_len);
int ceph_auth_handle_svc_reply_done(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len);
bool ceph_auth_handle_bad_authorizer(struct ceph_auth_client *ac,
int peer_type, int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt);
#endif

View File

@ -93,6 +93,10 @@ struct ceph_dir_layout {
#define CEPH_AUTH_NONE 0x1
#define CEPH_AUTH_CEPHX 0x2
#define CEPH_AUTH_MODE_NONE 0
#define CEPH_AUTH_MODE_AUTHORIZER 1
#define CEPH_AUTH_MODE_MON 10
/* msgr2 protocol modes */
#define CEPH_CON_MODE_UNKNOWN 0x0
#define CEPH_CON_MODE_CRC 0x1

View File

@ -221,6 +221,7 @@ static inline void ceph_encode_timespec64(struct ceph_timespec *tv,
#define CEPH_ENTITY_ADDR_TYPE_NONE 0
#define CEPH_ENTITY_ADDR_TYPE_LEGACY __cpu_to_le32(1)
#define CEPH_ENTITY_ADDR_TYPE_MSGR2 __cpu_to_le32(2)
#define CEPH_ENTITY_ADDR_TYPE_ANY __cpu_to_le32(3)
static inline void ceph_encode_banner_addr(struct ceph_entity_addr *a)
{
@ -243,6 +244,9 @@ extern int ceph_decode_entity_addr(void **p, void *end,
int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
struct ceph_entity_addr *addr);
int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr);
void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr);
/*
* encoders
*/

View File

@ -31,10 +31,10 @@
#define CEPH_OPT_FSID (1<<0)
#define CEPH_OPT_NOSHARE (1<<1) /* don't share client with other sbs */
#define CEPH_OPT_MYIP (1<<2) /* specified my ip */
#define CEPH_OPT_NOCRC (1<<3) /* no data crc on writes */
#define CEPH_OPT_NOCRC (1<<3) /* no data crc on writes (msgr1) */
#define CEPH_OPT_NOMSGAUTH (1<<4) /* don't require msg signing feat */
#define CEPH_OPT_TCP_NODELAY (1<<5) /* TCP_NODELAY on TCP sockets */
#define CEPH_OPT_NOMSGSIGN (1<<6) /* don't sign msgs */
#define CEPH_OPT_NOMSGSIGN (1<<6) /* don't sign msgs (msgr1) */
#define CEPH_OPT_ABORT_ON_FULL (1<<7) /* abort w/ ENOSPC when full */
#define CEPH_OPT_DEFAULT (CEPH_OPT_TCP_NODELAY)
@ -84,6 +84,7 @@ struct ceph_options {
#define CEPH_MONC_HUNT_BACKOFF 2
#define CEPH_MONC_HUNT_MAX_MULT 10
#define CEPH_MSG_MAX_CONTROL_LEN (16*1024*1024)
#define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
#define CEPH_MSG_MAX_MIDDLE_LEN (16*1024*1024)
@ -152,6 +153,10 @@ struct ceph_client {
#define from_msgr(ms) container_of(ms, struct ceph_client, msgr)
static inline bool ceph_msgr2(struct ceph_client *client)
{
return client->options->con_modes[0] != CEPH_CON_MODE_UNKNOWN;
}
/*
* snapshots

View File

@ -3,6 +3,7 @@
#define __FS_CEPH_MESSENGER_H
#include <linux/bvec.h>
#include <linux/crypto.h>
#include <linux/kref.h>
#include <linux/mutex.h>
#include <linux/net.h>
@ -52,6 +53,23 @@ struct ceph_connection_operations {
int (*sign_message) (struct ceph_msg *msg);
int (*check_message_signature) (struct ceph_msg *msg);
/* msgr2 authentication exchange */
int (*get_auth_request)(struct ceph_connection *con,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len);
int (*handle_auth_reply_more)(struct ceph_connection *con,
void *reply, int reply_len,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len);
int (*handle_auth_done)(struct ceph_connection *con,
u64 global_id, void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len);
int (*handle_auth_bad_method)(struct ceph_connection *con,
int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt);
};
/* use format string %s%lld */
@ -246,8 +264,15 @@ struct ceph_msg {
#define CEPH_CON_S_PREOPEN 2
#define CEPH_CON_S_V1_BANNER 3
#define CEPH_CON_S_V1_CONNECT_MSG 4
#define CEPH_CON_S_OPEN 5
#define CEPH_CON_S_STANDBY 6
#define CEPH_CON_S_V2_BANNER_PREFIX 5
#define CEPH_CON_S_V2_BANNER_PAYLOAD 6
#define CEPH_CON_S_V2_HELLO 7
#define CEPH_CON_S_V2_AUTH 8
#define CEPH_CON_S_V2_AUTH_SIGNATURE 9
#define CEPH_CON_S_V2_SESSION_CONNECT 10
#define CEPH_CON_S_V2_SESSION_RECONNECT 11
#define CEPH_CON_S_OPEN 12
#define CEPH_CON_S_STANDBY 13
/*
* ceph_connection flag bits
@ -301,6 +326,99 @@ struct ceph_connection_v1_info {
u32 peer_global_seq; /* peer's global seq for this connection */
};
#define CEPH_CRC_LEN 4
#define CEPH_GCM_KEY_LEN 16
#define CEPH_GCM_IV_LEN sizeof(struct ceph_gcm_nonce)
#define CEPH_GCM_BLOCK_LEN 16
#define CEPH_GCM_TAG_LEN 16
#define CEPH_PREAMBLE_LEN 32
#define CEPH_PREAMBLE_INLINE_LEN 48
#define CEPH_PREAMBLE_PLAIN_LEN CEPH_PREAMBLE_LEN
#define CEPH_PREAMBLE_SECURE_LEN (CEPH_PREAMBLE_LEN + \
CEPH_PREAMBLE_INLINE_LEN + \
CEPH_GCM_TAG_LEN)
#define CEPH_EPILOGUE_PLAIN_LEN (1 + 3 * CEPH_CRC_LEN)
#define CEPH_EPILOGUE_SECURE_LEN (CEPH_GCM_BLOCK_LEN + CEPH_GCM_TAG_LEN)
#define CEPH_FRAME_MAX_SEGMENT_COUNT 4
struct ceph_frame_desc {
int fd_tag; /* FRAME_TAG_* */
int fd_seg_cnt;
int fd_lens[CEPH_FRAME_MAX_SEGMENT_COUNT]; /* logical */
int fd_aligns[CEPH_FRAME_MAX_SEGMENT_COUNT];
};
struct ceph_gcm_nonce {
__le32 fixed;
__le64 counter __packed;
};
struct ceph_connection_v2_info {
struct iov_iter in_iter;
struct kvec in_kvecs[5]; /* recvmsg */
struct bio_vec in_bvec; /* recvmsg (in_cursor) */
int in_kvec_cnt;
int in_state; /* IN_S_* */
struct iov_iter out_iter;
struct kvec out_kvecs[8]; /* sendmsg */
struct bio_vec out_bvec; /* sendpage (out_cursor, out_zero),
sendmsg (out_enc_pages) */
int out_kvec_cnt;
int out_state; /* OUT_S_* */
int out_zero; /* # of zero bytes to send */
bool out_iter_sendpage; /* use sendpage if possible */
struct ceph_frame_desc in_desc;
struct ceph_msg_data_cursor in_cursor;
struct ceph_msg_data_cursor out_cursor;
struct crypto_shash *hmac_tfm; /* post-auth signature */
struct crypto_aead *gcm_tfm; /* on-wire encryption */
struct aead_request *gcm_req;
struct crypto_wait gcm_wait;
struct ceph_gcm_nonce in_gcm_nonce;
struct ceph_gcm_nonce out_gcm_nonce;
struct page **out_enc_pages;
int out_enc_page_cnt;
int out_enc_resid;
int out_enc_i;
int con_mode; /* CEPH_CON_MODE_* */
void *conn_bufs[16];
int conn_buf_cnt;
struct kvec in_sign_kvecs[8];
struct kvec out_sign_kvecs[8];
int in_sign_kvec_cnt;
int out_sign_kvec_cnt;
u64 client_cookie;
u64 server_cookie;
u64 global_seq;
u64 connect_seq;
u64 peer_global_seq;
u8 in_buf[CEPH_PREAMBLE_SECURE_LEN];
u8 out_buf[CEPH_PREAMBLE_SECURE_LEN];
struct {
u8 late_status; /* FRAME_LATE_STATUS_* */
union {
struct {
u32 front_crc;
u32 middle_crc;
u32 data_crc;
} __packed;
u8 pad[CEPH_GCM_BLOCK_LEN - 1];
};
} out_epil;
};
/*
* A single connection with another host.
*
@ -346,7 +464,10 @@ struct ceph_connection {
struct delayed_work work; /* send|recv work */
unsigned long delay; /* current delay interval */
struct ceph_connection_v1_info v1;
union {
struct ceph_connection_v1_info v1;
struct ceph_connection_v2_info v2;
};
};
extern struct page *ceph_zero_page;
@ -397,6 +518,15 @@ bool ceph_con_v1_opened(struct ceph_connection *con);
void ceph_con_v1_reset_session(struct ceph_connection *con);
void ceph_con_v1_reset_protocol(struct ceph_connection *con);
/* messenger_v2.c */
int ceph_con_v2_try_read(struct ceph_connection *con);
int ceph_con_v2_try_write(struct ceph_connection *con);
void ceph_con_v2_revoke(struct ceph_connection *con);
void ceph_con_v2_revoke_incoming(struct ceph_connection *con);
bool ceph_con_v2_opened(struct ceph_connection *con);
void ceph_con_v2_reset_session(struct ceph_connection *con);
void ceph_con_v2_reset_protocol(struct ceph_connection *con);
extern const char *ceph_pr_addr(const struct ceph_entity_addr *addr);

View File

@ -14,9 +14,39 @@
* constant.
*/
#define CEPH_BANNER "ceph v027"
#define CEPH_BANNER_LEN 9
#define CEPH_BANNER_MAX_LEN 30
/*
* messenger V2 connection banner prefix.
* The full banner string should have the form: "ceph v2\n<le16>"
* the 2 bytes are the length of the remaining banner.
*/
#define CEPH_BANNER_V2 "ceph v2\n"
#define CEPH_BANNER_V2_LEN 8
#define CEPH_BANNER_V2_PREFIX_LEN (CEPH_BANNER_V2_LEN + sizeof(__le16))
/*
* messenger V2 features
*/
#define CEPH_MSGR2_INCARNATION_1 (0ull)
#define DEFINE_MSGR2_FEATURE(bit, incarnation, name) \
static const uint64_t CEPH_MSGR2_FEATURE_##name = (1ULL << bit); \
static const uint64_t CEPH_MSGR2_FEATUREMASK_##name = \
(1ULL << bit | CEPH_MSGR2_INCARNATION_##incarnation);
#define HAVE_MSGR2_FEATURE(x, name) \
(((x) & (CEPH_MSGR2_FEATUREMASK_##name)) == (CEPH_MSGR2_FEATUREMASK_##name))
DEFINE_MSGR2_FEATURE( 0, 1, REVISION_1) // msgr2.1
#define CEPH_MSGR2_SUPPORTED_FEATURES (CEPH_MSGR2_FEATURE_REVISION_1)
#define CEPH_MSGR2_REQUIRED_FEATURES (CEPH_MSGR2_FEATURE_REVISION_1)
/*
* Rollover-safe type and comparator for 32-bit sequence numbers.
* Comparator returns -1, 0, or 1.
@ -158,6 +188,24 @@ struct ceph_msg_header {
__le32 crc; /* header crc32c */
} __attribute__ ((packed));
struct ceph_msg_header2 {
__le64 seq; /* message seq# for this session */
__le64 tid; /* transaction id */
__le16 type; /* message type */
__le16 priority; /* priority. higher value == higher priority */
__le16 version; /* version of message encoding */
__le32 data_pre_padding_len;
__le16 data_off; /* sender: include full offset;
receiver: mask against ~PAGE_MASK */
__le64 ack_seq;
__u8 flags;
/* oldest code we think can decode this. unknown if zero. */
__le16 compat_version;
__le16 reserved;
} __attribute__ ((packed));
#define CEPH_MSG_PRIO_LOW 64
#define CEPH_MSG_PRIO_DEFAULT 127
#define CEPH_MSG_PRIO_HIGH 196

View File

@ -5,6 +5,9 @@ config CEPH_LIB
select LIBCRC32C
select CRYPTO_AES
select CRYPTO_CBC
select CRYPTO_GCM
select CRYPTO_HMAC
select CRYPTO_SHA256
select CRYPTO
select KEYS
default n

View File

@ -15,4 +15,4 @@ libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
auth_x.o \
ceph_strings.o ceph_hash.o \
pagevec.o snapshot.o string_table.o \
messenger_v1.o
messenger_v1.o messenger_v2.o

View File

@ -293,6 +293,39 @@ int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
}
EXPORT_SYMBOL(ceph_auth_is_authenticated);
int __ceph_auth_get_authorizer(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
int peer_type, bool force_new,
int *proto, int *pref_mode, int *fallb_mode)
{
int ret;
mutex_lock(&ac->mutex);
if (force_new && auth->authorizer) {
ceph_auth_destroy_authorizer(auth->authorizer);
auth->authorizer = NULL;
}
if (!auth->authorizer)
ret = ac->ops->create_authorizer(ac, peer_type, auth);
else if (ac->ops->update_authorizer)
ret = ac->ops->update_authorizer(ac, peer_type, auth);
else
ret = 0;
if (ret)
goto out;
*proto = ac->protocol;
if (pref_mode && fallb_mode) {
*pref_mode = ac->preferred_mode;
*fallb_mode = ac->fallback_mode;
}
out:
mutex_unlock(&ac->mutex);
return ret;
}
EXPORT_SYMBOL(__ceph_auth_get_authorizer);
int ceph_auth_create_authorizer(struct ceph_auth_client *ac,
int peer_type,
struct ceph_auth_handshake *auth)
@ -369,3 +402,279 @@ void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac, int peer_type)
mutex_unlock(&ac->mutex);
}
EXPORT_SYMBOL(ceph_auth_invalidate_authorizer);
/*
* msgr2 authentication
*/
static bool contains(const int *arr, int cnt, int val)
{
int i;
for (i = 0; i < cnt; i++) {
if (arr[i] == val)
return true;
}
return false;
}
static int encode_con_modes(void **p, void *end, int pref_mode, int fallb_mode)
{
WARN_ON(pref_mode == CEPH_CON_MODE_UNKNOWN);
if (fallb_mode != CEPH_CON_MODE_UNKNOWN) {
ceph_encode_32_safe(p, end, 2, e_range);
ceph_encode_32_safe(p, end, pref_mode, e_range);
ceph_encode_32_safe(p, end, fallb_mode, e_range);
} else {
ceph_encode_32_safe(p, end, 1, e_range);
ceph_encode_32_safe(p, end, pref_mode, e_range);
}
return 0;
e_range:
return -ERANGE;
}
/*
* Similar to ceph_auth_build_hello().
*/
int ceph_auth_get_request(struct ceph_auth_client *ac, void *buf, int buf_len)
{
int proto = ac->key ? CEPH_AUTH_CEPHX : CEPH_AUTH_NONE;
void *end = buf + buf_len;
void *lenp;
void *p;
int ret;
mutex_lock(&ac->mutex);
if (ac->protocol == CEPH_AUTH_UNKNOWN) {
ret = init_protocol(ac, proto);
if (ret) {
pr_err("auth protocol '%s' init failed: %d\n",
ceph_auth_proto_name(proto), ret);
goto out;
}
} else {
WARN_ON(ac->protocol != proto);
ac->ops->reset(ac);
}
p = buf;
ceph_encode_32_safe(&p, end, ac->protocol, e_range);
ret = encode_con_modes(&p, end, ac->preferred_mode, ac->fallback_mode);
if (ret)
goto out;
lenp = p;
p += 4; /* space for len */
ceph_encode_8_safe(&p, end, CEPH_AUTH_MODE_MON, e_range);
ret = ceph_auth_entity_name_encode(ac->name, &p, end);
if (ret)
goto out;
ceph_encode_64_safe(&p, end, ac->global_id, e_range);
ceph_encode_32(&lenp, p - lenp - 4);
ret = p - buf;
out:
mutex_unlock(&ac->mutex);
return ret;
e_range:
ret = -ERANGE;
goto out;
}
int ceph_auth_handle_reply_more(struct ceph_auth_client *ac, void *reply,
int reply_len, void *buf, int buf_len)
{
int ret;
mutex_lock(&ac->mutex);
ret = ac->ops->handle_reply(ac, 0, reply, reply + reply_len,
NULL, NULL, NULL, NULL);
if (ret == -EAGAIN)
ret = build_request(ac, false, buf, buf_len);
else
WARN_ON(ret >= 0);
mutex_unlock(&ac->mutex);
return ret;
}
int ceph_auth_handle_reply_done(struct ceph_auth_client *ac,
u64 global_id, void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len)
{
int ret;
mutex_lock(&ac->mutex);
if (global_id && ac->global_id != global_id) {
dout("%s global_id %llu -> %llu\n", __func__, ac->global_id,
global_id);
ac->global_id = global_id;
}
ret = ac->ops->handle_reply(ac, 0, reply, reply + reply_len,
session_key, session_key_len,
con_secret, con_secret_len);
mutex_unlock(&ac->mutex);
return ret;
}
bool ceph_auth_handle_bad_method(struct ceph_auth_client *ac,
int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt)
{
mutex_lock(&ac->mutex);
WARN_ON(used_proto != ac->protocol);
if (result == -EOPNOTSUPP) {
if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
pr_err("auth protocol '%s' not allowed\n",
ceph_auth_proto_name(ac->protocol));
goto not_allowed;
}
if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
(ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
!contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
pr_err("preferred mode '%s' not allowed\n",
ceph_con_mode_name(ac->preferred_mode));
if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
pr_err("no fallback mode\n");
else
pr_err("fallback mode '%s' not allowed\n",
ceph_con_mode_name(ac->fallback_mode));
goto not_allowed;
}
}
WARN_ON(result == -EOPNOTSUPP || result >= 0);
pr_err("auth protocol '%s' msgr authentication failed: %d\n",
ceph_auth_proto_name(ac->protocol), result);
mutex_unlock(&ac->mutex);
return true;
not_allowed:
mutex_unlock(&ac->mutex);
return false;
}
int ceph_auth_get_authorizer(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
int peer_type, void *buf, int *buf_len)
{
void *end = buf + *buf_len;
int pref_mode, fallb_mode;
int proto;
void *p;
int ret;
ret = __ceph_auth_get_authorizer(ac, auth, peer_type, true, &proto,
&pref_mode, &fallb_mode);
if (ret)
return ret;
p = buf;
ceph_encode_32_safe(&p, end, proto, e_range);
ret = encode_con_modes(&p, end, pref_mode, fallb_mode);
if (ret)
return ret;
ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
*buf_len = p - buf;
return 0;
e_range:
return -ERANGE;
}
EXPORT_SYMBOL(ceph_auth_get_authorizer);
int ceph_auth_handle_svc_reply_more(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
void *reply, int reply_len,
void *buf, int *buf_len)
{
void *end = buf + *buf_len;
void *p;
int ret;
ret = ceph_auth_add_authorizer_challenge(ac, auth->authorizer,
reply, reply_len);
if (ret)
return ret;
p = buf;
ceph_encode_32_safe(&p, end, auth->authorizer_buf_len, e_range);
*buf_len = p - buf;
return 0;
e_range:
return -ERANGE;
}
EXPORT_SYMBOL(ceph_auth_handle_svc_reply_more);
int ceph_auth_handle_svc_reply_done(struct ceph_auth_client *ac,
struct ceph_auth_handshake *auth,
void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len)
{
return ceph_auth_verify_authorizer_reply(ac, auth->authorizer,
reply, reply_len, session_key, session_key_len,
con_secret, con_secret_len);
}
EXPORT_SYMBOL(ceph_auth_handle_svc_reply_done);
bool ceph_auth_handle_bad_authorizer(struct ceph_auth_client *ac,
int peer_type, int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt)
{
mutex_lock(&ac->mutex);
WARN_ON(used_proto != ac->protocol);
if (result == -EOPNOTSUPP) {
if (!contains(allowed_protos, proto_cnt, ac->protocol)) {
pr_err("auth protocol '%s' not allowed by %s\n",
ceph_auth_proto_name(ac->protocol),
ceph_entity_type_name(peer_type));
goto not_allowed;
}
if (!contains(allowed_modes, mode_cnt, ac->preferred_mode) &&
(ac->fallback_mode == CEPH_CON_MODE_UNKNOWN ||
!contains(allowed_modes, mode_cnt, ac->fallback_mode))) {
pr_err("preferred mode '%s' not allowed by %s\n",
ceph_con_mode_name(ac->preferred_mode),
ceph_entity_type_name(peer_type));
if (ac->fallback_mode == CEPH_CON_MODE_UNKNOWN)
pr_err("no fallback mode\n");
else
pr_err("fallback mode '%s' not allowed by %s\n",
ceph_con_mode_name(ac->fallback_mode),
ceph_entity_type_name(peer_type));
goto not_allowed;
}
}
WARN_ON(result == -EOPNOTSUPP || result >= 0);
pr_err("auth protocol '%s' authorization to %s failed: %d\n",
ceph_auth_proto_name(ac->protocol),
ceph_entity_type_name(peer_type), result);
if (ac->ops->invalidate_authorizer)
ac->ops->invalidate_authorizer(ac, peer_type);
mutex_unlock(&ac->mutex);
return true;
not_allowed:
mutex_unlock(&ac->mutex);
return false;
}
EXPORT_SYMBOL(ceph_auth_handle_bad_authorizer);

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/ceph/ceph_debug.h>
#include <linux/inet.h>
#include <linux/ceph/decode.h>
static int
@ -138,3 +140,46 @@ int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,
return -EINVAL;
}
EXPORT_SYMBOL(ceph_decode_entity_addrvec);
static int get_sockaddr_encoding_len(sa_family_t family)
{
union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} u;
switch (family) {
case AF_INET:
return sizeof(u.sin);
case AF_INET6:
return sizeof(u.sin6);
default:
return sizeof(u);
}
}
int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr)
{
sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
int addr_len = get_sockaddr_encoding_len(family);
return 1 + CEPH_ENCODING_START_BLK_LEN + 4 + 4 + 4 + addr_len;
}
void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr)
{
sa_family_t family = get_unaligned(&addr->in_addr.ss_family);
int addr_len = get_sockaddr_encoding_len(family);
ceph_encode_8(p, 1); /* marker */
ceph_start_encoding(p, 1, 1, sizeof(addr->type) +
sizeof(addr->nonce) +
sizeof(u32) + addr_len);
ceph_encode_copy(p, &addr->type, sizeof(addr->type));
ceph_encode_copy(p, &addr->nonce, sizeof(addr->nonce));
ceph_encode_32(p, addr_len);
ceph_encode_16(p, family);
ceph_encode_copy(p, addr->in_addr.__data, addr_len - sizeof(family));
}

View File

@ -195,8 +195,11 @@ EXPORT_SYMBOL(ceph_pr_addr);
void ceph_encode_my_addr(struct ceph_messenger *msgr)
{
memcpy(&msgr->my_enc_addr, &msgr->inst.addr, sizeof(msgr->my_enc_addr));
ceph_encode_banner_addr(&msgr->my_enc_addr);
if (!ceph_msgr2(from_msgr(msgr))) {
memcpy(&msgr->my_enc_addr, &msgr->inst.addr,
sizeof(msgr->my_enc_addr));
ceph_encode_banner_addr(&msgr->my_enc_addr);
}
}
/*
@ -513,7 +516,10 @@ static void ceph_con_reset_protocol(struct ceph_connection *con)
con->out_msg = NULL;
}
ceph_con_v1_reset_protocol(con);
if (ceph_msgr2(from_msgr(con->msgr)))
ceph_con_v2_reset_protocol(con);
else
ceph_con_v1_reset_protocol(con);
}
/*
@ -526,6 +532,7 @@ static void ceph_msg_remove(struct ceph_msg *msg)
ceph_msg_put(msg);
}
static void ceph_msg_remove_list(struct list_head *head)
{
while (!list_empty(head)) {
@ -547,7 +554,10 @@ void ceph_con_reset_session(struct ceph_connection *con)
con->in_seq = 0;
con->in_seq_acked = 0;
ceph_con_v1_reset_session(con);
if (ceph_msgr2(from_msgr(con->msgr)))
ceph_con_v2_reset_session(con);
else
ceph_con_v1_reset_session(con);
}
/*
@ -600,6 +610,9 @@ EXPORT_SYMBOL(ceph_con_open);
*/
bool ceph_con_opened(struct ceph_connection *con)
{
if (ceph_msgr2(from_msgr(con->msgr)))
return ceph_con_v2_opened(con);
return ceph_con_v1_opened(con);
}
@ -1302,7 +1315,16 @@ int ceph_parse_ips(const char *c, const char *end,
}
ceph_addr_set_port(&addr[i], port);
/*
* We want the type to be set according to ms_mode
* option, but options are normally parsed after mon
* addresses. Rather than complicating parsing, set
* to LEGACY and override in build_initial_monmap()
* for mon addresses and ceph_messenger_init() for
* ip option.
*/
addr[i].type = CEPH_ENTITY_ADDR_TYPE_LEGACY;
addr[i].nonce = 0;
dout("parse_ips got %s\n", ceph_pr_addr(&addr[i]));
@ -1410,6 +1432,13 @@ static bool con_sock_closed(struct ceph_connection *con)
CASE(PREOPEN);
CASE(V1_BANNER);
CASE(V1_CONNECT_MSG);
CASE(V2_BANNER_PREFIX);
CASE(V2_BANNER_PAYLOAD);
CASE(V2_HELLO);
CASE(V2_AUTH);
CASE(V2_AUTH_SIGNATURE);
CASE(V2_SESSION_CONNECT);
CASE(V2_SESSION_RECONNECT);
CASE(OPEN);
CASE(STANDBY);
default:
@ -1494,7 +1523,10 @@ static void ceph_con_workfn(struct work_struct *work)
BUG_ON(con->sock);
}
ret = ceph_con_v1_try_read(con);
if (ceph_msgr2(from_msgr(con->msgr)))
ret = ceph_con_v2_try_read(con);
else
ret = ceph_con_v1_try_read(con);
if (ret < 0) {
if (ret == -EAGAIN)
continue;
@ -1504,7 +1536,10 @@ static void ceph_con_workfn(struct work_struct *work)
break;
}
ret = ceph_con_v1_try_write(con);
if (ceph_msgr2(from_msgr(con->msgr)))
ret = ceph_con_v2_try_write(con);
else
ret = ceph_con_v1_try_write(con);
if (ret < 0) {
if (ret == -EAGAIN)
continue;
@ -1538,9 +1573,8 @@ static void con_fault(struct ceph_connection *con)
ceph_pr_addr(&con->peer_addr), con->error_msg);
con->error_msg = NULL;
WARN_ON(con->state != CEPH_CON_S_V1_BANNER &&
con->state != CEPH_CON_S_V1_CONNECT_MSG &&
con->state != CEPH_CON_S_OPEN);
WARN_ON(con->state == CEPH_CON_S_STANDBY ||
con->state == CEPH_CON_S_CLOSED);
ceph_con_reset_protocol(con);
@ -1596,7 +1630,11 @@ void ceph_messenger_init(struct ceph_messenger *msgr,
ceph_addr_set_port(&msgr->inst.addr, 0);
}
msgr->inst.addr.type = 0;
/*
* Since nautilus, clients are identified using type ANY.
* For msgr1, ceph_encode_banner_addr() munges it to NONE.
*/
msgr->inst.addr.type = CEPH_ENTITY_ADDR_TYPE_ANY;
/* generate a random non-zero nonce */
do {
@ -1706,7 +1744,10 @@ void ceph_msg_revoke(struct ceph_msg *msg)
if (con->out_msg == msg) {
WARN_ON(con->state != CEPH_CON_S_OPEN);
dout("%s con %p msg %p was sending\n", __func__, con, msg);
ceph_con_v1_revoke(con);
if (ceph_msgr2(from_msgr(con->msgr)))
ceph_con_v2_revoke(con);
else
ceph_con_v1_revoke(con);
ceph_msg_put(con->out_msg);
con->out_msg = NULL;
} else {
@ -1732,7 +1773,10 @@ void ceph_msg_revoke_incoming(struct ceph_msg *msg)
if (con->in_msg == msg) {
WARN_ON(con->state != CEPH_CON_S_OPEN);
dout("%s con %p msg %p was recving\n", __func__, con, msg);
ceph_con_v1_revoke_incoming(con);
if (ceph_msgr2(from_msgr(con->msgr)))
ceph_con_v2_revoke_incoming(con);
else
ceph_con_v1_revoke_incoming(con);
ceph_msg_put(con->in_msg);
con->in_msg = NULL;
} else {

3443
net/ceph/messenger_v2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -257,10 +257,16 @@ static void __open_session(struct ceph_mon_client *monc)
&monc->monmap->mon_inst[monc->cur_mon].addr);
/*
* send an initial keepalive to ensure our timestamp is valid
* by the time we are in an OPENED state
* Queue a keepalive to ensure that in case of an early fault
* the messenger doesn't put us into STANDBY state and instead
* retries. This also ensures that our timestamp is valid by
* the time we finish hunting and delayed_work() checks it.
*/
ceph_con_keepalive(&monc->con);
if (ceph_msgr2(monc->client)) {
monc->pending_auth = 1;
return;
}
/* initiate authentication handshake */
ret = ceph_auth_build_hello(monc->auth,
@ -543,7 +549,7 @@ static void ceph_monc_handle_map(struct ceph_mon_client *monc,
p = msg->front.iov_base;
end = p + msg->front.iov_len;
monmap = ceph_monmap_decode(&p, end, false);
monmap = ceph_monmap_decode(&p, end, ceph_msgr2(client));
if (IS_ERR(monmap)) {
pr_err("problem decoding monmap, %d\n",
(int)PTR_ERR(monmap));
@ -1119,8 +1125,9 @@ static void delayed_work(struct work_struct *work)
*/
static int build_initial_monmap(struct ceph_mon_client *monc)
{
__le32 my_type = ceph_msgr2(monc->client) ?
CEPH_ENTITY_ADDR_TYPE_MSGR2 : CEPH_ENTITY_ADDR_TYPE_LEGACY;
struct ceph_options *opt = monc->client->options;
struct ceph_entity_addr *mon_addr = opt->mon_addr;
int num_mon = opt->num_mon;
int i;
@ -1129,12 +1136,16 @@ static int build_initial_monmap(struct ceph_mon_client *monc)
GFP_KERNEL);
if (!monc->monmap)
return -ENOMEM;
for (i = 0; i < num_mon; i++) {
monc->monmap->mon_inst[i].addr = mon_addr[i];
monc->monmap->mon_inst[i].addr.nonce = 0;
monc->monmap->mon_inst[i].name.type =
CEPH_ENTITY_TYPE_MON;
monc->monmap->mon_inst[i].name.num = cpu_to_le64(i);
struct ceph_entity_inst *inst = &monc->monmap->mon_inst[i];
memcpy(&inst->addr.in_addr, &opt->mon_addr[i].in_addr,
sizeof(inst->addr.in_addr));
inst->addr.type = my_type;
inst->addr.nonce = 0;
inst->name.type = CEPH_ENTITY_TYPE_MON;
inst->name.num = cpu_to_le64(i);
}
monc->monmap->num_mon = num_mon;
return 0;
@ -1337,6 +1348,88 @@ int ceph_monc_validate_auth(struct ceph_mon_client *monc)
}
EXPORT_SYMBOL(ceph_monc_validate_auth);
static int mon_get_auth_request(struct ceph_connection *con,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len)
{
struct ceph_mon_client *monc = con->private;
int ret;
mutex_lock(&monc->mutex);
ret = ceph_auth_get_request(monc->auth, buf, *buf_len);
mutex_unlock(&monc->mutex);
if (ret < 0)
return ret;
*buf_len = ret;
*authorizer = NULL;
*authorizer_len = 0;
return 0;
}
static int mon_handle_auth_reply_more(struct ceph_connection *con,
void *reply, int reply_len,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len)
{
struct ceph_mon_client *monc = con->private;
int ret;
mutex_lock(&monc->mutex);
ret = ceph_auth_handle_reply_more(monc->auth, reply, reply_len,
buf, *buf_len);
mutex_unlock(&monc->mutex);
if (ret < 0)
return ret;
*buf_len = ret;
*authorizer = NULL;
*authorizer_len = 0;
return 0;
}
static int mon_handle_auth_done(struct ceph_connection *con,
u64 global_id, void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len)
{
struct ceph_mon_client *monc = con->private;
bool was_authed;
int ret;
mutex_lock(&monc->mutex);
WARN_ON(!monc->hunting);
was_authed = ceph_auth_is_authenticated(monc->auth);
ret = ceph_auth_handle_reply_done(monc->auth, global_id,
reply, reply_len,
session_key, session_key_len,
con_secret, con_secret_len);
finish_auth(monc, ret, was_authed);
if (!ret)
finish_hunting(monc);
mutex_unlock(&monc->mutex);
return 0;
}
static int mon_handle_auth_bad_method(struct ceph_connection *con,
int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt)
{
struct ceph_mon_client *monc = con->private;
bool was_authed;
mutex_lock(&monc->mutex);
WARN_ON(!monc->hunting);
was_authed = ceph_auth_is_authenticated(monc->auth);
ceph_auth_handle_bad_method(monc->auth, used_proto, result,
allowed_protos, proto_cnt,
allowed_modes, mode_cnt);
finish_auth(monc, -EACCES, was_authed);
mutex_unlock(&monc->mutex);
return 0;
}
/*
* handle incoming message
*/
@ -1487,4 +1580,8 @@ static const struct ceph_connection_operations mon_con_ops = {
.dispatch = dispatch,
.fault = mon_fault,
.alloc_msg = mon_alloc_msg,
.get_auth_request = mon_get_auth_request,
.handle_auth_reply_more = mon_handle_auth_reply_more,
.handle_auth_done = mon_handle_auth_done,
.handle_auth_bad_method = mon_handle_auth_bad_method,
};

View File

@ -3918,9 +3918,11 @@ static int handle_one_map(struct ceph_osd_client *osdc,
set_pool_was_full(osdc);
if (incremental)
newmap = osdmap_apply_incremental(&p, end, false, osdc->osdmap);
newmap = osdmap_apply_incremental(&p, end,
ceph_msgr2(osdc->client),
osdc->osdmap);
else
newmap = ceph_osdmap_decode(&p, end, false);
newmap = ceph_osdmap_decode(&p, end, ceph_msgr2(osdc->client));
if (IS_ERR(newmap))
return PTR_ERR(newmap);
@ -5575,6 +5577,7 @@ static void put_osd_con(struct ceph_connection *con)
/*
* authentication
*/
/*
* Note: returned pointer is the address of a structure that's
* managed separately. Caller must *not* attempt to free it.
@ -5640,6 +5643,80 @@ static int invalidate_authorizer(struct ceph_connection *con)
return ceph_monc_validate_auth(&osdc->client->monc);
}
static int osd_get_auth_request(struct ceph_connection *con,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len)
{
struct ceph_osd *o = con->private;
struct ceph_auth_client *ac = o->o_osdc->client->monc.auth;
struct ceph_auth_handshake *auth = &o->o_auth;
int ret;
ret = ceph_auth_get_authorizer(ac, auth, CEPH_ENTITY_TYPE_OSD,
buf, buf_len);
if (ret)
return ret;
*authorizer = auth->authorizer_buf;
*authorizer_len = auth->authorizer_buf_len;
return 0;
}
static int osd_handle_auth_reply_more(struct ceph_connection *con,
void *reply, int reply_len,
void *buf, int *buf_len,
void **authorizer, int *authorizer_len)
{
struct ceph_osd *o = con->private;
struct ceph_auth_client *ac = o->o_osdc->client->monc.auth;
struct ceph_auth_handshake *auth = &o->o_auth;
int ret;
ret = ceph_auth_handle_svc_reply_more(ac, auth, reply, reply_len,
buf, buf_len);
if (ret)
return ret;
*authorizer = auth->authorizer_buf;
*authorizer_len = auth->authorizer_buf_len;
return 0;
}
static int osd_handle_auth_done(struct ceph_connection *con,
u64 global_id, void *reply, int reply_len,
u8 *session_key, int *session_key_len,
u8 *con_secret, int *con_secret_len)
{
struct ceph_osd *o = con->private;
struct ceph_auth_client *ac = o->o_osdc->client->monc.auth;
struct ceph_auth_handshake *auth = &o->o_auth;
return ceph_auth_handle_svc_reply_done(ac, auth, reply, reply_len,
session_key, session_key_len,
con_secret, con_secret_len);
}
static int osd_handle_auth_bad_method(struct ceph_connection *con,
int used_proto, int result,
const int *allowed_protos, int proto_cnt,
const int *allowed_modes, int mode_cnt)
{
struct ceph_osd *o = con->private;
struct ceph_mon_client *monc = &o->o_osdc->client->monc;
int ret;
if (ceph_auth_handle_bad_authorizer(monc->auth, CEPH_ENTITY_TYPE_OSD,
used_proto, result,
allowed_protos, proto_cnt,
allowed_modes, mode_cnt)) {
ret = ceph_monc_validate_auth(monc);
if (ret)
return ret;
}
return -EACCES;
}
static void osd_reencode_message(struct ceph_msg *msg)
{
int type = le16_to_cpu(msg->hdr.type);
@ -5677,4 +5754,8 @@ static const struct ceph_connection_operations osd_con_ops = {
.sign_message = osd_sign_message,
.check_message_signature = osd_check_message_signature,
.fault = osd_fault,
.get_auth_request = osd_get_auth_request,
.handle_auth_reply_more = osd_handle_auth_reply_more,
.handle_auth_done = osd_handle_auth_done,
.handle_auth_bad_method = osd_handle_auth_bad_method,
};