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

eCryptfs: make ecryptfs_prepare_write decrypt the page

When the page is not up to date, ecryptfs_prepare_write() should be
acting much like ecryptfs_readpage(). This includes the painfully
obvious step of actually decrypting the page contents read from the
lower encrypted file.

Note that this patch resolves a bug in eCryptfs in 2.6.24 that one can
produce with these steps:

# mount -t ecryptfs /secret /secret
# echo "abc" > /secret/file.txt
# umount /secret
# mount -t ecryptfs /secret /secret
# echo "def" >> /secret/file.txt
# cat /secret/file.txt

Without this patch, the resulting data returned from cat is likely to
be something other than "abc\ndef\n".

(Thanks to Benedikt Driessen for reporting this.)

Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Cc: Benedikt Driessen <bdriessen@escrypt.com>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michael Halcrow and committed by
Linus Torvalds
e4465fda 87ffbe67

+76 -26
+76 -26
fs/ecryptfs/mmap.c
··· 263 263 return 0; 264 264 } 265 265 266 - /* This function must zero any hole we create */ 266 + /** 267 + * ecryptfs_prepare_write 268 + * @file: The eCryptfs file 269 + * @page: The eCryptfs page 270 + * @from: The start byte from which we will write 271 + * @to: The end byte to which we will write 272 + * 273 + * This function must zero any hole we create 274 + * 275 + * Returns zero on success; non-zero otherwise 276 + */ 267 277 static int ecryptfs_prepare_write(struct file *file, struct page *page, 268 278 unsigned from, unsigned to) 269 279 { 270 - int rc = 0; 271 280 loff_t prev_page_end_size; 281 + int rc = 0; 272 282 273 283 if (!PageUptodate(page)) { 274 - rc = ecryptfs_read_lower_page_segment(page, page->index, 0, 275 - PAGE_CACHE_SIZE, 276 - page->mapping->host); 277 - if (rc) { 278 - printk(KERN_ERR "%s: Error attemping to read lower " 279 - "page segment; rc = [%d]\n", __FUNCTION__, rc); 280 - ClearPageUptodate(page); 281 - goto out; 282 - } else 284 + struct ecryptfs_crypt_stat *crypt_stat = 285 + &ecryptfs_inode_to_private( 286 + file->f_path.dentry->d_inode)->crypt_stat; 287 + 288 + if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED) 289 + || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { 290 + rc = ecryptfs_read_lower_page_segment( 291 + page, page->index, 0, PAGE_CACHE_SIZE, 292 + page->mapping->host); 293 + if (rc) { 294 + printk(KERN_ERR "%s: Error attemping to read " 295 + "lower page segment; rc = [%d]\n", 296 + __FUNCTION__, rc); 297 + ClearPageUptodate(page); 298 + goto out; 299 + } else 300 + SetPageUptodate(page); 301 + } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { 302 + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { 303 + rc = ecryptfs_copy_up_encrypted_with_header( 304 + page, crypt_stat); 305 + if (rc) { 306 + printk(KERN_ERR "%s: Error attempting " 307 + "to copy the encrypted content " 308 + "from the lower file whilst " 309 + "inserting the metadata from " 310 + "the xattr into the header; rc " 311 + "= [%d]\n", __FUNCTION__, rc); 312 + ClearPageUptodate(page); 313 + goto out; 314 + } 315 + SetPageUptodate(page); 316 + } else { 317 + rc = ecryptfs_read_lower_page_segment( 318 + page, page->index, 0, PAGE_CACHE_SIZE, 319 + page->mapping->host); 320 + if (rc) { 321 + printk(KERN_ERR "%s: Error reading " 322 + "page; rc = [%d]\n", 323 + __FUNCTION__, rc); 324 + ClearPageUptodate(page); 325 + goto out; 326 + } 327 + SetPageUptodate(page); 328 + } 329 + } else { 330 + rc = ecryptfs_decrypt_page(page); 331 + if (rc) { 332 + printk(KERN_ERR "%s: Error decrypting page " 333 + "at index [%ld]; rc = [%d]\n", 334 + __FUNCTION__, page->index, rc); 335 + ClearPageUptodate(page); 336 + goto out; 337 + } 283 338 SetPageUptodate(page); 339 + } 284 340 } 285 - 286 341 prev_page_end_size = ((loff_t)page->index << PAGE_CACHE_SHIFT); 287 - 288 - /* 289 - * If creating a page or more of holes, zero them out via truncate. 290 - * Note, this will increase i_size. 291 - */ 342 + /* If creating a page or more of holes, zero them out via truncate. 343 + * Note, this will increase i_size. */ 292 344 if (page->index != 0) { 293 345 if (prev_page_end_size > i_size_read(page->mapping->host)) { 294 346 rc = ecryptfs_truncate(file->f_path.dentry, 295 347 prev_page_end_size); 296 348 if (rc) { 297 - printk(KERN_ERR "Error on attempt to " 349 + printk(KERN_ERR "%s: Error on attempt to " 298 350 "truncate to (higher) offset [%lld];" 299 - " rc = [%d]\n", prev_page_end_size, rc); 351 + " rc = [%d]\n", __FUNCTION__, 352 + prev_page_end_size, rc); 300 353 goto out; 301 354 } 302 355 } 303 356 } 304 - /* 305 - * Writing to a new page, and creating a small hole from start of page? 306 - * Zero it out. 307 - */ 308 - if ((i_size_read(page->mapping->host) == prev_page_end_size) && 309 - (from != 0)) { 357 + /* Writing to a new page, and creating a small hole from start 358 + * of page? Zero it out. */ 359 + if ((i_size_read(page->mapping->host) == prev_page_end_size) 360 + && (from != 0)) 310 361 zero_user(page, 0, PAGE_CACHE_SIZE); 311 - } 312 362 out: 313 363 return rc; 314 364 }