diff options
| author | David S. Miller <davem@davemloft.net> | 2009-09-11 23:35:13 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-09-11 23:35:13 -0400 |
| commit | cabc5c0f7fa1342049042d6e147db5a73773955b (patch) | |
| tree | 2be09ae1777d580c7dfe05d6d5b76e57281ec447 /fs/namei.c | |
| parent | b73d884756303316ead4cd7dad51236b2a515a1a (diff) | |
| parent | 86d710146fb9975f04c505ec78caa43d227c1018 (diff) | |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Conflicts:
arch/sparc/Kconfig
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 110 |
1 files changed, 60 insertions, 50 deletions
diff --git a/fs/namei.c b/fs/namei.c index f3c5b278895a..d11f404667e9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -169,19 +169,10 @@ void putname(const char *name) | |||
| 169 | EXPORT_SYMBOL(putname); | 169 | EXPORT_SYMBOL(putname); |
| 170 | #endif | 170 | #endif |
| 171 | 171 | ||
| 172 | 172 | /* | |
| 173 | /** | 173 | * This does basic POSIX ACL permission checking |
| 174 | * generic_permission - check for access rights on a Posix-like filesystem | ||
| 175 | * @inode: inode to check access rights for | ||
| 176 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | ||
| 177 | * @check_acl: optional callback to check for Posix ACLs | ||
| 178 | * | ||
| 179 | * Used to check for read/write/execute permissions on a file. | ||
| 180 | * We use "fsuid" for this, letting us set arbitrary permissions | ||
| 181 | * for filesystem access without changing the "normal" uids which | ||
| 182 | * are used for other things.. | ||
| 183 | */ | 174 | */ |
| 184 | int generic_permission(struct inode *inode, int mask, | 175 | static int acl_permission_check(struct inode *inode, int mask, |
| 185 | int (*check_acl)(struct inode *inode, int mask)) | 176 | int (*check_acl)(struct inode *inode, int mask)) |
| 186 | { | 177 | { |
| 187 | umode_t mode = inode->i_mode; | 178 | umode_t mode = inode->i_mode; |
| @@ -193,9 +184,7 @@ int generic_permission(struct inode *inode, int mask, | |||
| 193 | else { | 184 | else { |
| 194 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { | 185 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { |
| 195 | int error = check_acl(inode, mask); | 186 | int error = check_acl(inode, mask); |
| 196 | if (error == -EACCES) | 187 | if (error != -EAGAIN) |
| 197 | goto check_capabilities; | ||
| 198 | else if (error != -EAGAIN) | ||
| 199 | return error; | 188 | return error; |
| 200 | } | 189 | } |
| 201 | 190 | ||
| @@ -208,8 +197,32 @@ int generic_permission(struct inode *inode, int mask, | |||
| 208 | */ | 197 | */ |
| 209 | if ((mask & ~mode) == 0) | 198 | if ((mask & ~mode) == 0) |
| 210 | return 0; | 199 | return 0; |
| 200 | return -EACCES; | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * generic_permission - check for access rights on a Posix-like filesystem | ||
| 205 | * @inode: inode to check access rights for | ||
| 206 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | ||
| 207 | * @check_acl: optional callback to check for Posix ACLs | ||
| 208 | * | ||
| 209 | * Used to check for read/write/execute permissions on a file. | ||
| 210 | * We use "fsuid" for this, letting us set arbitrary permissions | ||
| 211 | * for filesystem access without changing the "normal" uids which | ||
| 212 | * are used for other things.. | ||
| 213 | */ | ||
| 214 | int generic_permission(struct inode *inode, int mask, | ||
| 215 | int (*check_acl)(struct inode *inode, int mask)) | ||
| 216 | { | ||
| 217 | int ret; | ||
| 218 | |||
| 219 | /* | ||
| 220 | * Do the basic POSIX ACL permission checks. | ||
| 221 | */ | ||
| 222 | ret = acl_permission_check(inode, mask, check_acl); | ||
| 223 | if (ret != -EACCES) | ||
| 224 | return ret; | ||
| 211 | 225 | ||
| 212 | check_capabilities: | ||
| 213 | /* | 226 | /* |
| 214 | * Read/write DACs are always overridable. | 227 | * Read/write DACs are always overridable. |
| 215 | * Executable DACs are overridable if at least one exec bit is set. | 228 | * Executable DACs are overridable if at least one exec bit is set. |
| @@ -262,7 +275,7 @@ int inode_permission(struct inode *inode, int mask) | |||
| 262 | if (inode->i_op->permission) | 275 | if (inode->i_op->permission) |
| 263 | retval = inode->i_op->permission(inode, mask); | 276 | retval = inode->i_op->permission(inode, mask); |
| 264 | else | 277 | else |
| 265 | retval = generic_permission(inode, mask, NULL); | 278 | retval = generic_permission(inode, mask, inode->i_op->check_acl); |
| 266 | 279 | ||
| 267 | if (retval) | 280 | if (retval) |
| 268 | return retval; | 281 | return retval; |
| @@ -432,29 +445,22 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, | |||
| 432 | */ | 445 | */ |
| 433 | static int exec_permission_lite(struct inode *inode) | 446 | static int exec_permission_lite(struct inode *inode) |
| 434 | { | 447 | { |
| 435 | umode_t mode = inode->i_mode; | 448 | int ret; |
| 436 | 449 | ||
| 437 | if (inode->i_op->permission) | 450 | if (inode->i_op->permission) { |
| 438 | return -EAGAIN; | 451 | ret = inode->i_op->permission(inode, MAY_EXEC); |
| 439 | 452 | if (!ret) | |
| 440 | if (current_fsuid() == inode->i_uid) | 453 | goto ok; |
| 441 | mode >>= 6; | 454 | return ret; |
| 442 | else if (in_group_p(inode->i_gid)) | 455 | } |
| 443 | mode >>= 3; | 456 | ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl); |
| 444 | 457 | if (!ret) | |
| 445 | if (mode & MAY_EXEC) | ||
| 446 | goto ok; | ||
| 447 | |||
| 448 | if ((inode->i_mode & S_IXUGO) && capable(CAP_DAC_OVERRIDE)) | ||
| 449 | goto ok; | ||
| 450 | |||
| 451 | if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_OVERRIDE)) | ||
| 452 | goto ok; | 458 | goto ok; |
| 453 | 459 | ||
| 454 | if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_READ_SEARCH)) | 460 | if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) |
| 455 | goto ok; | 461 | goto ok; |
| 456 | 462 | ||
| 457 | return -EACCES; | 463 | return ret; |
| 458 | ok: | 464 | ok: |
| 459 | return security_inode_permission(inode, MAY_EXEC); | 465 | return security_inode_permission(inode, MAY_EXEC); |
| 460 | } | 466 | } |
| @@ -853,12 +859,6 @@ static int __link_path_walk(const char *name, struct nameidata *nd) | |||
| 853 | 859 | ||
| 854 | nd->flags |= LOOKUP_CONTINUE; | 860 | nd->flags |= LOOKUP_CONTINUE; |
| 855 | err = exec_permission_lite(inode); | 861 | err = exec_permission_lite(inode); |
| 856 | if (err == -EAGAIN) | ||
| 857 | err = inode_permission(nd->path.dentry->d_inode, | ||
| 858 | MAY_EXEC); | ||
| 859 | if (!err) | ||
| 860 | err = ima_path_check(&nd->path, MAY_EXEC, | ||
| 861 | IMA_COUNT_UPDATE); | ||
| 862 | if (err) | 862 | if (err) |
| 863 | break; | 863 | break; |
| 864 | 864 | ||
| @@ -1533,37 +1533,42 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
| 1533 | if (error) | 1533 | if (error) |
| 1534 | return error; | 1534 | return error; |
| 1535 | 1535 | ||
| 1536 | error = ima_path_check(path, | 1536 | error = ima_path_check(path, acc_mode ? |
| 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC), | 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : |
| 1538 | ACC_MODE(flag) & (MAY_READ | MAY_WRITE), | ||
| 1538 | IMA_COUNT_UPDATE); | 1539 | IMA_COUNT_UPDATE); |
| 1540 | |||
| 1539 | if (error) | 1541 | if (error) |
| 1540 | return error; | 1542 | return error; |
| 1541 | /* | 1543 | /* |
| 1542 | * An append-only file must be opened in append mode for writing. | 1544 | * An append-only file must be opened in append mode for writing. |
| 1543 | */ | 1545 | */ |
| 1544 | if (IS_APPEND(inode)) { | 1546 | if (IS_APPEND(inode)) { |
| 1547 | error = -EPERM; | ||
| 1545 | if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) | 1548 | if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) |
| 1546 | return -EPERM; | 1549 | goto err_out; |
| 1547 | if (flag & O_TRUNC) | 1550 | if (flag & O_TRUNC) |
| 1548 | return -EPERM; | 1551 | goto err_out; |
| 1549 | } | 1552 | } |
| 1550 | 1553 | ||
| 1551 | /* O_NOATIME can only be set by the owner or superuser */ | 1554 | /* O_NOATIME can only be set by the owner or superuser */ |
| 1552 | if (flag & O_NOATIME) | 1555 | if (flag & O_NOATIME) |
| 1553 | if (!is_owner_or_cap(inode)) | 1556 | if (!is_owner_or_cap(inode)) { |
| 1554 | return -EPERM; | 1557 | error = -EPERM; |
| 1558 | goto err_out; | ||
| 1559 | } | ||
| 1555 | 1560 | ||
| 1556 | /* | 1561 | /* |
| 1557 | * Ensure there are no outstanding leases on the file. | 1562 | * Ensure there are no outstanding leases on the file. |
| 1558 | */ | 1563 | */ |
| 1559 | error = break_lease(inode, flag); | 1564 | error = break_lease(inode, flag); |
| 1560 | if (error) | 1565 | if (error) |
| 1561 | return error; | 1566 | goto err_out; |
| 1562 | 1567 | ||
| 1563 | if (flag & O_TRUNC) { | 1568 | if (flag & O_TRUNC) { |
| 1564 | error = get_write_access(inode); | 1569 | error = get_write_access(inode); |
| 1565 | if (error) | 1570 | if (error) |
| 1566 | return error; | 1571 | goto err_out; |
| 1567 | 1572 | ||
| 1568 | /* | 1573 | /* |
| 1569 | * Refuse to truncate files with mandatory locks held on them. | 1574 | * Refuse to truncate files with mandatory locks held on them. |
| @@ -1581,12 +1586,17 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
| 1581 | } | 1586 | } |
| 1582 | put_write_access(inode); | 1587 | put_write_access(inode); |
| 1583 | if (error) | 1588 | if (error) |
| 1584 | return error; | 1589 | goto err_out; |
| 1585 | } else | 1590 | } else |
| 1586 | if (flag & FMODE_WRITE) | 1591 | if (flag & FMODE_WRITE) |
| 1587 | vfs_dq_init(inode); | 1592 | vfs_dq_init(inode); |
| 1588 | 1593 | ||
| 1589 | return 0; | 1594 | return 0; |
| 1595 | err_out: | ||
| 1596 | ima_counts_put(path, acc_mode ? | ||
| 1597 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : | ||
| 1598 | ACC_MODE(flag) & (MAY_READ | MAY_WRITE)); | ||
| 1599 | return error; | ||
| 1590 | } | 1600 | } |
| 1591 | 1601 | ||
| 1592 | /* | 1602 | /* |
