0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/exportfs.h>
0013 #include <linux/fs.h>
0014 #include <linux/file.h>
0015 #include <linux/module.h>
0016 #include <linux/mount.h>
0017 #include <linux/namei.h>
0018 #include <linux/sched.h>
0019 #include <linux/cred.h>
0020
0021 #define dprintk(fmt, args...) do{}while(0)
0022
0023
0024 static int get_name(const struct path *path, char *name, struct dentry *child);
0025
0026
0027 static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
0028 char *name, struct dentry *child)
0029 {
0030 const struct export_operations *nop = dir->d_sb->s_export_op;
0031 struct path path = {.mnt = mnt, .dentry = dir};
0032
0033 if (nop->get_name)
0034 return nop->get_name(dir, name, child);
0035 else
0036 return get_name(&path, name, child);
0037 }
0038
0039
0040
0041
0042 static struct dentry *
0043 find_acceptable_alias(struct dentry *result,
0044 int (*acceptable)(void *context, struct dentry *dentry),
0045 void *context)
0046 {
0047 struct dentry *dentry, *toput = NULL;
0048 struct inode *inode;
0049
0050 if (acceptable(context, result))
0051 return result;
0052
0053 inode = result->d_inode;
0054 spin_lock(&inode->i_lock);
0055 hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
0056 dget(dentry);
0057 spin_unlock(&inode->i_lock);
0058 if (toput)
0059 dput(toput);
0060 if (dentry != result && acceptable(context, dentry)) {
0061 dput(result);
0062 return dentry;
0063 }
0064 spin_lock(&inode->i_lock);
0065 toput = dentry;
0066 }
0067 spin_unlock(&inode->i_lock);
0068
0069 if (toput)
0070 dput(toput);
0071 return NULL;
0072 }
0073
0074 static bool dentry_connected(struct dentry *dentry)
0075 {
0076 dget(dentry);
0077 while (dentry->d_flags & DCACHE_DISCONNECTED) {
0078 struct dentry *parent = dget_parent(dentry);
0079
0080 dput(dentry);
0081 if (dentry == parent) {
0082 dput(parent);
0083 return false;
0084 }
0085 dentry = parent;
0086 }
0087 dput(dentry);
0088 return true;
0089 }
0090
0091 static void clear_disconnected(struct dentry *dentry)
0092 {
0093 dget(dentry);
0094 while (dentry->d_flags & DCACHE_DISCONNECTED) {
0095 struct dentry *parent = dget_parent(dentry);
0096
0097 WARN_ON_ONCE(IS_ROOT(dentry));
0098
0099 spin_lock(&dentry->d_lock);
0100 dentry->d_flags &= ~DCACHE_DISCONNECTED;
0101 spin_unlock(&dentry->d_lock);
0102
0103 dput(dentry);
0104 dentry = parent;
0105 }
0106 dput(dentry);
0107 }
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 static struct dentry *reconnect_one(struct vfsmount *mnt,
0122 struct dentry *dentry, char *nbuf)
0123 {
0124 struct dentry *parent;
0125 struct dentry *tmp;
0126 int err;
0127
0128 parent = ERR_PTR(-EACCES);
0129 inode_lock(dentry->d_inode);
0130 if (mnt->mnt_sb->s_export_op->get_parent)
0131 parent = mnt->mnt_sb->s_export_op->get_parent(dentry);
0132 inode_unlock(dentry->d_inode);
0133
0134 if (IS_ERR(parent)) {
0135 dprintk("%s: get_parent of %ld failed, err %d\n",
0136 __func__, dentry->d_inode->i_ino, PTR_ERR(parent));
0137 return parent;
0138 }
0139
0140 dprintk("%s: find name of %lu in %lu\n", __func__,
0141 dentry->d_inode->i_ino, parent->d_inode->i_ino);
0142 err = exportfs_get_name(mnt, parent, nbuf, dentry);
0143 if (err == -ENOENT)
0144 goto out_reconnected;
0145 if (err)
0146 goto out_err;
0147 dprintk("%s: found name: %s\n", __func__, nbuf);
0148 tmp = lookup_one_unlocked(mnt_user_ns(mnt), nbuf, parent, strlen(nbuf));
0149 if (IS_ERR(tmp)) {
0150 dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp));
0151 err = PTR_ERR(tmp);
0152 goto out_err;
0153 }
0154 if (tmp != dentry) {
0155
0156
0157
0158
0159
0160
0161 dput(tmp);
0162 goto out_reconnected;
0163 }
0164 dput(tmp);
0165 if (IS_ROOT(dentry)) {
0166 err = -ESTALE;
0167 goto out_err;
0168 }
0169 return parent;
0170
0171 out_err:
0172 dput(parent);
0173 return ERR_PTR(err);
0174 out_reconnected:
0175 dput(parent);
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189 if (!dentry_connected(dentry))
0190 return ERR_PTR(-ESTALE);
0191 return NULL;
0192 }
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211 static int
0212 reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
0213 {
0214 struct dentry *dentry, *parent;
0215
0216 dentry = dget(target_dir);
0217
0218 while (dentry->d_flags & DCACHE_DISCONNECTED) {
0219 BUG_ON(dentry == mnt->mnt_sb->s_root);
0220
0221 if (IS_ROOT(dentry))
0222 parent = reconnect_one(mnt, dentry, nbuf);
0223 else
0224 parent = dget_parent(dentry);
0225
0226 if (!parent)
0227 break;
0228 dput(dentry);
0229 if (IS_ERR(parent))
0230 return PTR_ERR(parent);
0231 dentry = parent;
0232 }
0233 dput(dentry);
0234 clear_disconnected(target_dir);
0235 return 0;
0236 }
0237
0238 struct getdents_callback {
0239 struct dir_context ctx;
0240 char *name;
0241
0242 u64 ino;
0243 int found;
0244 int sequence;
0245 };
0246
0247
0248
0249
0250
0251 static int filldir_one(struct dir_context *ctx, const char *name, int len,
0252 loff_t pos, u64 ino, unsigned int d_type)
0253 {
0254 struct getdents_callback *buf =
0255 container_of(ctx, struct getdents_callback, ctx);
0256 int result = 0;
0257
0258 buf->sequence++;
0259 if (buf->ino == ino && len <= NAME_MAX) {
0260 memcpy(buf->name, name, len);
0261 buf->name[len] = '\0';
0262 buf->found = 1;
0263 result = -1;
0264 }
0265 return result;
0266 }
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 static int get_name(const struct path *path, char *name, struct dentry *child)
0278 {
0279 const struct cred *cred = current_cred();
0280 struct inode *dir = path->dentry->d_inode;
0281 int error;
0282 struct file *file;
0283 struct kstat stat;
0284 struct path child_path = {
0285 .mnt = path->mnt,
0286 .dentry = child,
0287 };
0288 struct getdents_callback buffer = {
0289 .ctx.actor = filldir_one,
0290 .name = name,
0291 };
0292
0293 error = -ENOTDIR;
0294 if (!dir || !S_ISDIR(dir->i_mode))
0295 goto out;
0296 error = -EINVAL;
0297 if (!dir->i_fop)
0298 goto out;
0299
0300
0301
0302
0303
0304
0305 error = vfs_getattr_nosec(&child_path, &stat,
0306 STATX_INO, AT_STATX_SYNC_AS_STAT);
0307 if (error)
0308 return error;
0309 buffer.ino = stat.ino;
0310
0311
0312
0313 file = dentry_open(path, O_RDONLY, cred);
0314 error = PTR_ERR(file);
0315 if (IS_ERR(file))
0316 goto out;
0317
0318 error = -EINVAL;
0319 if (!file->f_op->iterate && !file->f_op->iterate_shared)
0320 goto out_close;
0321
0322 buffer.sequence = 0;
0323 while (1) {
0324 int old_seq = buffer.sequence;
0325
0326 error = iterate_dir(file, &buffer.ctx);
0327 if (buffer.found) {
0328 error = 0;
0329 break;
0330 }
0331
0332 if (error < 0)
0333 break;
0334
0335 error = -ENOENT;
0336 if (old_seq == buffer.sequence)
0337 break;
0338 }
0339
0340 out_close:
0341 fput(file);
0342 out:
0343 return error;
0344 }
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358 static int export_encode_fh(struct inode *inode, struct fid *fid,
0359 int *max_len, struct inode *parent)
0360 {
0361 int len = *max_len;
0362 int type = FILEID_INO32_GEN;
0363
0364 if (parent && (len < 4)) {
0365 *max_len = 4;
0366 return FILEID_INVALID;
0367 } else if (len < 2) {
0368 *max_len = 2;
0369 return FILEID_INVALID;
0370 }
0371
0372 len = 2;
0373 fid->i32.ino = inode->i_ino;
0374 fid->i32.gen = inode->i_generation;
0375 if (parent) {
0376 fid->i32.parent_ino = parent->i_ino;
0377 fid->i32.parent_gen = parent->i_generation;
0378 len = 4;
0379 type = FILEID_INO32_GEN_PARENT;
0380 }
0381 *max_len = len;
0382 return type;
0383 }
0384
0385 int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
0386 int *max_len, struct inode *parent)
0387 {
0388 const struct export_operations *nop = inode->i_sb->s_export_op;
0389
0390 if (nop && nop->encode_fh)
0391 return nop->encode_fh(inode, fid->raw, max_len, parent);
0392
0393 return export_encode_fh(inode, fid, max_len, parent);
0394 }
0395 EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
0396
0397 int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
0398 int connectable)
0399 {
0400 int error;
0401 struct dentry *p = NULL;
0402 struct inode *inode = dentry->d_inode, *parent = NULL;
0403
0404 if (connectable && !S_ISDIR(inode->i_mode)) {
0405 p = dget_parent(dentry);
0406
0407
0408
0409
0410 parent = p->d_inode;
0411 }
0412
0413 error = exportfs_encode_inode_fh(inode, fid, max_len, parent);
0414 dput(p);
0415
0416 return error;
0417 }
0418 EXPORT_SYMBOL_GPL(exportfs_encode_fh);
0419
0420 struct dentry *
0421 exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
0422 int fileid_type,
0423 int (*acceptable)(void *, struct dentry *),
0424 void *context)
0425 {
0426 const struct export_operations *nop = mnt->mnt_sb->s_export_op;
0427 struct dentry *result, *alias;
0428 char nbuf[NAME_MAX+1];
0429 int err;
0430
0431
0432
0433
0434 if (!nop || !nop->fh_to_dentry)
0435 return ERR_PTR(-ESTALE);
0436 result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
0437 if (IS_ERR_OR_NULL(result))
0438 return result;
0439
0440
0441
0442
0443
0444
0445
0446 if (!acceptable)
0447 return result;
0448
0449 if (d_is_dir(result)) {
0450
0451
0452
0453
0454
0455
0456
0457
0458 if (result->d_flags & DCACHE_DISCONNECTED) {
0459 err = reconnect_path(mnt, result, nbuf);
0460 if (err)
0461 goto err_result;
0462 }
0463
0464 if (!acceptable(context, result)) {
0465 err = -EACCES;
0466 goto err_result;
0467 }
0468
0469 return result;
0470 } else {
0471
0472
0473
0474 struct dentry *target_dir, *nresult;
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485 alias = find_acceptable_alias(result, acceptable, context);
0486 if (alias)
0487 return alias;
0488
0489
0490
0491
0492
0493 err = -ESTALE;
0494 if (!nop->fh_to_parent)
0495 goto err_result;
0496
0497 target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
0498 fh_len, fileid_type);
0499 if (!target_dir)
0500 goto err_result;
0501 err = PTR_ERR(target_dir);
0502 if (IS_ERR(target_dir))
0503 goto err_result;
0504
0505
0506
0507
0508
0509
0510 err = reconnect_path(mnt, target_dir, nbuf);
0511 if (err) {
0512 dput(target_dir);
0513 goto err_result;
0514 }
0515
0516
0517
0518
0519
0520
0521 err = exportfs_get_name(mnt, target_dir, nbuf, result);
0522 if (err) {
0523 dput(target_dir);
0524 goto err_result;
0525 }
0526
0527 inode_lock(target_dir->d_inode);
0528 nresult = lookup_one(mnt_user_ns(mnt), nbuf,
0529 target_dir, strlen(nbuf));
0530 if (!IS_ERR(nresult)) {
0531 if (unlikely(nresult->d_inode != result->d_inode)) {
0532 dput(nresult);
0533 nresult = ERR_PTR(-ESTALE);
0534 }
0535 }
0536 inode_unlock(target_dir->d_inode);
0537
0538
0539
0540
0541 dput(target_dir);
0542
0543 if (IS_ERR(nresult)) {
0544 err = PTR_ERR(nresult);
0545 goto err_result;
0546 }
0547 dput(result);
0548 result = nresult;
0549
0550
0551
0552
0553
0554 alias = find_acceptable_alias(result, acceptable, context);
0555 if (!alias) {
0556 err = -EACCES;
0557 goto err_result;
0558 }
0559
0560 return alias;
0561 }
0562
0563 err_result:
0564 dput(result);
0565 return ERR_PTR(err);
0566 }
0567 EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
0568
0569 struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
0570 int fh_len, int fileid_type,
0571 int (*acceptable)(void *, struct dentry *),
0572 void *context)
0573 {
0574 struct dentry *ret;
0575
0576 ret = exportfs_decode_fh_raw(mnt, fid, fh_len, fileid_type,
0577 acceptable, context);
0578 if (IS_ERR_OR_NULL(ret)) {
0579 if (ret == ERR_PTR(-ENOMEM))
0580 return ret;
0581 return ERR_PTR(-ESTALE);
0582 }
0583 return ret;
0584 }
0585 EXPORT_SYMBOL_GPL(exportfs_decode_fh);
0586
0587 MODULE_LICENSE("GPL");