aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2009-12-16 03:54:00 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2009-12-16 12:16:47 -0500
commit7715b521222b6ebb6e927fa261ed91ed687fe454 (patch)
tree33c6f8179d405974ed6763df331f731044c16072
parent85a17f552dfe77efb44b971615e4f221a5f28f37 (diff)
O_TRUNC open shouldn't fail after file truncation
* take truncate logics into a helper (handle_truncate()) * rip it out of may_open() * call it from the only caller of may_open() that might pass O_TRUNC * and do that after we'd finished with opening. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c109
1 files changed, 56 insertions, 53 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 1fc038b117be..0f0fcccab19f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1444,69 +1444,52 @@ int may_open(struct path *path, int acc_mode, int flag)
1444 if (error) 1444 if (error)
1445 return error; 1445 return error;
1446 1446
1447 error = ima_path_check(path, acc_mode ?
1448 acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) :
1449 ACC_MODE(flag) & (MAY_READ | MAY_WRITE),
1450 IMA_COUNT_UPDATE);
1451
1452 if (error)
1453 return error;
1454 /* 1447 /*
1455 * An append-only file must be opened in append mode for writing. 1448 * An append-only file must be opened in append mode for writing.
1456 */ 1449 */
1457 if (IS_APPEND(inode)) { 1450 if (IS_APPEND(inode)) {
1458 error = -EPERM;
1459 if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) 1451 if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
1460 goto err_out; 1452 return -EPERM;
1461 if (flag & O_TRUNC) 1453 if (flag & O_TRUNC)
1462 goto err_out; 1454 return -EPERM;
1463 } 1455 }
1464 1456
1465 /* O_NOATIME can only be set by the owner or superuser */ 1457 /* O_NOATIME can only be set by the owner or superuser */
1466 if (flag & O_NOATIME) 1458 if (flag & O_NOATIME && !is_owner_or_cap(inode))
1467 if (!is_owner_or_cap(inode)) { 1459 return -EPERM;
1468 error = -EPERM;
1469 goto err_out;
1470 }
1471 1460
1472 /* 1461 /*
1473 * Ensure there are no outstanding leases on the file. 1462 * Ensure there are no outstanding leases on the file.
1474 */ 1463 */
1475 error = break_lease(inode, flag); 1464 error = break_lease(inode, flag);
1476 if (error) 1465 if (error)
1477 goto err_out; 1466 return error;
1478
1479 if (flag & O_TRUNC) {
1480 error = get_write_access(inode);
1481 if (error)
1482 goto err_out;
1483
1484 /*
1485 * Refuse to truncate files with mandatory locks held on them.
1486 */
1487 error = locks_verify_locked(inode);
1488 if (!error)
1489 error = security_path_truncate(path, 0,
1490 ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
1491 if (!error) {
1492 vfs_dq_init(inode);
1493 1467
1494 error = do_truncate(dentry, 0, 1468 return ima_path_check(path, acc_mode ?
1495 ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, 1469 acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) :
1496 NULL); 1470 ACC_MODE(flag) & (MAY_READ | MAY_WRITE),
1497 } 1471 IMA_COUNT_UPDATE);
1498 put_write_access(inode); 1472}
1499 if (error)
1500 goto err_out;
1501 } else
1502 if (flag & FMODE_WRITE)
1503 vfs_dq_init(inode);
1504 1473
1505 return 0; 1474static int handle_truncate(struct path *path)
1506err_out: 1475{
1507 ima_counts_put(path, acc_mode ? 1476 struct inode *inode = path->dentry->d_inode;
1508 acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : 1477 int error = get_write_access(inode);
1509 ACC_MODE(flag) & (MAY_READ | MAY_WRITE)); 1478 if (error)
1479 return error;
1480 /*
1481 * Refuse to truncate files with mandatory locks held on them.
1482 */
1483 error = locks_verify_locked(inode);
1484 if (!error)
1485 error = security_path_truncate(path, 0,
1486 ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
1487 if (!error) {
1488 error = do_truncate(path->dentry, 0,
1489 ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
1490 NULL);
1491 }
1492 put_write_access(inode);
1510 return error; 1493 return error;
1511} 1494}
1512 1495
@@ -1561,7 +1544,7 @@ static inline int open_to_namei_flags(int flag)
1561 return flag; 1544 return flag;
1562} 1545}
1563 1546
1564static int open_will_write_to_fs(int flag, struct inode *inode) 1547static int open_will_truncate(int flag, struct inode *inode)
1565{ 1548{
1566 /* 1549 /*
1567 * We'll never write to the fs underlying 1550 * We'll never write to the fs underlying
@@ -1586,7 +1569,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
1586 struct path path, save; 1569 struct path path, save;
1587 struct dentry *dir; 1570 struct dentry *dir;
1588 int count = 0; 1571 int count = 0;
1589 int will_write; 1572 int will_truncate;
1590 int flag = open_to_namei_flags(open_flag); 1573 int flag = open_to_namei_flags(open_flag);
1591 1574
1592 /* 1575 /*
@@ -1752,28 +1735,48 @@ ok:
1752 * be avoided. Taking this mnt write here 1735 * be avoided. Taking this mnt write here
1753 * ensures that (2) can not occur. 1736 * ensures that (2) can not occur.
1754 */ 1737 */
1755 will_write = open_will_write_to_fs(flag, nd.path.dentry->d_inode); 1738 will_truncate = open_will_truncate(flag, nd.path.dentry->d_inode);
1756 if (will_write) { 1739 if (will_truncate) {
1757 error = mnt_want_write(nd.path.mnt); 1740 error = mnt_want_write(nd.path.mnt);
1758 if (error) 1741 if (error)
1759 goto exit; 1742 goto exit;
1760 } 1743 }
1761 error = may_open(&nd.path, acc_mode, flag); 1744 error = may_open(&nd.path, acc_mode, flag);
1762 if (error) { 1745 if (error) {
1763 if (will_write) 1746 if (will_truncate)
1764 mnt_drop_write(nd.path.mnt); 1747 mnt_drop_write(nd.path.mnt);
1765 goto exit; 1748 goto exit;
1766 } 1749 }
1767 filp = nameidata_to_filp(&nd, open_flag); 1750 filp = nameidata_to_filp(&nd, open_flag);
1768 if (IS_ERR(filp)) 1751 if (IS_ERR(filp)) {
1769 ima_counts_put(&nd.path, 1752 ima_counts_put(&nd.path,
1770 acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); 1753 acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC));
1754 if (will_truncate)
1755 mnt_drop_write(nd.path.mnt);
1756 if (nd.root.mnt)
1757 path_put(&nd.root);
1758 return filp;
1759 }
1760
1761 if (acc_mode & MAY_WRITE)
1762 vfs_dq_init(nd.path.dentry->d_inode);
1763
1764 if (will_truncate) {
1765 error = handle_truncate(&nd.path);
1766 if (error) {
1767 mnt_drop_write(nd.path.mnt);
1768 fput(filp);
1769 if (nd.root.mnt)
1770 path_put(&nd.root);
1771 return ERR_PTR(error);
1772 }
1773 }
1771 /* 1774 /*
1772 * It is now safe to drop the mnt write 1775 * It is now safe to drop the mnt write
1773 * because the filp has had a write taken 1776 * because the filp has had a write taken
1774 * on its behalf. 1777 * on its behalf.
1775 */ 1778 */
1776 if (will_write) 1779 if (will_truncate)
1777 mnt_drop_write(nd.path.mnt); 1780 mnt_drop_write(nd.path.mnt);
1778 if (nd.root.mnt) 1781 if (nd.root.mnt)
1779 path_put(&nd.root); 1782 path_put(&nd.root);