aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTyler Hicks <tyhicks@linux.vnet.ibm.com>2009-03-20 02:25:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-03-22 14:20:43 -0400
commit8faece5f906725c10e7a1f6caf84452abadbdc7b (patch)
treebbe7d6cba67c909fbc86fc63dbfa1cf0d3cb12bc /fs
parent18a0d89e54ca0f6f33582f99ae39867b2c975559 (diff)
eCryptfs: Allocate a variable number of pages for file headers
When allocating the memory used to store the eCryptfs header contents, a single, zeroed page was being allocated with get_zeroed_page(). However, the size of an eCryptfs header is either PAGE_CACHE_SIZE or ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE (8192), whichever is larger, and is stored in the file's private_data->crypt_stat->num_header_bytes_at_front field. ecryptfs_write_metadata_to_contents() was using num_header_bytes_at_front to decide how many bytes should be written to the lower filesystem for the file header. Unfortunately, at least 8K was being written from the page, despite the chance of the single, zeroed page being smaller than 8K. This resulted in random areas of kernel memory being written between the 0x1000 and 0x1FFF bytes offsets in the eCryptfs file headers if PAGE_SIZE was 4K. This patch allocates a variable number of pages, calculated with num_header_bytes_at_front, and passes the number of allocated pages along to ecryptfs_write_metadata_to_contents(). Thanks to Florian Streibelt for reporting the data leak and working with me to find the problem. 2.6.28 is the only kernel release with this vulnerability. Corresponds to CVE-2009-0787 Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com> Acked-by: Dustin Kirkland <kirkland@canonical.com> Reviewed-by: Eric Sandeen <sandeen@redhat.com> Reviewed-by: Eugene Teo <eugeneteo@kernel.sg> Cc: Greg KH <greg@kroah.com> Cc: dann frazier <dannf@dannf.org> Cc: Serge E. Hallyn <serue@us.ibm.com> Cc: Florian Streibelt <florian@f-streibelt.de> Cc: stable@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/ecryptfs/crypto.c39
1 files changed, 26 insertions, 13 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index bdca1f4b3a3e..75bee99de0f6 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1324,14 +1324,13 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t max,
1324} 1324}
1325 1325
1326static int 1326static int
1327ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, 1327ecryptfs_write_metadata_to_contents(struct dentry *ecryptfs_dentry,
1328 struct dentry *ecryptfs_dentry, 1328 char *virt, size_t virt_len)
1329 char *virt)
1330{ 1329{
1331 int rc; 1330 int rc;
1332 1331
1333 rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt, 1332 rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
1334 0, crypt_stat->num_header_bytes_at_front); 1333 0, virt_len);
1335 if (rc) 1334 if (rc)
1336 printk(KERN_ERR "%s: Error attempting to write header " 1335 printk(KERN_ERR "%s: Error attempting to write header "
1337 "information to lower file; rc = [%d]\n", __func__, 1336 "information to lower file; rc = [%d]\n", __func__,
@@ -1341,7 +1340,6 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
1341 1340
1342static int 1341static int
1343ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, 1342ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
1344 struct ecryptfs_crypt_stat *crypt_stat,
1345 char *page_virt, size_t size) 1343 char *page_virt, size_t size)
1346{ 1344{
1347 int rc; 1345 int rc;
@@ -1351,6 +1349,17 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
1351 return rc; 1349 return rc;
1352} 1350}
1353 1351
1352static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask,
1353 unsigned int order)
1354{
1355 struct page *page;
1356
1357 page = alloc_pages(gfp_mask | __GFP_ZERO, order);
1358 if (page)
1359 return (unsigned long) page_address(page);
1360 return 0;
1361}
1362
1354/** 1363/**
1355 * ecryptfs_write_metadata 1364 * ecryptfs_write_metadata
1356 * @ecryptfs_dentry: The eCryptfs dentry 1365 * @ecryptfs_dentry: The eCryptfs dentry
@@ -1367,7 +1376,9 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
1367{ 1376{
1368 struct ecryptfs_crypt_stat *crypt_stat = 1377 struct ecryptfs_crypt_stat *crypt_stat =
1369 &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; 1378 &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
1379 unsigned int order;
1370 char *virt; 1380 char *virt;
1381 size_t virt_len;
1371 size_t size = 0; 1382 size_t size = 0;
1372 int rc = 0; 1383 int rc = 0;
1373 1384
@@ -1383,33 +1394,35 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
1383 rc = -EINVAL; 1394 rc = -EINVAL;
1384 goto out; 1395 goto out;
1385 } 1396 }
1397 virt_len = crypt_stat->num_header_bytes_at_front;
1398 order = get_order(virt_len);
1386 /* Released in this function */ 1399 /* Released in this function */
1387 virt = (char *)get_zeroed_page(GFP_KERNEL); 1400 virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order);
1388 if (!virt) { 1401 if (!virt) {
1389 printk(KERN_ERR "%s: Out of memory\n", __func__); 1402 printk(KERN_ERR "%s: Out of memory\n", __func__);
1390 rc = -ENOMEM; 1403 rc = -ENOMEM;
1391 goto out; 1404 goto out;
1392 } 1405 }
1393 rc = ecryptfs_write_headers_virt(virt, PAGE_CACHE_SIZE, &size, 1406 rc = ecryptfs_write_headers_virt(virt, virt_len, &size, crypt_stat,
1394 crypt_stat, ecryptfs_dentry); 1407 ecryptfs_dentry);
1395 if (unlikely(rc)) { 1408 if (unlikely(rc)) {
1396 printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n", 1409 printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
1397 __func__, rc); 1410 __func__, rc);
1398 goto out_free; 1411 goto out_free;
1399 } 1412 }
1400 if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) 1413 if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
1401 rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, 1414 rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, virt,
1402 crypt_stat, virt, size); 1415 size);
1403 else 1416 else
1404 rc = ecryptfs_write_metadata_to_contents(crypt_stat, 1417 rc = ecryptfs_write_metadata_to_contents(ecryptfs_dentry, virt,
1405 ecryptfs_dentry, virt); 1418 virt_len);
1406 if (rc) { 1419 if (rc) {
1407 printk(KERN_ERR "%s: Error writing metadata out to lower file; " 1420 printk(KERN_ERR "%s: Error writing metadata out to lower file; "
1408 "rc = [%d]\n", __func__, rc); 1421 "rc = [%d]\n", __func__, rc);
1409 goto out_free; 1422 goto out_free;
1410 } 1423 }
1411out_free: 1424out_free:
1412 free_page((unsigned long)virt); 1425 free_pages((unsigned long)virt, order);
1413out: 1426out:
1414 return rc; 1427 return rc;
1415} 1428}