libceph: message signature support
authorYan, Zheng <zyan@redhat.com>
Tue, 4 Nov 2014 08:33:37 +0000 (16:33 +0800)
committerIlya Dryomov <idryomov@redhat.com>
Wed, 17 Dec 2014 17:09:50 +0000 (20:09 +0300)
Signed-off-by: Yan, Zheng <zyan@redhat.com>
fs/ceph/mds_client.c
include/linux/ceph/auth.h
include/linux/ceph/ceph_features.h
include/linux/ceph/messenger.h
include/linux/ceph/msgr.h
net/ceph/auth_x.c
net/ceph/messenger.c
net/ceph/osd_client.c

index fc74617069a3310d8f7914845924964ed2c98385..9f00853f6d42b9394058ee2f316c972a1830fe62 100644 (file)
@@ -3744,6 +3744,20 @@ static struct ceph_msg *mds_alloc_msg(struct ceph_connection *con,
        return msg;
 }
 
+static int sign_message(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       struct ceph_mds_session *s = con->private;
+       struct ceph_auth_handshake *auth = &s->s_auth;
+       return ceph_auth_sign_message(auth, msg);
+}
+
+static int check_message_signature(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       struct ceph_mds_session *s = con->private;
+       struct ceph_auth_handshake *auth = &s->s_auth;
+       return ceph_auth_check_message_signature(auth, msg);
+}
+
 static const struct ceph_connection_operations mds_con_ops = {
        .get = con_get,
        .put = con_put,
@@ -3753,6 +3767,8 @@ static const struct ceph_connection_operations mds_con_ops = {
        .invalidate_authorizer = invalidate_authorizer,
        .peer_reset = peer_reset,
        .alloc_msg = mds_alloc_msg,
+       .sign_message = sign_message,
+       .check_message_signature = check_message_signature,
 };
 
 /* eof */
index 5f3386844134f9a7d467a4a22f0d61f978b0c15f..260d78b587c48e99f552f328a27a65ddd9745dd2 100644 (file)
@@ -13,6 +13,7 @@
 
 struct ceph_auth_client;
 struct ceph_authorizer;
+struct ceph_msg;
 
 struct ceph_auth_handshake {
        struct ceph_authorizer *authorizer;
@@ -20,6 +21,10 @@ struct ceph_auth_handshake {
        size_t authorizer_buf_len;
        void *authorizer_reply_buf;
        size_t authorizer_reply_buf_len;
+       int (*sign_message)(struct ceph_auth_handshake *auth,
+                           struct ceph_msg *msg);
+       int (*check_message_signature)(struct ceph_auth_handshake *auth,
+                                      struct ceph_msg *msg);
 };
 
 struct ceph_auth_client_ops {
@@ -66,6 +71,11 @@ struct ceph_auth_client_ops {
        void (*reset)(struct ceph_auth_client *ac);
 
        void (*destroy)(struct ceph_auth_client *ac);
+
+       int (*sign_message)(struct ceph_auth_handshake *auth,
+                           struct ceph_msg *msg);
+       int (*check_message_signature)(struct ceph_auth_handshake *auth,
+                                      struct ceph_msg *msg);
 };
 
 struct ceph_auth_client {
@@ -113,4 +123,20 @@ extern int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
 extern void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac,
                                            int peer_type);
 
+static inline int ceph_auth_sign_message(struct ceph_auth_handshake *auth,
+                                        struct ceph_msg *msg)
+{
+       if (auth->sign_message)
+               return auth->sign_message(auth, msg);
+       return 0;
+}
+
+static inline
+int ceph_auth_check_message_signature(struct ceph_auth_handshake *auth,
+                                     struct ceph_msg *msg)
+{
+       if (auth->check_message_signature)
+               return auth->check_message_signature(auth, msg);
+       return 0;
+}
 #endif
index d12659ce550d2f160cf7a0bebdc51160b39a6c3a..71e05bbf8cebe3888a9a4ff72abb1d210dadd4c1 100644 (file)
@@ -84,6 +84,7 @@ static inline u64 ceph_sanitize_features(u64 features)
         CEPH_FEATURE_PGPOOL3 |                 \
         CEPH_FEATURE_OSDENC |                  \
         CEPH_FEATURE_CRUSH_TUNABLES |          \
+        CEPH_FEATURE_MSG_AUTH |                \
         CEPH_FEATURE_CRUSH_TUNABLES2 |         \
         CEPH_FEATURE_REPLY_CREATE_INODE |      \
         CEPH_FEATURE_OSDHASHPSPOOL |           \
index 40ae58e3e9db67d5adbfac4c6207ee4af8b1bebc..d9d396c165037a7d6f661a41ec0dccec12f7dd1a 100644 (file)
@@ -42,6 +42,10 @@ struct ceph_connection_operations {
        struct ceph_msg * (*alloc_msg) (struct ceph_connection *con,
                                        struct ceph_msg_header *hdr,
                                        int *skip);
+       int (*sign_message) (struct ceph_connection *con, struct ceph_msg *msg);
+
+       int (*check_message_signature) (struct ceph_connection *con,
+                                       struct ceph_msg *msg);
 };
 
 /* use format string %s%d */
@@ -142,7 +146,10 @@ struct ceph_msg_data_cursor {
  */
 struct ceph_msg {
        struct ceph_msg_header hdr;     /* header */
-       struct ceph_msg_footer footer;  /* footer */
+       union {
+               struct ceph_msg_footer footer;          /* footer */
+               struct ceph_msg_footer_old old_footer;  /* old format footer */
+       };
        struct kvec front;              /* unaligned blobs of message */
        struct ceph_buffer *middle;
 
index 3d94a73b5f30c43b6e47b1c97ef23c9861e5bb7f..cac4b28ac1c09dd368df92232ba8e59384340caa 100644 (file)
@@ -164,13 +164,21 @@ struct ceph_msg_header {
 /*
  * follows data payload
  */
+struct ceph_msg_footer_old {
+       __le32 front_crc, middle_crc, data_crc;
+       __u8 flags;
+} __attribute__ ((packed));
+
 struct ceph_msg_footer {
        __le32 front_crc, middle_crc, data_crc;
+       // sig holds the 64 bits of the digital signature for the message PLR
+       __le64  sig;
        __u8 flags;
 } __attribute__ ((packed));
 
 #define CEPH_MSG_FOOTER_COMPLETE  (1<<0)   /* msg wasn't aborted */
 #define CEPH_MSG_FOOTER_NOCRC     (1<<1)   /* no data crc */
+#define CEPH_MSG_FOOTER_SIGNED   (1<<2)   /* msg was signed */
 
 
 #endif
index 77f3885c16bc7f41813be9d509ec674e40a218b5..15845814a0f25eaefb95590cb848aa6032a8e038 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/ceph/decode.h>
 #include <linux/ceph/auth.h>
+#include <linux/ceph/messenger.h>
 
 #include "crypto.h"
 #include "auth_x.h"
@@ -567,6 +568,8 @@ static int ceph_x_create_authorizer(
        auth->authorizer_buf_len = au->buf->vec.iov_len;
        auth->authorizer_reply_buf = au->reply_buf;
        auth->authorizer_reply_buf_len = sizeof (au->reply_buf);
+       auth->sign_message = ac->ops->sign_message;
+       auth->check_message_signature = ac->ops->check_message_signature;
 
        return 0;
 }
@@ -667,6 +670,59 @@ static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac,
                memset(&th->validity, 0, sizeof(th->validity));
 }
 
+static int calcu_signature(struct ceph_x_authorizer *au,
+                          struct ceph_msg *msg, __le64 *sig)
+{
+       int ret;
+       char tmp_enc[40];
+       __le32 tmp[5] = {
+               16u, msg->hdr.crc, msg->footer.front_crc,
+               msg->footer.middle_crc, msg->footer.data_crc,
+       };
+       ret = ceph_x_encrypt(&au->session_key, &tmp, sizeof(tmp),
+                            tmp_enc, sizeof(tmp_enc));
+       if (ret < 0)
+               return ret;
+       *sig = *(__le64*)(tmp_enc + 4);
+       return 0;
+}
+
+static int ceph_x_sign_message(struct ceph_auth_handshake *auth,
+                              struct ceph_msg *msg)
+{
+       int ret;
+       if (!auth->authorizer)
+               return 0;
+       ret = calcu_signature((struct ceph_x_authorizer *)auth->authorizer,
+                             msg, &msg->footer.sig);
+       if (ret < 0)
+               return ret;
+       msg->footer.flags |= CEPH_MSG_FOOTER_SIGNED;
+       return 0;
+}
+
+static int ceph_x_check_message_signature(struct ceph_auth_handshake *auth,
+                                         struct ceph_msg *msg)
+{
+       __le64 sig_check;
+       int ret;
+
+       if (!auth->authorizer)
+               return 0;
+       ret = calcu_signature((struct ceph_x_authorizer *)auth->authorizer,
+                             msg, &sig_check);
+       if (ret < 0)
+               return ret;
+       if (sig_check == msg->footer.sig)
+               return 0;
+       if (msg->footer.flags & CEPH_MSG_FOOTER_SIGNED)
+               dout("ceph_x_check_message_signature %p has signature %llx "
+                    "expect %llx\n", msg, msg->footer.sig, sig_check);
+       else
+               dout("ceph_x_check_message_signature %p sender did not set "
+                    "CEPH_MSG_FOOTER_SIGNED\n", msg);
+       return -EBADMSG;
+}
 
 static const struct ceph_auth_client_ops ceph_x_ops = {
        .name = "x",
@@ -681,6 +737,8 @@ static const struct ceph_auth_client_ops ceph_x_ops = {
        .invalidate_authorizer = ceph_x_invalidate_authorizer,
        .reset =  ceph_x_reset,
        .destroy = ceph_x_destroy,
+       .sign_message = ceph_x_sign_message,
+       .check_message_signature = ceph_x_check_message_signature,
 };
 
 
index 863d07ab212943b1821956075aaf604a735d9726..33a2f201e460e1585f82db94c8f3f90f01bbacdf 100644 (file)
@@ -1196,8 +1196,18 @@ static void prepare_write_message_footer(struct ceph_connection *con)
        dout("prepare_write_message_footer %p\n", con);
        con->out_kvec_is_msg = true;
        con->out_kvec[v].iov_base = &m->footer;
-       con->out_kvec[v].iov_len = sizeof(m->footer);
-       con->out_kvec_bytes += sizeof(m->footer);
+       if (con->peer_features & CEPH_FEATURE_MSG_AUTH) {
+               if (con->ops->sign_message)
+                       con->ops->sign_message(con, m);
+               else
+                       m->footer.sig = 0;
+               con->out_kvec[v].iov_len = sizeof(m->footer);
+               con->out_kvec_bytes += sizeof(m->footer);
+       } else {
+               m->old_footer.flags = m->footer.flags;
+               con->out_kvec[v].iov_len = sizeof(m->old_footer);
+               con->out_kvec_bytes += sizeof(m->old_footer);
+       }
        con->out_kvec_left++;
        con->out_more = m->more_to_follow;
        con->out_msg_done = true;
@@ -2249,6 +2259,7 @@ static int read_partial_message(struct ceph_connection *con)
        int ret;
        unsigned int front_len, middle_len, data_len;
        bool do_datacrc = !con->msgr->nocrc;
+       bool need_sign = (con->peer_features & CEPH_FEATURE_MSG_AUTH);
        u64 seq;
        u32 crc;
 
@@ -2361,12 +2372,21 @@ static int read_partial_message(struct ceph_connection *con)
        }
 
        /* footer */
-       size = sizeof (m->footer);
+       if (need_sign)
+               size = sizeof(m->footer);
+       else
+               size = sizeof(m->old_footer);
+
        end += size;
        ret = read_partial(con, end, size, &m->footer);
        if (ret <= 0)
                return ret;
 
+       if (!need_sign) {
+               m->footer.flags = m->old_footer.flags;
+               m->footer.sig = 0;
+       }
+
        dout("read_partial_message got msg %p %d (%u) + %d (%u) + %d (%u)\n",
             m, front_len, m->footer.front_crc, middle_len,
             m->footer.middle_crc, data_len, m->footer.data_crc);
@@ -2390,6 +2410,12 @@ static int read_partial_message(struct ceph_connection *con)
                return -EBADMSG;
        }
 
+       if (need_sign && con->ops->check_message_signature &&
+           con->ops->check_message_signature(con, m)) {
+               pr_err("read_partial_message %p signature check failed\n", m);
+               return -EBADMSG;
+       }
+
        return 1; /* done! */
 }
 
index 6f164289bde8860e333c747934da5459e807d7eb..1f6c4055adafdee5110355f7713e979ac495cb08 100644 (file)
@@ -2920,6 +2920,20 @@ static int invalidate_authorizer(struct ceph_connection *con)
        return ceph_monc_validate_auth(&osdc->client->monc);
 }
 
+static int sign_message(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       struct ceph_osd *o = con->private;
+       struct ceph_auth_handshake *auth = &o->o_auth;
+       return ceph_auth_sign_message(auth, msg);
+}
+
+static int check_message_signature(struct ceph_connection *con, struct ceph_msg *msg)
+{
+       struct ceph_osd *o = con->private;
+       struct ceph_auth_handshake *auth = &o->o_auth;
+       return ceph_auth_check_message_signature(auth, msg);
+}
+
 static const struct ceph_connection_operations osd_con_ops = {
        .get = get_osd_con,
        .put = put_osd_con,
@@ -2928,5 +2942,7 @@ static const struct ceph_connection_operations osd_con_ops = {
        .verify_authorizer_reply = verify_authorizer_reply,
        .invalidate_authorizer = invalidate_authorizer,
        .alloc_msg = alloc_msg,
+       .sign_message = sign_message,
+       .check_message_signature = check_message_signature,
        .fault = osd_reset,
 };