Skip to content

Commit 2ea8871

Browse files
committed
libceph: make recv path in secure mode work the same as send path
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/[email protected]/ Signed-off-by: Ilya Dryomov <[email protected]> Reviewed-by: Jeff Layton <[email protected]>
1 parent 26291c5 commit 2ea8871

File tree

2 files changed

+158
-62
lines changed

2 files changed

+158
-62
lines changed

include/linux/ceph/messenger.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ struct ceph_connection_v2_info {
383383
struct ceph_gcm_nonce in_gcm_nonce;
384384
struct ceph_gcm_nonce out_gcm_nonce;
385385

386+
struct page **in_enc_pages;
387+
int in_enc_page_cnt;
388+
int in_enc_resid;
389+
int in_enc_i;
386390
struct page **out_enc_pages;
387391
int out_enc_page_cnt;
388392
int out_enc_resid;

net/ceph/messenger_v2.c

Lines changed: 154 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@
5757
#define IN_S_HANDLE_CONTROL_REMAINDER 3
5858
#define IN_S_PREPARE_READ_DATA 4
5959
#define IN_S_PREPARE_READ_DATA_CONT 5
60-
#define IN_S_HANDLE_EPILOGUE 6
61-
#define IN_S_FINISH_SKIP 7
60+
#define IN_S_PREPARE_READ_ENC_PAGE 6
61+
#define IN_S_HANDLE_EPILOGUE 7
62+
#define IN_S_FINISH_SKIP 8
6263

6364
#define OUT_S_QUEUE_DATA 1
6465
#define OUT_S_QUEUE_DATA_CONT 2
@@ -1032,22 +1033,41 @@ static int decrypt_control_remainder(struct ceph_connection *con)
10321033
padded_len(rem_len) + CEPH_GCM_TAG_LEN);
10331034
}
10341035

1035-
static int decrypt_message(struct ceph_connection *con)
1036+
static int decrypt_tail(struct ceph_connection *con)
10361037
{
1038+
struct sg_table enc_sgt = {};
10371039
struct sg_table sgt = {};
1040+
int tail_len;
10381041
int ret;
10391042

1043+
tail_len = tail_onwire_len(con->in_msg, true);
1044+
ret = sg_alloc_table_from_pages(&enc_sgt, con->v2.in_enc_pages,
1045+
con->v2.in_enc_page_cnt, 0, tail_len,
1046+
GFP_NOIO);
1047+
if (ret)
1048+
goto out;
1049+
10401050
ret = setup_message_sgs(&sgt, con->in_msg, FRONT_PAD(con->v2.in_buf),
10411051
MIDDLE_PAD(con->v2.in_buf), DATA_PAD(con->v2.in_buf),
10421052
con->v2.in_buf, true);
10431053
if (ret)
10441054
goto out;
10451055

1046-
ret = gcm_crypt(con, false, sgt.sgl, sgt.sgl,
1047-
tail_onwire_len(con->in_msg, true));
1056+
dout("%s con %p msg %p enc_page_cnt %d sg_cnt %d\n", __func__, con,
1057+
con->in_msg, con->v2.in_enc_page_cnt, sgt.orig_nents);
1058+
ret = gcm_crypt(con, false, enc_sgt.sgl, sgt.sgl, tail_len);
1059+
if (ret)
1060+
goto out;
1061+
1062+
WARN_ON(!con->v2.in_enc_page_cnt);
1063+
ceph_release_page_vector(con->v2.in_enc_pages,
1064+
con->v2.in_enc_page_cnt);
1065+
con->v2.in_enc_pages = NULL;
1066+
con->v2.in_enc_page_cnt = 0;
10481067

10491068
out:
10501069
sg_free_table(&sgt);
1070+
sg_free_table(&enc_sgt);
10511071
return ret;
10521072
}
10531073

@@ -1737,8 +1757,7 @@ static void prepare_read_data(struct ceph_connection *con)
17371757
{
17381758
struct bio_vec bv;
17391759

1740-
if (!con_secure(con))
1741-
con->in_data_crc = -1;
1760+
con->in_data_crc = -1;
17421761
ceph_msg_data_cursor_init(&con->v2.in_cursor, con->in_msg,
17431762
data_len(con->in_msg));
17441763

@@ -1751,11 +1770,10 @@ static void prepare_read_data_cont(struct ceph_connection *con)
17511770
{
17521771
struct bio_vec bv;
17531772

1754-
if (!con_secure(con))
1755-
con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
1756-
con->v2.in_bvec.bv_page,
1757-
con->v2.in_bvec.bv_offset,
1758-
con->v2.in_bvec.bv_len);
1773+
con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
1774+
con->v2.in_bvec.bv_page,
1775+
con->v2.in_bvec.bv_offset,
1776+
con->v2.in_bvec.bv_len);
17591777

17601778
ceph_msg_data_advance(&con->v2.in_cursor, con->v2.in_bvec.bv_len);
17611779
if (con->v2.in_cursor.total_resid) {
@@ -1766,21 +1784,94 @@ static void prepare_read_data_cont(struct ceph_connection *con)
17661784
}
17671785

17681786
/*
1769-
* We've read all data. Prepare to read data padding (if any)
1770-
* and epilogue.
1787+
* We've read all data. Prepare to read epilogue.
17711788
*/
17721789
reset_in_kvecs(con);
1773-
if (con_secure(con)) {
1774-
if (need_padding(data_len(con->in_msg)))
1775-
add_in_kvec(con, DATA_PAD(con->v2.in_buf),
1776-
padding_len(data_len(con->in_msg)));
1777-
add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_SECURE_LEN);
1790+
add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
1791+
con->v2.in_state = IN_S_HANDLE_EPILOGUE;
1792+
}
1793+
1794+
static void prepare_read_tail_plain(struct ceph_connection *con)
1795+
{
1796+
struct ceph_msg *msg = con->in_msg;
1797+
1798+
if (!front_len(msg) && !middle_len(msg)) {
1799+
WARN_ON(!data_len(msg));
1800+
prepare_read_data(con);
1801+
return;
1802+
}
1803+
1804+
reset_in_kvecs(con);
1805+
if (front_len(msg)) {
1806+
add_in_kvec(con, msg->front.iov_base, front_len(msg));
1807+
WARN_ON(msg->front.iov_len != front_len(msg));
1808+
}
1809+
if (middle_len(msg)) {
1810+
add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
1811+
WARN_ON(msg->middle->vec.iov_len != middle_len(msg));
1812+
}
1813+
1814+
if (data_len(msg)) {
1815+
con->v2.in_state = IN_S_PREPARE_READ_DATA;
17781816
} else {
17791817
add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
1818+
con->v2.in_state = IN_S_HANDLE_EPILOGUE;
1819+
}
1820+
}
1821+
1822+
static void prepare_read_enc_page(struct ceph_connection *con)
1823+
{
1824+
struct bio_vec bv;
1825+
1826+
dout("%s con %p i %d resid %d\n", __func__, con, con->v2.in_enc_i,
1827+
con->v2.in_enc_resid);
1828+
WARN_ON(!con->v2.in_enc_resid);
1829+
1830+
bv.bv_page = con->v2.in_enc_pages[con->v2.in_enc_i];
1831+
bv.bv_offset = 0;
1832+
bv.bv_len = min(con->v2.in_enc_resid, (int)PAGE_SIZE);
1833+
1834+
set_in_bvec(con, &bv);
1835+
con->v2.in_enc_i++;
1836+
con->v2.in_enc_resid -= bv.bv_len;
1837+
1838+
if (con->v2.in_enc_resid) {
1839+
con->v2.in_state = IN_S_PREPARE_READ_ENC_PAGE;
1840+
return;
17801841
}
1842+
1843+
/*
1844+
* We are set to read the last piece of ciphertext (ending
1845+
* with epilogue) + auth tag.
1846+
*/
1847+
WARN_ON(con->v2.in_enc_i != con->v2.in_enc_page_cnt);
17811848
con->v2.in_state = IN_S_HANDLE_EPILOGUE;
17821849
}
17831850

1851+
static int prepare_read_tail_secure(struct ceph_connection *con)
1852+
{
1853+
struct page **enc_pages;
1854+
int enc_page_cnt;
1855+
int tail_len;
1856+
1857+
tail_len = tail_onwire_len(con->in_msg, true);
1858+
WARN_ON(!tail_len);
1859+
1860+
enc_page_cnt = calc_pages_for(0, tail_len);
1861+
enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO);
1862+
if (IS_ERR(enc_pages))
1863+
return PTR_ERR(enc_pages);
1864+
1865+
WARN_ON(con->v2.in_enc_pages || con->v2.in_enc_page_cnt);
1866+
con->v2.in_enc_pages = enc_pages;
1867+
con->v2.in_enc_page_cnt = enc_page_cnt;
1868+
con->v2.in_enc_resid = tail_len;
1869+
con->v2.in_enc_i = 0;
1870+
1871+
prepare_read_enc_page(con);
1872+
return 0;
1873+
}
1874+
17841875
static void __finish_skip(struct ceph_connection *con)
17851876
{
17861877
con->in_seq++;
@@ -2589,46 +2680,26 @@ static int __handle_control(struct ceph_connection *con, void *p)
25892680
}
25902681

25912682
msg = con->in_msg; /* set in process_message_header() */
2592-
if (!front_len(msg) && !middle_len(msg)) {
2593-
if (!data_len(msg))
2594-
return process_message(con);
2595-
2596-
prepare_read_data(con);
2597-
return 0;
2598-
}
2599-
2600-
reset_in_kvecs(con);
26012683
if (front_len(msg)) {
26022684
WARN_ON(front_len(msg) > msg->front_alloc_len);
2603-
add_in_kvec(con, msg->front.iov_base, front_len(msg));
26042685
msg->front.iov_len = front_len(msg);
2605-
2606-
if (con_secure(con) && need_padding(front_len(msg)))
2607-
add_in_kvec(con, FRONT_PAD(con->v2.in_buf),
2608-
padding_len(front_len(msg)));
26092686
} else {
26102687
msg->front.iov_len = 0;
26112688
}
26122689
if (middle_len(msg)) {
26132690
WARN_ON(middle_len(msg) > msg->middle->alloc_len);
2614-
add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
26152691
msg->middle->vec.iov_len = middle_len(msg);
2616-
2617-
if (con_secure(con) && need_padding(middle_len(msg)))
2618-
add_in_kvec(con, MIDDLE_PAD(con->v2.in_buf),
2619-
padding_len(middle_len(msg)));
26202692
} else if (msg->middle) {
26212693
msg->middle->vec.iov_len = 0;
26222694
}
26232695

2624-
if (data_len(msg)) {
2625-
con->v2.in_state = IN_S_PREPARE_READ_DATA;
2626-
} else {
2627-
add_in_kvec(con, con->v2.in_buf,
2628-
con_secure(con) ? CEPH_EPILOGUE_SECURE_LEN :
2629-
CEPH_EPILOGUE_PLAIN_LEN);
2630-
con->v2.in_state = IN_S_HANDLE_EPILOGUE;
2631-
}
2696+
if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
2697+
return process_message(con);
2698+
2699+
if (con_secure(con))
2700+
return prepare_read_tail_secure(con);
2701+
2702+
prepare_read_tail_plain(con);
26322703
return 0;
26332704
}
26342705

@@ -2717,7 +2788,7 @@ static int handle_epilogue(struct ceph_connection *con)
27172788
int ret;
27182789

27192790
if (con_secure(con)) {
2720-
ret = decrypt_message(con);
2791+
ret = decrypt_tail(con);
27212792
if (ret) {
27222793
if (ret == -EBADMSG)
27232794
con->error_msg = "integrity error, bad epilogue auth tag";
@@ -2792,6 +2863,10 @@ static int populate_in_iter(struct ceph_connection *con)
27922863
prepare_read_data_cont(con);
27932864
ret = 0;
27942865
break;
2866+
case IN_S_PREPARE_READ_ENC_PAGE:
2867+
prepare_read_enc_page(con);
2868+
ret = 0;
2869+
break;
27952870
case IN_S_HANDLE_EPILOGUE:
27962871
ret = handle_epilogue(con);
27972872
break;
@@ -3326,20 +3401,16 @@ void ceph_con_v2_revoke(struct ceph_connection *con)
33263401

33273402
static void revoke_at_prepare_read_data(struct ceph_connection *con)
33283403
{
3329-
int remaining; /* data + [data padding] + epilogue */
3404+
int remaining;
33303405
int resid;
33313406

3407+
WARN_ON(con_secure(con));
33323408
WARN_ON(!data_len(con->in_msg));
33333409
WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
33343410
resid = iov_iter_count(&con->v2.in_iter);
33353411
WARN_ON(!resid);
33363412

3337-
if (con_secure(con))
3338-
remaining = padded_len(data_len(con->in_msg)) +
3339-
CEPH_EPILOGUE_SECURE_LEN;
3340-
else
3341-
remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
3342-
3413+
remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
33433414
dout("%s con %p resid %d remaining %d\n", __func__, con, resid,
33443415
remaining);
33453416
con->v2.in_iter.count -= resid;
@@ -3350,8 +3421,9 @@ static void revoke_at_prepare_read_data(struct ceph_connection *con)
33503421
static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
33513422
{
33523423
int recved, resid; /* current piece of data */
3353-
int remaining; /* [data padding] + epilogue */
3424+
int remaining;
33543425

3426+
WARN_ON(con_secure(con));
33553427
WARN_ON(!data_len(con->in_msg));
33563428
WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
33573429
resid = iov_iter_count(&con->v2.in_iter);
@@ -3363,24 +3435,34 @@ static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
33633435
ceph_msg_data_advance(&con->v2.in_cursor, recved);
33643436
WARN_ON(resid > con->v2.in_cursor.total_resid);
33653437

3366-
if (con_secure(con))
3367-
remaining = padding_len(data_len(con->in_msg)) +
3368-
CEPH_EPILOGUE_SECURE_LEN;
3369-
else
3370-
remaining = CEPH_EPILOGUE_PLAIN_LEN;
3371-
3438+
remaining = CEPH_EPILOGUE_PLAIN_LEN;
33723439
dout("%s con %p total_resid %zu remaining %d\n", __func__, con,
33733440
con->v2.in_cursor.total_resid, remaining);
33743441
con->v2.in_iter.count -= resid;
33753442
set_in_skip(con, con->v2.in_cursor.total_resid + remaining);
33763443
con->v2.in_state = IN_S_FINISH_SKIP;
33773444
}
33783445

3446+
static void revoke_at_prepare_read_enc_page(struct ceph_connection *con)
3447+
{
3448+
int resid; /* current enc page (not necessarily data) */
3449+
3450+
WARN_ON(!con_secure(con));
3451+
WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
3452+
resid = iov_iter_count(&con->v2.in_iter);
3453+
WARN_ON(!resid || resid > con->v2.in_bvec.bv_len);
3454+
3455+
dout("%s con %p resid %d enc_resid %d\n", __func__, con, resid,
3456+
con->v2.in_enc_resid);
3457+
con->v2.in_iter.count -= resid;
3458+
set_in_skip(con, resid + con->v2.in_enc_resid);
3459+
con->v2.in_state = IN_S_FINISH_SKIP;
3460+
}
3461+
33793462
static void revoke_at_handle_epilogue(struct ceph_connection *con)
33803463
{
33813464
int resid;
33823465

3383-
WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
33843466
resid = iov_iter_count(&con->v2.in_iter);
33853467
WARN_ON(!resid);
33863468

@@ -3399,6 +3481,9 @@ void ceph_con_v2_revoke_incoming(struct ceph_connection *con)
33993481
case IN_S_PREPARE_READ_DATA_CONT:
34003482
revoke_at_prepare_read_data_cont(con);
34013483
break;
3484+
case IN_S_PREPARE_READ_ENC_PAGE:
3485+
revoke_at_prepare_read_enc_page(con);
3486+
break;
34023487
case IN_S_HANDLE_EPILOGUE:
34033488
revoke_at_handle_epilogue(con);
34043489
break;
@@ -3432,6 +3517,13 @@ void ceph_con_v2_reset_protocol(struct ceph_connection *con)
34323517
clear_out_sign_kvecs(con);
34333518
free_conn_bufs(con);
34343519

3520+
if (con->v2.in_enc_pages) {
3521+
WARN_ON(!con->v2.in_enc_page_cnt);
3522+
ceph_release_page_vector(con->v2.in_enc_pages,
3523+
con->v2.in_enc_page_cnt);
3524+
con->v2.in_enc_pages = NULL;
3525+
con->v2.in_enc_page_cnt = 0;
3526+
}
34353527
if (con->v2.out_enc_pages) {
34363528
WARN_ON(!con->v2.out_enc_page_cnt);
34373529
ceph_release_page_vector(con->v2.out_enc_pages,

0 commit comments

Comments
 (0)