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.

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>

authored by

Tyler Hicks and committed by
Linus Torvalds
8faece5f 18a0d89e

+26 -13
+26 -13
fs/ecryptfs/crypto.c
··· 1324 1324 } 1325 1325 1326 1326 static int 1327 - ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, 1328 - struct dentry *ecryptfs_dentry, 1329 - char *virt) 1327 + ecryptfs_write_metadata_to_contents(struct dentry *ecryptfs_dentry, 1328 + char *virt, size_t virt_len) 1330 1329 { 1331 1330 int rc; 1332 1331 1333 1332 rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt, 1334 - 0, crypt_stat->num_header_bytes_at_front); 1333 + 0, virt_len); 1335 1334 if (rc) 1336 1335 printk(KERN_ERR "%s: Error attempting to write header " 1337 1336 "information to lower file; rc = [%d]\n", __func__, ··· 1340 1341 1341 1342 static int 1342 1343 ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, 1343 - struct ecryptfs_crypt_stat *crypt_stat, 1344 1344 char *page_virt, size_t size) 1345 1345 { 1346 1346 int rc; ··· 1347 1349 rc = ecryptfs_setxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, page_virt, 1348 1350 size, 0); 1349 1351 return rc; 1352 + } 1353 + 1354 + static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask, 1355 + unsigned int order) 1356 + { 1357 + struct page *page; 1358 + 1359 + page = alloc_pages(gfp_mask | __GFP_ZERO, order); 1360 + if (page) 1361 + return (unsigned long) page_address(page); 1362 + return 0; 1350 1363 } 1351 1364 1352 1365 /** ··· 1376 1367 { 1377 1368 struct ecryptfs_crypt_stat *crypt_stat = 1378 1369 &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; 1370 + unsigned int order; 1379 1371 char *virt; 1372 + size_t virt_len; 1380 1373 size_t size = 0; 1381 1374 int rc = 0; 1382 1375 ··· 1394 1383 rc = -EINVAL; 1395 1384 goto out; 1396 1385 } 1386 + virt_len = crypt_stat->num_header_bytes_at_front; 1387 + order = get_order(virt_len); 1397 1388 /* Released in this function */ 1398 - virt = (char *)get_zeroed_page(GFP_KERNEL); 1389 + virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order); 1399 1390 if (!virt) { 1400 1391 printk(KERN_ERR "%s: Out of memory\n", __func__); 1401 1392 rc = -ENOMEM; 1402 1393 goto out; 1403 1394 } 1404 - rc = ecryptfs_write_headers_virt(virt, PAGE_CACHE_SIZE, &size, 1405 - crypt_stat, ecryptfs_dentry); 1395 + rc = ecryptfs_write_headers_virt(virt, virt_len, &size, crypt_stat, 1396 + ecryptfs_dentry); 1406 1397 if (unlikely(rc)) { 1407 1398 printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n", 1408 1399 __func__, rc); 1409 1400 goto out_free; 1410 1401 } 1411 1402 if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) 1412 - rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, 1413 - crypt_stat, virt, size); 1403 + rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, virt, 1404 + size); 1414 1405 else 1415 - rc = ecryptfs_write_metadata_to_contents(crypt_stat, 1416 - ecryptfs_dentry, virt); 1406 + rc = ecryptfs_write_metadata_to_contents(ecryptfs_dentry, virt, 1407 + virt_len); 1417 1408 if (rc) { 1418 1409 printk(KERN_ERR "%s: Error writing metadata out to lower file; " 1419 1410 "rc = [%d]\n", __func__, rc); 1420 1411 goto out_free; 1421 1412 } 1422 1413 out_free: 1423 - free_page((unsigned long)virt); 1414 + free_pages((unsigned long)virt, order); 1424 1415 out: 1425 1416 return rc; 1426 1417 }