diff options
Diffstat (limited to 'fs/ncpfs')
| -rw-r--r-- | fs/ncpfs/dir.c | 45 | ||||
| -rw-r--r-- | fs/ncpfs/inode.c | 16 | ||||
| -rw-r--r-- | fs/ncpfs/mmap.c | 2 |
3 files changed, 38 insertions, 25 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 0e7f00298213..3be047474bfc 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
| @@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations = | |||
| 73 | * Dentry operations routines | 73 | * Dentry operations routines |
| 74 | */ | 74 | */ |
| 75 | static int ncp_lookup_validate(struct dentry *, unsigned int); | 75 | static int ncp_lookup_validate(struct dentry *, unsigned int); |
| 76 | static int ncp_hash_dentry(const struct dentry *, const struct inode *, | 76 | static int ncp_hash_dentry(const struct dentry *, struct qstr *); |
| 77 | struct qstr *); | 77 | static int ncp_compare_dentry(const struct dentry *, const struct dentry *, |
| 78 | static int ncp_compare_dentry(const struct dentry *, const struct inode *, | ||
| 79 | const struct dentry *, const struct inode *, | ||
| 80 | unsigned int, const char *, const struct qstr *); | 78 | unsigned int, const char *, const struct qstr *); |
| 81 | static int ncp_delete_dentry(const struct dentry *); | 79 | static int ncp_delete_dentry(const struct dentry *); |
| 82 | 80 | ||
| @@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i) | |||
| 119 | /* | 117 | /* |
| 120 | * Note: leave the hash unchanged if the directory | 118 | * Note: leave the hash unchanged if the directory |
| 121 | * is case-sensitive. | 119 | * is case-sensitive. |
| 120 | * | ||
| 121 | * Accessing the parent inode can be racy under RCU pathwalking. | ||
| 122 | * Use ACCESS_ONCE() to make sure we use _one_ particular inode, | ||
| 123 | * the callers will handle races. | ||
| 122 | */ | 124 | */ |
| 123 | static int | 125 | static int |
| 124 | ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, | 126 | ncp_hash_dentry(const struct dentry *dentry, struct qstr *this) |
| 125 | struct qstr *this) | ||
| 126 | { | 127 | { |
| 128 | struct inode *inode = ACCESS_ONCE(dentry->d_inode); | ||
| 129 | |||
| 130 | if (!inode) | ||
| 131 | return 0; | ||
| 132 | |||
| 127 | if (!ncp_case_sensitive(inode)) { | 133 | if (!ncp_case_sensitive(inode)) { |
| 128 | struct super_block *sb = dentry->d_sb; | 134 | struct super_block *sb = dentry->d_sb; |
| 129 | struct nls_table *t; | 135 | struct nls_table *t; |
| @@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, | |||
| 140 | return 0; | 146 | return 0; |
| 141 | } | 147 | } |
| 142 | 148 | ||
| 149 | /* | ||
| 150 | * Accessing the parent inode can be racy under RCU pathwalking. | ||
| 151 | * Use ACCESS_ONCE() to make sure we use _one_ particular inode, | ||
| 152 | * the callers will handle races. | ||
| 153 | */ | ||
| 143 | static int | 154 | static int |
| 144 | ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode, | 155 | ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry, |
| 145 | const struct dentry *dentry, const struct inode *inode, | ||
| 146 | unsigned int len, const char *str, const struct qstr *name) | 156 | unsigned int len, const char *str, const struct qstr *name) |
| 147 | { | 157 | { |
| 158 | struct inode *pinode; | ||
| 159 | |||
| 148 | if (len != name->len) | 160 | if (len != name->len) |
| 149 | return 1; | 161 | return 1; |
| 150 | 162 | ||
| 163 | pinode = ACCESS_ONCE(parent->d_inode); | ||
| 164 | if (!pinode) | ||
| 165 | return 1; | ||
| 166 | |||
| 151 | if (ncp_case_sensitive(pinode)) | 167 | if (ncp_case_sensitive(pinode)) |
| 152 | return strncmp(str, name->name, len); | 168 | return strncmp(str, name->name, len); |
| 153 | 169 | ||
| @@ -660,8 +676,6 @@ end_advance: | |||
| 660 | ctl.valid = 0; | 676 | ctl.valid = 0; |
| 661 | if (!ctl.filled && (ctl.fpos == ctx->pos)) { | 677 | if (!ctl.filled && (ctl.fpos == ctx->pos)) { |
| 662 | if (!ino) | 678 | if (!ino) |
| 663 | ino = find_inode_number(dentry, &qname); | ||
| 664 | if (!ino) | ||
| 665 | ino = iunique(dir->i_sb, 2); | 679 | ino = iunique(dir->i_sb, 2); |
| 666 | ctl.filled = !dir_emit(ctx, qname.name, qname.len, | 680 | ctl.filled = !dir_emit(ctx, qname.name, qname.len, |
| 667 | ino, DT_UNKNOWN); | 681 | ino, DT_UNKNOWN); |
| @@ -1123,17 +1137,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 1123 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1137 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
| 1124 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name); | 1138 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name); |
| 1125 | 1139 | ||
| 1126 | if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) { | ||
| 1127 | /* | ||
| 1128 | * fail with EBUSY if there are still references to this | ||
| 1129 | * directory. | ||
| 1130 | */ | ||
| 1131 | dentry_unhash(new_dentry); | ||
| 1132 | error = -EBUSY; | ||
| 1133 | if (!d_unhashed(new_dentry)) | ||
| 1134 | goto out; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | ncp_age_dentry(server, old_dentry); | 1140 | ncp_age_dentry(server, old_dentry); |
| 1138 | ncp_age_dentry(server, new_dentry); | 1141 | ncp_age_dentry(server, new_dentry); |
| 1139 | 1142 | ||
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 26910c8154da..4659da67e7f6 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
| @@ -403,18 +403,24 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) | |||
| 403 | switch (optval) { | 403 | switch (optval) { |
| 404 | case 'u': | 404 | case 'u': |
| 405 | data->uid = make_kuid(current_user_ns(), optint); | 405 | data->uid = make_kuid(current_user_ns(), optint); |
| 406 | if (!uid_valid(data->uid)) | 406 | if (!uid_valid(data->uid)) { |
| 407 | ret = -EINVAL; | ||
| 407 | goto err; | 408 | goto err; |
| 409 | } | ||
| 408 | break; | 410 | break; |
| 409 | case 'g': | 411 | case 'g': |
| 410 | data->gid = make_kgid(current_user_ns(), optint); | 412 | data->gid = make_kgid(current_user_ns(), optint); |
| 411 | if (!gid_valid(data->gid)) | 413 | if (!gid_valid(data->gid)) { |
| 414 | ret = -EINVAL; | ||
| 412 | goto err; | 415 | goto err; |
| 416 | } | ||
| 413 | break; | 417 | break; |
| 414 | case 'o': | 418 | case 'o': |
| 415 | data->mounted_uid = make_kuid(current_user_ns(), optint); | 419 | data->mounted_uid = make_kuid(current_user_ns(), optint); |
| 416 | if (!uid_valid(data->mounted_uid)) | 420 | if (!uid_valid(data->mounted_uid)) { |
| 421 | ret = -EINVAL; | ||
| 417 | goto err; | 422 | goto err; |
| 423 | } | ||
| 418 | break; | 424 | break; |
| 419 | case 'm': | 425 | case 'm': |
| 420 | data->file_mode = optint; | 426 | data->file_mode = optint; |
| @@ -891,6 +897,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 891 | if (!server) /* How this could happen? */ | 897 | if (!server) /* How this could happen? */ |
| 892 | goto out; | 898 | goto out; |
| 893 | 899 | ||
| 900 | result = -EPERM; | ||
| 901 | if (IS_DEADDIR(dentry->d_inode)) | ||
| 902 | goto out; | ||
| 903 | |||
| 894 | /* ageing the dentry to force validation */ | 904 | /* ageing the dentry to force validation */ |
| 895 | ncp_age_dentry(server, dentry); | 905 | ncp_age_dentry(server, dentry); |
| 896 | 906 | ||
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index ee24df5af1f9..3c5dd55d284c 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c | |||
| @@ -117,7 +117,7 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 117 | return -EINVAL; | 117 | return -EINVAL; |
| 118 | /* we do not support files bigger than 4GB... We eventually | 118 | /* we do not support files bigger than 4GB... We eventually |
| 119 | supports just 4GB... */ | 119 | supports just 4GB... */ |
| 120 | if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff | 120 | if (vma_pages(vma) + vma->vm_pgoff |
| 121 | > (1U << (32 - PAGE_SHIFT))) | 121 | > (1U << (32 - PAGE_SHIFT))) |
| 122 | return -EFBIG; | 122 | return -EFBIG; |
| 123 | 123 | ||
