Re: [PATCH 1/2] libceph: make recv path in secure mode work the same as send path

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jan 31, 2022 at 4:58 PM Ilya Dryomov <idryomov@xxxxxxxxx> wrote:
>
> The recv path of secure mode is intertwined with that of crc mode.
> While it's slightly more efficient that way (the ciphertext is read
> into the destination buffer and decrypted in place, thus avoiding
> two potentially heavy memory allocations for the bounce buffer and
> the corresponding sg array), it isn't really amenable to changes.
> Sacrifice that edge and align with the send path which always uses
> a full-sized bounce buffer (currently there is no other way -- if
> the kernel crypto API ever grows support for streaming (piecewise)
> en/decryption for GCM [1], we would be able to easily take advantage
> of that on both sides).
>
> [1] https://lore.kernel.org/all/20141225202830.GA18794@xxxxxxxxxxxxxxxxxxx/
>
> Signed-off-by: Ilya Dryomov <idryomov@xxxxxxxxx>
> ---
>  include/linux/ceph/messenger.h |   4 +
>  net/ceph/messenger_v2.c        | 231 ++++++++++++++++++++++-----------
>  2 files changed, 162 insertions(+), 73 deletions(-)
>
> diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
> index ff99ce094cfa..6c6b6ea52bb8 100644
> --- a/include/linux/ceph/messenger.h
> +++ b/include/linux/ceph/messenger.h
> @@ -383,6 +383,10 @@ struct ceph_connection_v2_info {
>         struct ceph_gcm_nonce in_gcm_nonce;
>         struct ceph_gcm_nonce out_gcm_nonce;
>
> +       struct page **in_enc_pages;
> +       int in_enc_page_cnt;
> +       int in_enc_resid;
> +       int in_enc_i;
>         struct page **out_enc_pages;
>         int out_enc_page_cnt;
>         int out_enc_resid;
> diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c
> index c4099b641b38..d34349f112b0 100644
> --- a/net/ceph/messenger_v2.c
> +++ b/net/ceph/messenger_v2.c
> @@ -57,8 +57,9 @@
>  #define IN_S_HANDLE_CONTROL_REMAINDER  3
>  #define IN_S_PREPARE_READ_DATA         4
>  #define IN_S_PREPARE_READ_DATA_CONT    5
> -#define IN_S_HANDLE_EPILOGUE           6
> -#define IN_S_FINISH_SKIP               7
> +#define IN_S_PREPARE_READ_ENC_PAGE     6
> +#define IN_S_HANDLE_EPILOGUE           7
> +#define IN_S_FINISH_SKIP               8
>
>  #define OUT_S_QUEUE_DATA               1
>  #define OUT_S_QUEUE_DATA_CONT          2
> @@ -1032,22 +1033,41 @@ static int decrypt_control_remainder(struct ceph_connection *con)
>                          padded_len(rem_len) + CEPH_GCM_TAG_LEN);
>  }
>
> -static int decrypt_message(struct ceph_connection *con)
> +static int decrypt_tail(struct ceph_connection *con)
>  {
> +       struct sg_table enc_sgt = {};
>         struct sg_table sgt = {};
> +       int tail_len;
>         int ret;
>
> +       tail_len = tail_onwire_len(con->in_msg, true);
> +       ret = sg_alloc_table_from_pages(&enc_sgt, con->v2.in_enc_pages,
> +                                       con->v2.in_enc_page_cnt, 0, tail_len,
> +                                       GFP_NOIO);
> +       if (ret)
> +               goto out;
> +
>         ret = setup_message_sgs(&sgt, con->in_msg, FRONT_PAD(con->v2.in_buf),
>                         MIDDLE_PAD(con->v2.in_buf), DATA_PAD(con->v2.in_buf),
>                         con->v2.in_buf, true);
>         if (ret)
>                 goto out;
>
> -       ret = gcm_crypt(con, false, sgt.sgl, sgt.sgl,
> -                       tail_onwire_len(con->in_msg, true));
> +       dout("%s con %p msg %p enc_page_cnt %d sg_cnt %d\n", __func__, con,
> +            con->in_msg, con->v2.in_enc_page_cnt, sgt.orig_nents);
> +       ret = gcm_crypt(con, false, enc_sgt.sgl, sgt.sgl, tail_len);
> +       if (ret)
> +               goto out;
> +
> +       WARN_ON(!con->v2.in_enc_page_cnt);
> +       ceph_release_page_vector(con->v2.in_enc_pages,
> +                                con->v2.in_enc_page_cnt);
> +       con->v2.in_enc_pages = NULL;
> +       con->v2.in_enc_page_cnt = 0;
>
>  out:
>         sg_free_table(&sgt);
> +       sg_free_table(&enc_sgt);
>         return ret;
>  }
>
> @@ -1737,8 +1757,7 @@ static void prepare_read_data(struct ceph_connection *con)
>  {
>         struct bio_vec bv;
>
> -       if (!con_secure(con))
> -               con->in_data_crc = -1;
> +       con->in_data_crc = -1;
>         ceph_msg_data_cursor_init(&con->v2.in_cursor, con->in_msg,
>                                   data_len(con->in_msg));
>
> @@ -1751,11 +1770,10 @@ static void prepare_read_data_cont(struct ceph_connection *con)
>  {
>         struct bio_vec bv;
>
> -       if (!con_secure(con))
> -               con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
> -                                                   con->v2.in_bvec.bv_page,
> -                                                   con->v2.in_bvec.bv_offset,
> -                                                   con->v2.in_bvec.bv_len);
> +       con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
> +                                           con->v2.in_bvec.bv_page,
> +                                           con->v2.in_bvec.bv_offset,
> +                                           con->v2.in_bvec.bv_len);
>
>         ceph_msg_data_advance(&con->v2.in_cursor, con->v2.in_bvec.bv_len);
>         if (con->v2.in_cursor.total_resid) {
> @@ -1766,21 +1784,100 @@ static void prepare_read_data_cont(struct ceph_connection *con)
>         }
>
>         /*
> -        * We've read all data.  Prepare to read data padding (if any)
> -        * and epilogue.
> +        * We've read all data.  Prepare to read epilogue.
>          */
>         reset_in_kvecs(con);
> -       if (con_secure(con)) {
> -               if (need_padding(data_len(con->in_msg)))
> -                       add_in_kvec(con, DATA_PAD(con->v2.in_buf),
> -                                   padding_len(data_len(con->in_msg)));
> -               add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_SECURE_LEN);
> +       add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
> +       con->v2.in_state = IN_S_HANDLE_EPILOGUE;
> +}
> +
> +static void prepare_read_tail_plain(struct ceph_connection *con)
> +{
> +       struct ceph_msg *msg = con->in_msg;
> +
> +       if (!front_len(msg) && !middle_len(msg)) {
> +               WARN_ON(!data_len(msg));
> +               prepare_read_data(con);
> +               return;
> +       }
> +
> +       reset_in_kvecs(con);
> +       if (front_len(msg)) {
> +               WARN_ON(front_len(msg) > msg->front_alloc_len);
> +               add_in_kvec(con, msg->front.iov_base, front_len(msg));
> +               msg->front.iov_len = front_len(msg);
> +       } else {
> +               msg->front.iov_len = 0;
> +       }
> +       if (middle_len(msg)) {
> +               WARN_ON(middle_len(msg) > msg->middle->alloc_len);
> +               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
> +               msg->middle->vec.iov_len = middle_len(msg);
> +       } else if (msg->middle) {
> +               msg->middle->vec.iov_len = 0;
> +       }
> +
> +       if (data_len(msg)) {
> +               con->v2.in_state = IN_S_PREPARE_READ_DATA;
>         } else {
>                 add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
> +               con->v2.in_state = IN_S_HANDLE_EPILOGUE;
> +       }
> +}
> +
> +static void prepare_read_enc_page(struct ceph_connection *con)
> +{
> +       struct bio_vec bv;
> +
> +       dout("%s con %p i %d resid %d\n", __func__, con, con->v2.in_enc_i,
> +            con->v2.in_enc_resid);
> +       WARN_ON(!con->v2.in_enc_resid);
> +
> +       bv.bv_page = con->v2.in_enc_pages[con->v2.in_enc_i];
> +       bv.bv_offset = 0;
> +       bv.bv_len = min(con->v2.in_enc_resid, (int)PAGE_SIZE);
> +
> +       set_in_bvec(con, &bv);
> +       con->v2.in_enc_i++;
> +       con->v2.in_enc_resid -= bv.bv_len;
> +
> +       if (con->v2.in_enc_resid) {
> +               con->v2.in_state = IN_S_PREPARE_READ_ENC_PAGE;
> +               return;
>         }
> +
> +       /*
> +        * We are set to read the last piece of ciphertext (ending
> +        * with epilogue) + auth tag.
> +        */
> +       WARN_ON(con->v2.in_enc_i != con->v2.in_enc_page_cnt);
>         con->v2.in_state = IN_S_HANDLE_EPILOGUE;
>  }
>
> +static int prepare_read_tail_secure(struct ceph_connection *con)
> +{
> +       struct page **enc_pages;
> +       int enc_page_cnt;
> +       int tail_len;
> +
> +       tail_len = tail_onwire_len(con->in_msg, true);
> +       WARN_ON(!tail_len);
> +
> +       enc_page_cnt = calc_pages_for(0, tail_len);
> +       enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO);
> +       if (IS_ERR(enc_pages))
> +               return PTR_ERR(enc_pages);
> +
> +       WARN_ON(con->v2.in_enc_pages || con->v2.in_enc_page_cnt);
> +       con->v2.in_enc_pages = enc_pages;
> +       con->v2.in_enc_page_cnt = enc_page_cnt;
> +       con->v2.in_enc_resid = tail_len;
> +       con->v2.in_enc_i = 0;
> +
> +       prepare_read_enc_page(con);
> +       return 0;
> +}
> +
>  static void __finish_skip(struct ceph_connection *con)
>  {
>         con->in_seq++;
> @@ -2589,46 +2686,13 @@ static int __handle_control(struct ceph_connection *con, void *p)
>         }
>
>         msg = con->in_msg;  /* set in process_message_header() */
> -       if (!front_len(msg) && !middle_len(msg)) {
> -               if (!data_len(msg))
> -                       return process_message(con);
> -
> -               prepare_read_data(con);
> -               return 0;
> -       }
> -
> -       reset_in_kvecs(con);
> -       if (front_len(msg)) {
> -               WARN_ON(front_len(msg) > msg->front_alloc_len);
> -               add_in_kvec(con, msg->front.iov_base, front_len(msg));
> -               msg->front.iov_len = front_len(msg);
> -
> -               if (con_secure(con) && need_padding(front_len(msg)))
> -                       add_in_kvec(con, FRONT_PAD(con->v2.in_buf),
> -                                   padding_len(front_len(msg)));
> -       } else {
> -               msg->front.iov_len = 0;
> -       }
> -       if (middle_len(msg)) {
> -               WARN_ON(middle_len(msg) > msg->middle->alloc_len);
> -               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
> -               msg->middle->vec.iov_len = middle_len(msg);
> +       if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
> +               return process_message(con);
>
> -               if (con_secure(con) && need_padding(middle_len(msg)))
> -                       add_in_kvec(con, MIDDLE_PAD(con->v2.in_buf),
> -                                   padding_len(middle_len(msg)));
> -       } else if (msg->middle) {
> -               msg->middle->vec.iov_len = 0;
> -       }
> +       if (con_secure(con))
> +               return prepare_read_tail_secure(con);

This isn't quite right: the front and/or middle iov_len isn't set in
secure mode.  In most cases it's irrelevant but it does cause issues
with code like:

    void *p = buf;
    void *end = buf + len;

    ...
    advance p
    ...

    if (p != end)
            goto bad;

I have folded in the attached incremental.

Thanks,

                Ilya
diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c
index 8a101f5d4c23..c81379f93ad5 100644
--- a/net/ceph/messenger_v2.c
+++ b/net/ceph/messenger_v2.c
@@ -1834,18 +1834,12 @@ static int prepare_read_tail_plain(struct ceph_connection *con)
 
 	reset_in_kvecs(con);
 	if (front_len(msg)) {
-		WARN_ON(front_len(msg) > msg->front_alloc_len);
 		add_in_kvec(con, msg->front.iov_base, front_len(msg));
-		msg->front.iov_len = front_len(msg);
-	} else {
-		msg->front.iov_len = 0;
+		WARN_ON(msg->front.iov_len != front_len(msg));
 	}
 	if (middle_len(msg)) {
-		WARN_ON(middle_len(msg) > msg->middle->alloc_len);
 		add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
-		msg->middle->vec.iov_len = middle_len(msg);
-	} else if (msg->middle) {
-		msg->middle->vec.iov_len = 0;
+		WARN_ON(msg->middle->vec.iov_len != middle_len(msg));
 	}
 
 	if (data_len(msg)) {
@@ -2718,6 +2712,19 @@ static int __handle_control(struct ceph_connection *con, void *p)
 	}
 
 	msg = con->in_msg;  /* set in process_message_header() */
+	if (front_len(msg)) {
+		WARN_ON(front_len(msg) > msg->front_alloc_len);
+		msg->front.iov_len = front_len(msg);
+	} else {
+		msg->front.iov_len = 0;
+	}
+	if (middle_len(msg)) {
+		WARN_ON(middle_len(msg) > msg->middle->alloc_len);
+		msg->middle->vec.iov_len = middle_len(msg);
+	} else if (msg->middle) {
+		msg->middle->vec.iov_len = 0;
+	}
+
 	if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
 		return process_message(con);
 

[Index of Archives]     [CEPH Users]     [Ceph Large]     [Ceph Dev]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux