Commit acd0c935178649f72c44ec49ca83bee35ce1f79e
Committed by
James Morris
1 parent
e07cccf404
Exists in
master
and in
20 other branches
IMA: update ima_counts_put
- As ima_counts_put() may be called after the inode has been freed, verify that the inode is not NULL, before dereferencing it. - Maintain the IMA file counters in may_open() properly, decrementing any counter increments on subsequent errors. Reported-by: Ciprian Docan <docan@eden.rutgers.edu> Reported-by: J.R. Okajima <hooanon05@yahoo.co.jp> Signed-off-by: Mimi Zohar <zohar@us.ibm.com> Acked-by: Eric Paris <eparis@redhat.com Signed-off-by: James Morris <jmorris@namei.org>
Showing 2 changed files with 20 additions and 8 deletions Side-by-side Diff
fs/namei.c
... | ... | @@ -1542,28 +1542,31 @@ |
1542 | 1542 | * An append-only file must be opened in append mode for writing. |
1543 | 1543 | */ |
1544 | 1544 | if (IS_APPEND(inode)) { |
1545 | + error = -EPERM; | |
1545 | 1546 | if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) |
1546 | - return -EPERM; | |
1547 | + goto err_out; | |
1547 | 1548 | if (flag & O_TRUNC) |
1548 | - return -EPERM; | |
1549 | + goto err_out; | |
1549 | 1550 | } |
1550 | 1551 | |
1551 | 1552 | /* O_NOATIME can only be set by the owner or superuser */ |
1552 | 1553 | if (flag & O_NOATIME) |
1553 | - if (!is_owner_or_cap(inode)) | |
1554 | - return -EPERM; | |
1554 | + if (!is_owner_or_cap(inode)) { | |
1555 | + error = -EPERM; | |
1556 | + goto err_out; | |
1557 | + } | |
1555 | 1558 | |
1556 | 1559 | /* |
1557 | 1560 | * Ensure there are no outstanding leases on the file. |
1558 | 1561 | */ |
1559 | 1562 | error = break_lease(inode, flag); |
1560 | 1563 | if (error) |
1561 | - return error; | |
1564 | + goto err_out; | |
1562 | 1565 | |
1563 | 1566 | if (flag & O_TRUNC) { |
1564 | 1567 | error = get_write_access(inode); |
1565 | 1568 | if (error) |
1566 | - return error; | |
1569 | + goto err_out; | |
1567 | 1570 | |
1568 | 1571 | /* |
1569 | 1572 | * Refuse to truncate files with mandatory locks held on them. |
1570 | 1573 | |
... | ... | @@ -1581,12 +1584,17 @@ |
1581 | 1584 | } |
1582 | 1585 | put_write_access(inode); |
1583 | 1586 | if (error) |
1584 | - return error; | |
1587 | + goto err_out; | |
1585 | 1588 | } else |
1586 | 1589 | if (flag & FMODE_WRITE) |
1587 | 1590 | vfs_dq_init(inode); |
1588 | 1591 | |
1589 | 1592 | return 0; |
1593 | +err_out: | |
1594 | + ima_counts_put(path, acc_mode ? | |
1595 | + acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : | |
1596 | + ACC_MODE(flag) & (MAY_READ | MAY_WRITE)); | |
1597 | + return error; | |
1590 | 1598 | } |
1591 | 1599 | |
1592 | 1600 | /* |
security/integrity/ima/ima_main.c
... | ... | @@ -249,7 +249,11 @@ |
249 | 249 | struct inode *inode = path->dentry->d_inode; |
250 | 250 | struct ima_iint_cache *iint; |
251 | 251 | |
252 | - if (!ima_initialized || !S_ISREG(inode->i_mode)) | |
252 | + /* The inode may already have been freed, freeing the iint | |
253 | + * with it. Verify the inode is not NULL before dereferencing | |
254 | + * it. | |
255 | + */ | |
256 | + if (!ima_initialized || !inode || !S_ISREG(inode->i_mode)) | |
253 | 257 | return; |
254 | 258 | iint = ima_iint_find_insert_get(inode); |
255 | 259 | if (!iint) |