X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fnamei.c;h=5e2d98d10c5d79220a7daa95be76a8ac0616df93;hb=ecd27b92fbb41f779d857632a69bd45dbaf0f915;hp=28d49b301d5516bbdfb5bf7651f3c51b8f370f31;hpb=f0b364a13d7fba001c0571d954f165dfaf5f434a;p=linux-2.6 diff --git a/fs/namei.c b/fs/namei.c index 28d49b301d..5e2d98d10c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -249,9 +248,11 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) /* * MAY_EXEC on regular files requires special handling: We override - * filesystem execute permissions if the mode bits aren't set. + * filesystem execute permissions if the mode bits aren't set or + * the fs is mounted with the "noexec" flag. */ - if ((mask & MAY_EXEC) && S_ISREG(mode) && !(mode & S_IXUGO)) + if ((mask & MAY_EXEC) && S_ISREG(mode) && (!(mode & S_IXUGO) || + (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC)))) return -EACCES; /* Ordinary permission routines do not understand MAY_APPEND. */ @@ -295,7 +296,7 @@ int vfs_permission(struct nameidata *nd, int mask) */ int file_permission(struct file *file, int mask) { - return permission(file->f_dentry->d_inode, mask, NULL); + return permission(file->f_path.dentry->d_inode, mask, NULL); } /* @@ -331,7 +332,7 @@ int get_write_access(struct inode * inode) int deny_write_access(struct file * file) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; spin_lock(&inode->i_lock); if (atomic_read(&inode->i_writecount) > 0) { @@ -366,7 +367,7 @@ void path_release_on_umount(struct nameidata *nd) */ void release_open_intent(struct nameidata *nd) { - if (nd->intent.open.file->f_dentry == NULL) + if (nd->intent.open.file->f_path.dentry == NULL) put_filp(nd->intent.open.file); else fput(nd->intent.open.file); @@ -570,11 +571,6 @@ fail: return PTR_ERR(link); } -struct path { - struct vfsmount *mnt; - struct dentry *dentry; -}; - static inline void dput_path(struct path *path, struct nameidata *nd) { dput(path->dentry); @@ -1141,7 +1137,7 @@ static int fastcall do_path_lookup(int dfd, const char *name, if (!file) goto out_fail; - dentry = file->f_dentry; + dentry = file->f_path.dentry; retval = -ENOTDIR; if (!S_ISDIR(dentry->d_inode->i_mode)) @@ -1151,19 +1147,17 @@ static int fastcall do_path_lookup(int dfd, const char *name, if (retval) goto fput_fail; - nd->mnt = mntget(file->f_vfsmnt); + nd->mnt = mntget(file->f_path.mnt); nd->dentry = dget(dentry); fput_light(file, fput_needed); } - current->total_link_count = 0; - retval = link_path_walk(name, nd); + + retval = path_walk(name, nd); out: - if (likely(retval == 0)) { - if (unlikely(!audit_dummy_context() && nd && nd->dentry && + if (unlikely(!retval && !audit_dummy_context() && nd->dentry && nd->dentry->d_inode)) audit_inode(name, nd->dentry->d_inode); - } out_fail: return retval; @@ -1246,22 +1240,13 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, return err; } -/* - * Restricted form of lookup. Doesn't follow links, single-component only, - * needs parent already locked. Doesn't follow mounts. - * SMP-safe. - */ -static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd) +static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd) { - struct dentry * dentry; + struct dentry *dentry; struct inode *inode; int err; inode = base->d_inode; - err = permission(inode, MAY_EXEC, nd); - dentry = ERR_PTR(err); - if (err) - goto out; /* * See if the low-level filesystem might want @@ -1290,48 +1275,78 @@ out: return dentry; } +/* + * Restricted form of lookup. Doesn't follow links, single-component only, + * needs parent already locked. Doesn't follow mounts. + * SMP-safe. + */ +static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) +{ + struct dentry *dentry; + struct inode *inode; + int err; + + inode = base->d_inode; + + err = permission(inode, MAY_EXEC, nd); + dentry = ERR_PTR(err); + if (err) + goto out; + + dentry = __lookup_hash_kern(name, base, nd); +out: + return dentry; +} + static struct dentry *lookup_hash(struct nameidata *nd) { return __lookup_hash(&nd->last, nd->dentry, nd); } /* SMP-safe */ -struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) +static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len) { unsigned long hash; - struct qstr this; unsigned int c; - this.name = name; - this.len = len; + this->name = name; + this->len = len; if (!len) - goto access; + return -EACCES; hash = init_name_hash(); while (len--) { c = *(const unsigned char *)name++; if (c == '/' || c == '\0') - goto access; + return -EACCES; hash = partial_name_hash(c, hash); } - this.hash = end_name_hash(hash); + this->hash = end_name_hash(hash); + return 0; +} + +struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) +{ + int err; + struct qstr this; + err = __lookup_one_len(name, &this, base, len); + if (err) + return ERR_PTR(err); return __lookup_hash(&this, base, NULL); -access: - return ERR_PTR(-EACCES); } -/* - * namei() - * - * is used by most simple commands to get the inode of a specified name. - * Open, link etc use their own routines, but this is enough for things - * like 'chmod' etc. - * - * namei exists in two versions: namei/lnamei. The only difference is - * that namei follows links, while lnamei does not. - * SMP-safe - */ +struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len) +{ + int err; + struct qstr this; + + err = __lookup_one_len(name, &this, base, len); + if (err) + return ERR_PTR(err); + return __lookup_hash_kern(&this, base, NULL); +} + int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, struct nameidata *nd) { @@ -1704,7 +1719,7 @@ do_last: * It already exists. */ mutex_unlock(&dir->d_inode->i_mutex); - audit_inode_update(path.dentry->d_inode); + audit_inode(pathname, path.dentry->d_inode); error = -EEXIST; if (flag & O_EXCL) @@ -1996,8 +2011,7 @@ asmlinkage long sys_mkdir(const char __user *pathname, int mode) void dentry_unhash(struct dentry *dentry) { dget(dentry); - if (atomic_read(&dentry->d_count)) - shrink_dcache_parent(dentry); + shrink_dcache_parent(dentry); spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (atomic_read(&dentry->d_count) == 2) @@ -2643,19 +2657,9 @@ static char *page_getlink(struct dentry * dentry, struct page **ppage) struct address_space *mapping = dentry->d_inode->i_mapping; page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) - goto sync_fail; - wait_on_page_locked(page); - if (!PageUptodate(page)) - goto async_fail; + return (char*)page; *ppage = page; return kmap(page); - -async_fail: - page_cache_release(page); - return ERR_PTR(-EIO); - -sync_fail: - return (char*)page; } int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) @@ -2692,10 +2696,11 @@ int __page_symlink(struct inode *inode, const char *symname, int len, { struct address_space *mapping = inode->i_mapping; struct page *page; - int err = -ENOMEM; + int err; char *kaddr; retry: + err = -ENOMEM; page = find_or_create_page(mapping, 0, gfp_mask); if (!page) goto fail; @@ -2748,7 +2753,7 @@ int page_symlink(struct inode *inode, const char *symname, int len) mapping_gfp_mask(inode->i_mapping)); } -struct inode_operations page_symlink_inode_operations = { +const struct inode_operations page_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link,