diff options
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 | /* |