diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 82 |
1 files changed, 41 insertions, 41 deletions
diff --git a/fs/namei.c b/fs/namei.c index 1f13751693a5..ed27bb205b7e 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 | |||
437 | if (inode->i_op->permission) | ||
438 | return -EAGAIN; | ||
439 | |||
440 | if (current_fsuid() == inode->i_uid) | ||
441 | mode >>= 6; | ||
442 | else if (in_group_p(inode->i_gid)) | ||
443 | mode >>= 3; | ||
444 | |||
445 | if (mode & MAY_EXEC) | ||
446 | goto ok; | ||
447 | 449 | ||
448 | if ((inode->i_mode & S_IXUGO) && capable(CAP_DAC_OVERRIDE)) | 450 | if (inode->i_op->permission) { |
449 | goto ok; | 451 | ret = inode->i_op->permission(inode, MAY_EXEC); |
450 | 452 | if (!ret) | |
451 | if (S_ISDIR(inode->i_mode) && capable(CAP_DAC_OVERRIDE)) | 453 | goto ok; |
454 | return ret; | ||
455 | } | ||
456 | ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl); | ||
457 | if (!ret) | ||
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 | ||