Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ceph: add infrastructure for file encryption and decryption

...and allow test_dummy_encryption to bypass content encryption
if mounted with test_dummy_encryption=clear.

[ xiubli: remove test_dummy_encryption=clear support per Ilya ]

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Reviewed-and-tested-by: Luís Henriques <lhenriques@suse.de>
Reviewed-by: Milind Changire <mchangir@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>

authored by

Jeff Layton and committed by
Ilya Dryomov
77cdb7e1 0d91f0ad

+251
+171
fs/ceph/crypto.c
··· 9 9 #include <linux/ceph/ceph_debug.h> 10 10 #include <linux/xattr.h> 11 11 #include <linux/fscrypt.h> 12 + #include <linux/ceph/striper.h> 12 13 13 14 #include "super.h" 14 15 #include "mds_client.h" ··· 365 364 return 1; 366 365 } 367 366 return 0; 367 + } 368 + 369 + int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode, 370 + struct page *page, unsigned int len, 371 + unsigned int offs, u64 lblk_num) 372 + { 373 + dout("%s: len %u offs %u blk %llu\n", __func__, len, offs, lblk_num); 374 + return fscrypt_decrypt_block_inplace(inode, page, len, offs, lblk_num); 375 + } 376 + 377 + int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode, 378 + struct page *page, unsigned int len, 379 + unsigned int offs, u64 lblk_num, 380 + gfp_t gfp_flags) 381 + { 382 + dout("%s: len %u offs %u blk %llu\n", __func__, len, offs, lblk_num); 383 + return fscrypt_encrypt_block_inplace(inode, page, len, offs, lblk_num, 384 + gfp_flags); 385 + } 386 + 387 + /** 388 + * ceph_fscrypt_decrypt_pages - decrypt an array of pages 389 + * @inode: pointer to inode associated with these pages 390 + * @page: pointer to page array 391 + * @off: offset into the file that the read data starts 392 + * @len: max length to decrypt 393 + * 394 + * Decrypt an array of fscrypt'ed pages and return the amount of 395 + * data decrypted. Any data in the page prior to the start of the 396 + * first complete block in the read is ignored. Any incomplete 397 + * crypto blocks at the end of the array are ignored (and should 398 + * probably be zeroed by the caller). 399 + * 400 + * Returns the length of the decrypted data or a negative errno. 401 + */ 402 + int ceph_fscrypt_decrypt_pages(struct inode *inode, struct page **page, 403 + u64 off, int len) 404 + { 405 + int i, num_blocks; 406 + u64 baseblk = off >> CEPH_FSCRYPT_BLOCK_SHIFT; 407 + int ret = 0; 408 + 409 + /* 410 + * We can't deal with partial blocks on an encrypted file, so mask off 411 + * the last bit. 412 + */ 413 + num_blocks = ceph_fscrypt_blocks(off, len & CEPH_FSCRYPT_BLOCK_MASK); 414 + 415 + /* Decrypt each block */ 416 + for (i = 0; i < num_blocks; ++i) { 417 + int blkoff = i << CEPH_FSCRYPT_BLOCK_SHIFT; 418 + int pgidx = blkoff >> PAGE_SHIFT; 419 + unsigned int pgoffs = offset_in_page(blkoff); 420 + int fret; 421 + 422 + fret = ceph_fscrypt_decrypt_block_inplace(inode, page[pgidx], 423 + CEPH_FSCRYPT_BLOCK_SIZE, pgoffs, 424 + baseblk + i); 425 + if (fret < 0) { 426 + if (ret == 0) 427 + ret = fret; 428 + break; 429 + } 430 + ret += CEPH_FSCRYPT_BLOCK_SIZE; 431 + } 432 + return ret; 433 + } 434 + 435 + /** 436 + * ceph_fscrypt_decrypt_extents: decrypt received extents in given buffer 437 + * @inode: inode associated with pages being decrypted 438 + * @page: pointer to page array 439 + * @off: offset into the file that the data in page[0] starts 440 + * @map: pointer to extent array 441 + * @ext_cnt: length of extent array 442 + * 443 + * Given an extent map and a page array, decrypt the received data in-place, 444 + * skipping holes. Returns the offset into buffer of end of last decrypted 445 + * block. 446 + */ 447 + int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page, 448 + u64 off, struct ceph_sparse_extent *map, 449 + u32 ext_cnt) 450 + { 451 + int i, ret = 0; 452 + struct ceph_inode_info *ci = ceph_inode(inode); 453 + u64 objno, objoff; 454 + u32 xlen; 455 + 456 + /* Nothing to do for empty array */ 457 + if (ext_cnt == 0) { 458 + dout("%s: empty array, ret 0\n", __func__); 459 + return 0; 460 + } 461 + 462 + ceph_calc_file_object_mapping(&ci->i_layout, off, map[0].len, 463 + &objno, &objoff, &xlen); 464 + 465 + for (i = 0; i < ext_cnt; ++i) { 466 + struct ceph_sparse_extent *ext = &map[i]; 467 + int pgsoff = ext->off - objoff; 468 + int pgidx = pgsoff >> PAGE_SHIFT; 469 + int fret; 470 + 471 + if ((ext->off | ext->len) & ~CEPH_FSCRYPT_BLOCK_MASK) { 472 + pr_warn("%s: bad encrypted sparse extent idx %d off %llx len %llx\n", 473 + __func__, i, ext->off, ext->len); 474 + return -EIO; 475 + } 476 + fret = ceph_fscrypt_decrypt_pages(inode, &page[pgidx], 477 + off + pgsoff, ext->len); 478 + dout("%s: [%d] 0x%llx~0x%llx fret %d\n", __func__, i, 479 + ext->off, ext->len, fret); 480 + if (fret < 0) { 481 + if (ret == 0) 482 + ret = fret; 483 + break; 484 + } 485 + ret = pgsoff + fret; 486 + } 487 + dout("%s: ret %d\n", __func__, ret); 488 + return ret; 489 + } 490 + 491 + /** 492 + * ceph_fscrypt_encrypt_pages - encrypt an array of pages 493 + * @inode: pointer to inode associated with these pages 494 + * @page: pointer to page array 495 + * @off: offset into the file that the data starts 496 + * @len: max length to encrypt 497 + * @gfp: gfp flags to use for allocation 498 + * 499 + * Decrypt an array of cleartext pages and return the amount of 500 + * data encrypted. Any data in the page prior to the start of the 501 + * first complete block in the read is ignored. Any incomplete 502 + * crypto blocks at the end of the array are ignored. 503 + * 504 + * Returns the length of the encrypted data or a negative errno. 505 + */ 506 + int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off, 507 + int len, gfp_t gfp) 508 + { 509 + int i, num_blocks; 510 + u64 baseblk = off >> CEPH_FSCRYPT_BLOCK_SHIFT; 511 + int ret = 0; 512 + 513 + /* 514 + * We can't deal with partial blocks on an encrypted file, so mask off 515 + * the last bit. 516 + */ 517 + num_blocks = ceph_fscrypt_blocks(off, len & CEPH_FSCRYPT_BLOCK_MASK); 518 + 519 + /* Encrypt each block */ 520 + for (i = 0; i < num_blocks; ++i) { 521 + int blkoff = i << CEPH_FSCRYPT_BLOCK_SHIFT; 522 + int pgidx = blkoff >> PAGE_SHIFT; 523 + unsigned int pgoffs = offset_in_page(blkoff); 524 + int fret; 525 + 526 + fret = ceph_fscrypt_encrypt_block_inplace(inode, page[pgidx], 527 + CEPH_FSCRYPT_BLOCK_SIZE, pgoffs, 528 + baseblk + i, gfp); 529 + if (fret < 0) { 530 + if (ret == 0) 531 + ret = fret; 532 + break; 533 + } 534 + ret += CEPH_FSCRYPT_BLOCK_SIZE; 535 + } 536 + return ret; 368 537 }
+80
fs/ceph/crypto.h
··· 105 105 struct fscrypt_str *oname, bool *is_nokey); 106 106 int ceph_fscrypt_prepare_readdir(struct inode *dir); 107 107 108 + static inline unsigned int ceph_fscrypt_blocks(u64 off, u64 len) 109 + { 110 + /* crypto blocks cannot span more than one page */ 111 + BUILD_BUG_ON(CEPH_FSCRYPT_BLOCK_SHIFT > PAGE_SHIFT); 112 + 113 + return ((off+len+CEPH_FSCRYPT_BLOCK_SIZE-1) >> CEPH_FSCRYPT_BLOCK_SHIFT) - 114 + (off >> CEPH_FSCRYPT_BLOCK_SHIFT); 115 + } 116 + 117 + /* 118 + * If we have an encrypted inode then we must adjust the offset and 119 + * range of the on-the-wire read to cover an entire encryption block. 120 + * The copy will be done using the original offset and length, after 121 + * we've decrypted the result. 122 + */ 123 + static inline void ceph_fscrypt_adjust_off_and_len(struct inode *inode, 124 + u64 *off, u64 *len) 125 + { 126 + if (IS_ENCRYPTED(inode)) { 127 + *len = ceph_fscrypt_blocks(*off, *len) * CEPH_FSCRYPT_BLOCK_SIZE; 128 + *off &= CEPH_FSCRYPT_BLOCK_MASK; 129 + } 130 + } 131 + 132 + int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode, 133 + struct page *page, unsigned int len, 134 + unsigned int offs, u64 lblk_num); 135 + int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode, 136 + struct page *page, unsigned int len, 137 + unsigned int offs, u64 lblk_num, 138 + gfp_t gfp_flags); 139 + int ceph_fscrypt_decrypt_pages(struct inode *inode, struct page **page, 140 + u64 off, int len); 141 + int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page, 142 + u64 off, struct ceph_sparse_extent *map, 143 + u32 ext_cnt); 144 + int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off, 145 + int len, gfp_t gfp); 108 146 #else /* CONFIG_FS_ENCRYPTION */ 109 147 110 148 static inline void ceph_fscrypt_set_ops(struct super_block *sb) ··· 201 163 } 202 164 203 165 static inline int ceph_fscrypt_prepare_readdir(struct inode *dir) 166 + { 167 + return 0; 168 + } 169 + 170 + static inline void ceph_fscrypt_adjust_off_and_len(struct inode *inode, 171 + u64 *off, u64 *len) 172 + { 173 + } 174 + 175 + static inline int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode, 176 + struct page *page, unsigned int len, 177 + unsigned int offs, u64 lblk_num) 178 + { 179 + return 0; 180 + } 181 + 182 + static inline int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode, 183 + struct page *page, unsigned int len, 184 + unsigned int offs, u64 lblk_num, 185 + gfp_t gfp_flags) 186 + { 187 + return 0; 188 + } 189 + 190 + static inline int ceph_fscrypt_decrypt_pages(struct inode *inode, 191 + struct page **page, u64 off, 192 + int len) 193 + { 194 + return 0; 195 + } 196 + 197 + static inline int ceph_fscrypt_decrypt_extents(struct inode *inode, 198 + struct page **page, u64 off, 199 + struct ceph_sparse_extent *map, 200 + u32 ext_cnt) 201 + { 202 + return 0; 203 + } 204 + 205 + static inline int ceph_fscrypt_encrypt_pages(struct inode *inode, 206 + struct page **page, u64 off, 207 + int len, gfp_t gfp) 204 208 { 205 209 return 0; 206 210 }