diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 146 |
1 files changed, 68 insertions, 78 deletions
diff --git a/fs/namei.c b/fs/namei.c index 4ea63ed5e791..09ce58e49e72 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -212,8 +212,7 @@ int generic_permission(struct inode *inode, int mask, | |||
212 | * Read/write DACs are always overridable. | 212 | * Read/write DACs are always overridable. |
213 | * Executable DACs are overridable if at least one exec bit is set. | 213 | * Executable DACs are overridable if at least one exec bit is set. |
214 | */ | 214 | */ |
215 | if (!(mask & MAY_EXEC) || | 215 | if (!(mask & MAY_EXEC) || execute_ok(inode)) |
216 | (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)) | ||
217 | if (capable(CAP_DAC_OVERRIDE)) | 216 | if (capable(CAP_DAC_OVERRIDE)) |
218 | return 0; | 217 | return 0; |
219 | 218 | ||
@@ -249,23 +248,11 @@ int inode_permission(struct inode *inode, int mask) | |||
249 | } | 248 | } |
250 | 249 | ||
251 | /* Ordinary permission routines do not understand MAY_APPEND. */ | 250 | /* Ordinary permission routines do not understand MAY_APPEND. */ |
252 | if (inode->i_op && inode->i_op->permission) { | 251 | if (inode->i_op && inode->i_op->permission) |
253 | retval = inode->i_op->permission(inode, mask); | 252 | retval = inode->i_op->permission(inode, mask); |
254 | if (!retval) { | 253 | else |
255 | /* | ||
256 | * Exec permission on a regular file is denied if none | ||
257 | * of the execute bits are set. | ||
258 | * | ||
259 | * This check should be done by the ->permission() | ||
260 | * method. | ||
261 | */ | ||
262 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) && | ||
263 | !(inode->i_mode & S_IXUGO)) | ||
264 | return -EACCES; | ||
265 | } | ||
266 | } else { | ||
267 | retval = generic_permission(inode, mask, NULL); | 254 | retval = generic_permission(inode, mask, NULL); |
268 | } | 255 | |
269 | if (retval) | 256 | if (retval) |
270 | return retval; | 257 | return retval; |
271 | 258 | ||
@@ -1106,6 +1093,15 @@ int path_lookup(const char *name, unsigned int flags, | |||
1106 | return do_path_lookup(AT_FDCWD, name, flags, nd); | 1093 | return do_path_lookup(AT_FDCWD, name, flags, nd); |
1107 | } | 1094 | } |
1108 | 1095 | ||
1096 | int kern_path(const char *name, unsigned int flags, struct path *path) | ||
1097 | { | ||
1098 | struct nameidata nd; | ||
1099 | int res = do_path_lookup(AT_FDCWD, name, flags, &nd); | ||
1100 | if (!res) | ||
1101 | *path = nd.path; | ||
1102 | return res; | ||
1103 | } | ||
1104 | |||
1109 | /** | 1105 | /** |
1110 | * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair | 1106 | * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair |
1111 | * @dentry: pointer to dentry of the base directory | 1107 | * @dentry: pointer to dentry of the base directory |
@@ -1138,9 +1134,16 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
1138 | 1134 | ||
1139 | } | 1135 | } |
1140 | 1136 | ||
1141 | static int __path_lookup_intent_open(int dfd, const char *name, | 1137 | /** |
1142 | unsigned int lookup_flags, struct nameidata *nd, | 1138 | * path_lookup_open - lookup a file path with open intent |
1143 | int open_flags, int create_mode) | 1139 | * @dfd: the directory to use as base, or AT_FDCWD |
1140 | * @name: pointer to file name | ||
1141 | * @lookup_flags: lookup intent flags | ||
1142 | * @nd: pointer to nameidata | ||
1143 | * @open_flags: open intent flags | ||
1144 | */ | ||
1145 | int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags, | ||
1146 | struct nameidata *nd, int open_flags) | ||
1144 | { | 1147 | { |
1145 | struct file *filp = get_empty_filp(); | 1148 | struct file *filp = get_empty_filp(); |
1146 | int err; | 1149 | int err; |
@@ -1149,7 +1152,7 @@ static int __path_lookup_intent_open(int dfd, const char *name, | |||
1149 | return -ENFILE; | 1152 | return -ENFILE; |
1150 | nd->intent.open.file = filp; | 1153 | nd->intent.open.file = filp; |
1151 | nd->intent.open.flags = open_flags; | 1154 | nd->intent.open.flags = open_flags; |
1152 | nd->intent.open.create_mode = create_mode; | 1155 | nd->intent.open.create_mode = 0; |
1153 | err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd); | 1156 | err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd); |
1154 | if (IS_ERR(nd->intent.open.file)) { | 1157 | if (IS_ERR(nd->intent.open.file)) { |
1155 | if (err == 0) { | 1158 | if (err == 0) { |
@@ -1161,38 +1164,6 @@ static int __path_lookup_intent_open(int dfd, const char *name, | |||
1161 | return err; | 1164 | return err; |
1162 | } | 1165 | } |
1163 | 1166 | ||
1164 | /** | ||
1165 | * path_lookup_open - lookup a file path with open intent | ||
1166 | * @dfd: the directory to use as base, or AT_FDCWD | ||
1167 | * @name: pointer to file name | ||
1168 | * @lookup_flags: lookup intent flags | ||
1169 | * @nd: pointer to nameidata | ||
1170 | * @open_flags: open intent flags | ||
1171 | */ | ||
1172 | int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags, | ||
1173 | struct nameidata *nd, int open_flags) | ||
1174 | { | ||
1175 | return __path_lookup_intent_open(dfd, name, lookup_flags, nd, | ||
1176 | open_flags, 0); | ||
1177 | } | ||
1178 | |||
1179 | /** | ||
1180 | * path_lookup_create - lookup a file path with open + create intent | ||
1181 | * @dfd: the directory to use as base, or AT_FDCWD | ||
1182 | * @name: pointer to file name | ||
1183 | * @lookup_flags: lookup intent flags | ||
1184 | * @nd: pointer to nameidata | ||
1185 | * @open_flags: open intent flags | ||
1186 | * @create_mode: create intent flags | ||
1187 | */ | ||
1188 | static int path_lookup_create(int dfd, const char *name, | ||
1189 | unsigned int lookup_flags, struct nameidata *nd, | ||
1190 | int open_flags, int create_mode) | ||
1191 | { | ||
1192 | return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE, | ||
1193 | nd, open_flags, create_mode); | ||
1194 | } | ||
1195 | |||
1196 | static struct dentry *__lookup_hash(struct qstr *name, | 1167 | static struct dentry *__lookup_hash(struct qstr *name, |
1197 | struct dentry *base, struct nameidata *nd) | 1168 | struct dentry *base, struct nameidata *nd) |
1198 | { | 1169 | { |
@@ -1470,20 +1441,18 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) | |||
1470 | 1441 | ||
1471 | mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex); | 1442 | mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex); |
1472 | 1443 | ||
1473 | for (p = p1; p->d_parent != p; p = p->d_parent) { | 1444 | p = d_ancestor(p2, p1); |
1474 | if (p->d_parent == p2) { | 1445 | if (p) { |
1475 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT); | 1446 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT); |
1476 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD); | 1447 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD); |
1477 | return p; | 1448 | return p; |
1478 | } | ||
1479 | } | 1449 | } |
1480 | 1450 | ||
1481 | for (p = p2; p->d_parent != p; p = p->d_parent) { | 1451 | p = d_ancestor(p1, p2); |
1482 | if (p->d_parent == p1) { | 1452 | if (p) { |
1483 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); | 1453 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); |
1484 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); | 1454 | mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); |
1485 | return p; | 1455 | return p; |
1486 | } | ||
1487 | } | 1456 | } |
1488 | 1457 | ||
1489 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); | 1458 | mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); |
@@ -1702,8 +1671,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1702 | /* | 1671 | /* |
1703 | * Create - we need to know the parent. | 1672 | * Create - we need to know the parent. |
1704 | */ | 1673 | */ |
1705 | error = path_lookup_create(dfd, pathname, LOOKUP_PARENT, | 1674 | error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); |
1706 | &nd, flag, mode); | ||
1707 | if (error) | 1675 | if (error) |
1708 | return ERR_PTR(error); | 1676 | return ERR_PTR(error); |
1709 | 1677 | ||
@@ -1714,10 +1682,20 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1714 | */ | 1682 | */ |
1715 | error = -EISDIR; | 1683 | error = -EISDIR; |
1716 | if (nd.last_type != LAST_NORM || nd.last.name[nd.last.len]) | 1684 | if (nd.last_type != LAST_NORM || nd.last.name[nd.last.len]) |
1717 | goto exit; | 1685 | goto exit_parent; |
1718 | 1686 | ||
1687 | error = -ENFILE; | ||
1688 | filp = get_empty_filp(); | ||
1689 | if (filp == NULL) | ||
1690 | goto exit_parent; | ||
1691 | nd.intent.open.file = filp; | ||
1692 | nd.intent.open.flags = flag; | ||
1693 | nd.intent.open.create_mode = mode; | ||
1719 | dir = nd.path.dentry; | 1694 | dir = nd.path.dentry; |
1720 | nd.flags &= ~LOOKUP_PARENT; | 1695 | nd.flags &= ~LOOKUP_PARENT; |
1696 | nd.flags |= LOOKUP_CREATE | LOOKUP_OPEN; | ||
1697 | if (flag & O_EXCL) | ||
1698 | nd.flags |= LOOKUP_EXCL; | ||
1721 | mutex_lock(&dir->d_inode->i_mutex); | 1699 | mutex_lock(&dir->d_inode->i_mutex); |
1722 | path.dentry = lookup_hash(&nd); | 1700 | path.dentry = lookup_hash(&nd); |
1723 | path.mnt = nd.path.mnt; | 1701 | path.mnt = nd.path.mnt; |
@@ -1822,6 +1800,7 @@ exit_dput: | |||
1822 | exit: | 1800 | exit: |
1823 | if (!IS_ERR(nd.intent.open.file)) | 1801 | if (!IS_ERR(nd.intent.open.file)) |
1824 | release_open_intent(&nd); | 1802 | release_open_intent(&nd); |
1803 | exit_parent: | ||
1825 | path_put(&nd.path); | 1804 | path_put(&nd.path); |
1826 | return ERR_PTR(error); | 1805 | return ERR_PTR(error); |
1827 | 1806 | ||
@@ -1914,7 +1893,7 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir) | |||
1914 | if (nd->last_type != LAST_NORM) | 1893 | if (nd->last_type != LAST_NORM) |
1915 | goto fail; | 1894 | goto fail; |
1916 | nd->flags &= ~LOOKUP_PARENT; | 1895 | nd->flags &= ~LOOKUP_PARENT; |
1917 | nd->flags |= LOOKUP_CREATE; | 1896 | nd->flags |= LOOKUP_CREATE | LOOKUP_EXCL; |
1918 | nd->intent.open.flags = O_EXCL; | 1897 | nd->intent.open.flags = O_EXCL; |
1919 | 1898 | ||
1920 | /* | 1899 | /* |
@@ -2178,16 +2157,19 @@ static long do_rmdir(int dfd, const char __user *pathname) | |||
2178 | return error; | 2157 | return error; |
2179 | 2158 | ||
2180 | switch(nd.last_type) { | 2159 | switch(nd.last_type) { |
2181 | case LAST_DOTDOT: | 2160 | case LAST_DOTDOT: |
2182 | error = -ENOTEMPTY; | 2161 | error = -ENOTEMPTY; |
2183 | goto exit1; | 2162 | goto exit1; |
2184 | case LAST_DOT: | 2163 | case LAST_DOT: |
2185 | error = -EINVAL; | 2164 | error = -EINVAL; |
2186 | goto exit1; | 2165 | goto exit1; |
2187 | case LAST_ROOT: | 2166 | case LAST_ROOT: |
2188 | error = -EBUSY; | 2167 | error = -EBUSY; |
2189 | goto exit1; | 2168 | goto exit1; |
2190 | } | 2169 | } |
2170 | |||
2171 | nd.flags &= ~LOOKUP_PARENT; | ||
2172 | |||
2191 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 2173 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); |
2192 | dentry = lookup_hash(&nd); | 2174 | dentry = lookup_hash(&nd); |
2193 | error = PTR_ERR(dentry); | 2175 | error = PTR_ERR(dentry); |
@@ -2265,6 +2247,9 @@ static long do_unlinkat(int dfd, const char __user *pathname) | |||
2265 | error = -EISDIR; | 2247 | error = -EISDIR; |
2266 | if (nd.last_type != LAST_NORM) | 2248 | if (nd.last_type != LAST_NORM) |
2267 | goto exit1; | 2249 | goto exit1; |
2250 | |||
2251 | nd.flags &= ~LOOKUP_PARENT; | ||
2252 | |||
2268 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 2253 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); |
2269 | dentry = lookup_hash(&nd); | 2254 | dentry = lookup_hash(&nd); |
2270 | error = PTR_ERR(dentry); | 2255 | error = PTR_ERR(dentry); |
@@ -2654,6 +2639,10 @@ asmlinkage long sys_renameat(int olddfd, const char __user *oldname, | |||
2654 | if (newnd.last_type != LAST_NORM) | 2639 | if (newnd.last_type != LAST_NORM) |
2655 | goto exit2; | 2640 | goto exit2; |
2656 | 2641 | ||
2642 | oldnd.flags &= ~LOOKUP_PARENT; | ||
2643 | newnd.flags &= ~LOOKUP_PARENT; | ||
2644 | newnd.flags |= LOOKUP_RENAME_TARGET; | ||
2645 | |||
2657 | trap = lock_rename(new_dir, old_dir); | 2646 | trap = lock_rename(new_dir, old_dir); |
2658 | 2647 | ||
2659 | old_dentry = lookup_hash(&oldnd); | 2648 | old_dentry = lookup_hash(&oldnd); |
@@ -2855,6 +2844,7 @@ EXPORT_SYMBOL(__page_symlink); | |||
2855 | EXPORT_SYMBOL(page_symlink); | 2844 | EXPORT_SYMBOL(page_symlink); |
2856 | EXPORT_SYMBOL(page_symlink_inode_operations); | 2845 | EXPORT_SYMBOL(page_symlink_inode_operations); |
2857 | EXPORT_SYMBOL(path_lookup); | 2846 | EXPORT_SYMBOL(path_lookup); |
2847 | EXPORT_SYMBOL(kern_path); | ||
2858 | EXPORT_SYMBOL(vfs_path_lookup); | 2848 | EXPORT_SYMBOL(vfs_path_lookup); |
2859 | EXPORT_SYMBOL(inode_permission); | 2849 | EXPORT_SYMBOL(inode_permission); |
2860 | EXPORT_SYMBOL(vfs_permission); | 2850 | EXPORT_SYMBOL(vfs_permission); |