| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Overlayfs NFS export support. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Amir Goldstein <amir73il@gmail.com> |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright (C) 2017-2018 CTERA Networks. All Rights Reserved. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 9 | | - * under the terms of the GNU General Public License version 2 as published by |
|---|
| 10 | | - * the Free Software Foundation. |
|---|
| 11 | 8 | */ |
|---|
| 12 | 9 | |
|---|
| 13 | 10 | #include <linux/fs.h> |
|---|
| .. | .. |
|---|
| 33 | 30 | } |
|---|
| 34 | 31 | |
|---|
| 35 | 32 | if (err) { |
|---|
| 36 | | - pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n", |
|---|
| 33 | + pr_warn_ratelimited("failed to copy up on encode (%pd2, err=%i)\n", |
|---|
| 37 | 34 | dentry, err); |
|---|
| 38 | 35 | } |
|---|
| 39 | 36 | |
|---|
| .. | .. |
|---|
| 207 | 204 | * ovl_connect_layer() will try to make origin's layer "connected" by |
|---|
| 208 | 205 | * copying up a "connectable" ancestor. |
|---|
| 209 | 206 | */ |
|---|
| 210 | | - if (d_is_dir(dentry) && ofs->upper_mnt) |
|---|
| 207 | + if (d_is_dir(dentry) && ovl_upper_mnt(ofs)) |
|---|
| 211 | 208 | return ovl_connect_layer(dentry); |
|---|
| 212 | 209 | |
|---|
| 213 | 210 | /* Lower file handle for indexed and non-upper dir/non-dir */ |
|---|
| 214 | 211 | return 1; |
|---|
| 215 | 212 | } |
|---|
| 216 | 213 | |
|---|
| 217 | | -static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen) |
|---|
| 214 | +static int ovl_dentry_to_fid(struct dentry *dentry, u32 *fid, int buflen) |
|---|
| 218 | 215 | { |
|---|
| 219 | 216 | struct ovl_fh *fh = NULL; |
|---|
| 220 | 217 | int err, enc_lower; |
|---|
| 218 | + int len; |
|---|
| 221 | 219 | |
|---|
| 222 | 220 | /* |
|---|
| 223 | 221 | * Check if we should encode a lower or upper file handle and maybe |
|---|
| .. | .. |
|---|
| 233 | 231 | if (IS_ERR(fh)) |
|---|
| 234 | 232 | return PTR_ERR(fh); |
|---|
| 235 | 233 | |
|---|
| 236 | | - err = -EOVERFLOW; |
|---|
| 237 | | - if (fh->len > buflen) |
|---|
| 238 | | - goto fail; |
|---|
| 239 | | - |
|---|
| 240 | | - memcpy(buf, (char *)fh, fh->len); |
|---|
| 241 | | - err = fh->len; |
|---|
| 234 | + len = OVL_FH_LEN(fh); |
|---|
| 235 | + if (len <= buflen) |
|---|
| 236 | + memcpy(fid, fh, len); |
|---|
| 237 | + err = len; |
|---|
| 242 | 238 | |
|---|
| 243 | 239 | out: |
|---|
| 244 | 240 | kfree(fh); |
|---|
| 245 | 241 | return err; |
|---|
| 246 | 242 | |
|---|
| 247 | 243 | fail: |
|---|
| 248 | | - pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n", |
|---|
| 249 | | - dentry, err, buflen, fh ? (int)fh->len : 0, |
|---|
| 250 | | - fh ? fh->type : 0); |
|---|
| 244 | + pr_warn_ratelimited("failed to encode file handle (%pd2, err=%i)\n", |
|---|
| 245 | + dentry, err); |
|---|
| 251 | 246 | goto out; |
|---|
| 252 | | -} |
|---|
| 253 | | - |
|---|
| 254 | | -static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len) |
|---|
| 255 | | -{ |
|---|
| 256 | | - int res, len = *max_len << 2; |
|---|
| 257 | | - |
|---|
| 258 | | - res = ovl_d_to_fh(dentry, (char *)fid, len); |
|---|
| 259 | | - if (res <= 0) |
|---|
| 260 | | - return FILEID_INVALID; |
|---|
| 261 | | - |
|---|
| 262 | | - len = res; |
|---|
| 263 | | - |
|---|
| 264 | | - /* Round up to dwords */ |
|---|
| 265 | | - *max_len = (len + 3) >> 2; |
|---|
| 266 | | - return OVL_FILEID; |
|---|
| 267 | 247 | } |
|---|
| 268 | 248 | |
|---|
| 269 | 249 | static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len, |
|---|
| 270 | 250 | struct inode *parent) |
|---|
| 271 | 251 | { |
|---|
| 272 | 252 | struct dentry *dentry; |
|---|
| 273 | | - int type; |
|---|
| 253 | + int bytes, buflen = *max_len << 2; |
|---|
| 274 | 254 | |
|---|
| 275 | 255 | /* TODO: encode connectable file handles */ |
|---|
| 276 | 256 | if (parent) |
|---|
| 277 | 257 | return FILEID_INVALID; |
|---|
| 278 | 258 | |
|---|
| 279 | 259 | dentry = d_find_any_alias(inode); |
|---|
| 280 | | - if (WARN_ON(!dentry)) |
|---|
| 260 | + if (!dentry) |
|---|
| 281 | 261 | return FILEID_INVALID; |
|---|
| 282 | 262 | |
|---|
| 283 | | - type = ovl_dentry_to_fh(dentry, fid, max_len); |
|---|
| 284 | | - |
|---|
| 263 | + bytes = ovl_dentry_to_fid(dentry, fid, buflen); |
|---|
| 285 | 264 | dput(dentry); |
|---|
| 286 | | - return type; |
|---|
| 265 | + if (bytes <= 0) |
|---|
| 266 | + return FILEID_INVALID; |
|---|
| 267 | + |
|---|
| 268 | + *max_len = bytes >> 2; |
|---|
| 269 | + if (bytes > buflen) |
|---|
| 270 | + return FILEID_INVALID; |
|---|
| 271 | + |
|---|
| 272 | + return OVL_FILEID_V1; |
|---|
| 287 | 273 | } |
|---|
| 288 | 274 | |
|---|
| 289 | 275 | /* |
|---|
| .. | .. |
|---|
| 320 | 306 | ovl_set_flag(OVL_UPPERDATA, inode); |
|---|
| 321 | 307 | |
|---|
| 322 | 308 | dentry = d_find_any_alias(inode); |
|---|
| 323 | | - if (!dentry) { |
|---|
| 324 | | - dentry = d_alloc_anon(inode->i_sb); |
|---|
| 325 | | - if (!dentry) |
|---|
| 326 | | - goto nomem; |
|---|
| 327 | | - oe = ovl_alloc_entry(lower ? 1 : 0); |
|---|
| 328 | | - if (!oe) |
|---|
| 329 | | - goto nomem; |
|---|
| 309 | + if (dentry) |
|---|
| 310 | + goto out_iput; |
|---|
| 330 | 311 | |
|---|
| 331 | | - if (lower) { |
|---|
| 332 | | - oe->lowerstack->dentry = dget(lower); |
|---|
| 333 | | - oe->lowerstack->layer = lowerpath->layer; |
|---|
| 334 | | - } |
|---|
| 335 | | - dentry->d_fsdata = oe; |
|---|
| 336 | | - if (upper_alias) |
|---|
| 337 | | - ovl_dentry_set_upper_alias(dentry); |
|---|
| 312 | + dentry = d_alloc_anon(inode->i_sb); |
|---|
| 313 | + if (unlikely(!dentry)) |
|---|
| 314 | + goto nomem; |
|---|
| 315 | + oe = ovl_alloc_entry(lower ? 1 : 0); |
|---|
| 316 | + if (!oe) |
|---|
| 317 | + goto nomem; |
|---|
| 318 | + |
|---|
| 319 | + if (lower) { |
|---|
| 320 | + oe->lowerstack->dentry = dget(lower); |
|---|
| 321 | + oe->lowerstack->layer = lowerpath->layer; |
|---|
| 338 | 322 | } |
|---|
| 323 | + dentry->d_fsdata = oe; |
|---|
| 324 | + if (upper_alias) |
|---|
| 325 | + ovl_dentry_set_upper_alias(dentry); |
|---|
| 326 | + |
|---|
| 327 | + ovl_dentry_init_reval(dentry, upper); |
|---|
| 339 | 328 | |
|---|
| 340 | 329 | return d_instantiate_anon(dentry, inode); |
|---|
| 341 | 330 | |
|---|
| 342 | 331 | nomem: |
|---|
| 343 | | - iput(inode); |
|---|
| 344 | 332 | dput(dentry); |
|---|
| 345 | | - return ERR_PTR(-ENOMEM); |
|---|
| 333 | + dentry = ERR_PTR(-ENOMEM); |
|---|
| 334 | +out_iput: |
|---|
| 335 | + iput(inode); |
|---|
| 336 | + return dentry; |
|---|
| 346 | 337 | } |
|---|
| 347 | 338 | |
|---|
| 348 | 339 | /* Get the upper or lower dentry in stach whose on layer @idx */ |
|---|
| .. | .. |
|---|
| 370 | 361 | */ |
|---|
| 371 | 362 | static struct dentry *ovl_lookup_real_one(struct dentry *connected, |
|---|
| 372 | 363 | struct dentry *real, |
|---|
| 373 | | - struct ovl_layer *layer) |
|---|
| 364 | + const struct ovl_layer *layer) |
|---|
| 374 | 365 | { |
|---|
| 375 | 366 | struct inode *dir = d_inode(connected); |
|---|
| 376 | 367 | struct dentry *this, *parent = NULL; |
|---|
| .. | .. |
|---|
| 397 | 388 | * pointer because we hold no lock on the real dentry. |
|---|
| 398 | 389 | */ |
|---|
| 399 | 390 | take_dentry_name_snapshot(&name, real); |
|---|
| 400 | | - this = lookup_one_len(name.name, connected, strlen(name.name)); |
|---|
| 391 | + this = lookup_one_len(name.name.name, connected, name.name.len); |
|---|
| 392 | + release_dentry_name_snapshot(&name); |
|---|
| 401 | 393 | err = PTR_ERR(this); |
|---|
| 402 | 394 | if (IS_ERR(this)) { |
|---|
| 403 | 395 | goto fail; |
|---|
| .. | .. |
|---|
| 412 | 404 | } |
|---|
| 413 | 405 | |
|---|
| 414 | 406 | out: |
|---|
| 415 | | - release_dentry_name_snapshot(&name); |
|---|
| 416 | 407 | dput(parent); |
|---|
| 417 | 408 | inode_unlock(dir); |
|---|
| 418 | 409 | return this; |
|---|
| 419 | 410 | |
|---|
| 420 | 411 | fail: |
|---|
| 421 | | - pr_warn_ratelimited("overlayfs: failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
|---|
| 412 | + pr_warn_ratelimited("failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
|---|
| 422 | 413 | real, layer->idx, connected, err); |
|---|
| 423 | 414 | this = ERR_PTR(err); |
|---|
| 424 | 415 | goto out; |
|---|
| .. | .. |
|---|
| 426 | 417 | |
|---|
| 427 | 418 | static struct dentry *ovl_lookup_real(struct super_block *sb, |
|---|
| 428 | 419 | struct dentry *real, |
|---|
| 429 | | - struct ovl_layer *layer); |
|---|
| 420 | + const struct ovl_layer *layer); |
|---|
| 430 | 421 | |
|---|
| 431 | 422 | /* |
|---|
| 432 | 423 | * Lookup an indexed or hashed overlay dentry by real inode. |
|---|
| 433 | 424 | */ |
|---|
| 434 | 425 | static struct dentry *ovl_lookup_real_inode(struct super_block *sb, |
|---|
| 435 | 426 | struct dentry *real, |
|---|
| 436 | | - struct ovl_layer *layer) |
|---|
| 427 | + const struct ovl_layer *layer) |
|---|
| 437 | 428 | { |
|---|
| 438 | 429 | struct ovl_fs *ofs = sb->s_fs_info; |
|---|
| 439 | | - struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; |
|---|
| 440 | 430 | struct dentry *index = NULL; |
|---|
| 441 | 431 | struct dentry *this = NULL; |
|---|
| 442 | 432 | struct inode *inode; |
|---|
| .. | .. |
|---|
| 478 | 468 | * recursive call walks back from indexed upper to the topmost |
|---|
| 479 | 469 | * connected/hashed upper parent (or up to root). |
|---|
| 480 | 470 | */ |
|---|
| 481 | | - this = ovl_lookup_real(sb, upper, &upper_layer); |
|---|
| 471 | + this = ovl_lookup_real(sb, upper, &ofs->layers[0]); |
|---|
| 482 | 472 | dput(upper); |
|---|
| 483 | 473 | } |
|---|
| 484 | 474 | |
|---|
| .. | .. |
|---|
| 499 | 489 | */ |
|---|
| 500 | 490 | static struct dentry *ovl_lookup_real_ancestor(struct super_block *sb, |
|---|
| 501 | 491 | struct dentry *real, |
|---|
| 502 | | - struct ovl_layer *layer) |
|---|
| 492 | + const struct ovl_layer *layer) |
|---|
| 503 | 493 | { |
|---|
| 504 | 494 | struct dentry *next, *parent = NULL; |
|---|
| 505 | 495 | struct dentry *ancestor = ERR_PTR(-EIO); |
|---|
| .. | .. |
|---|
| 552 | 542 | */ |
|---|
| 553 | 543 | static struct dentry *ovl_lookup_real(struct super_block *sb, |
|---|
| 554 | 544 | struct dentry *real, |
|---|
| 555 | | - struct ovl_layer *layer) |
|---|
| 545 | + const struct ovl_layer *layer) |
|---|
| 556 | 546 | { |
|---|
| 557 | 547 | struct dentry *connected; |
|---|
| 558 | 548 | int err = 0; |
|---|
| .. | .. |
|---|
| 643 | 633 | return connected; |
|---|
| 644 | 634 | |
|---|
| 645 | 635 | fail: |
|---|
| 646 | | - pr_warn_ratelimited("overlayfs: failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
|---|
| 636 | + pr_warn_ratelimited("failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
|---|
| 647 | 637 | real, layer->idx, connected, err); |
|---|
| 648 | 638 | dput(connected); |
|---|
| 649 | 639 | return ERR_PTR(err); |
|---|
| .. | .. |
|---|
| 658 | 648 | struct dentry *index) |
|---|
| 659 | 649 | { |
|---|
| 660 | 650 | struct ovl_fs *ofs = sb->s_fs_info; |
|---|
| 661 | | - struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; |
|---|
| 662 | | - struct ovl_layer *layer = upper ? &upper_layer : lowerpath->layer; |
|---|
| 651 | + const struct ovl_layer *layer = upper ? &ofs->layers[0] : lowerpath->layer; |
|---|
| 663 | 652 | struct dentry *real = upper ?: (index ?: lowerpath->dentry); |
|---|
| 664 | 653 | |
|---|
| 665 | 654 | /* |
|---|
| .. | .. |
|---|
| 687 | 676 | struct dentry *dentry; |
|---|
| 688 | 677 | struct dentry *upper; |
|---|
| 689 | 678 | |
|---|
| 690 | | - if (!ofs->upper_mnt) |
|---|
| 679 | + if (!ovl_upper_mnt(ofs)) |
|---|
| 691 | 680 | return ERR_PTR(-EACCES); |
|---|
| 692 | 681 | |
|---|
| 693 | | - upper = ovl_decode_real_fh(fh, ofs->upper_mnt, true); |
|---|
| 682 | + upper = ovl_decode_real_fh(fh, ovl_upper_mnt(ofs), true); |
|---|
| 694 | 683 | if (IS_ERR_OR_NULL(upper)) |
|---|
| 695 | 684 | return upper; |
|---|
| 696 | 685 | |
|---|
| .. | .. |
|---|
| 762 | 751 | goto out_err; |
|---|
| 763 | 752 | } |
|---|
| 764 | 753 | if (index) { |
|---|
| 765 | | - err = ovl_verify_origin(index, origin.dentry, false); |
|---|
| 754 | + err = ovl_verify_origin(ofs, index, origin.dentry, false); |
|---|
| 766 | 755 | if (err) |
|---|
| 767 | 756 | goto out_err; |
|---|
| 768 | 757 | } |
|---|
| .. | .. |
|---|
| 780 | 769 | goto out; |
|---|
| 781 | 770 | } |
|---|
| 782 | 771 | |
|---|
| 772 | +static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type) |
|---|
| 773 | +{ |
|---|
| 774 | + struct ovl_fh *fh; |
|---|
| 775 | + |
|---|
| 776 | + /* If on-wire inner fid is aligned - nothing to do */ |
|---|
| 777 | + if (fh_type == OVL_FILEID_V1) |
|---|
| 778 | + return (struct ovl_fh *)fid; |
|---|
| 779 | + |
|---|
| 780 | + if (fh_type != OVL_FILEID_V0) |
|---|
| 781 | + return ERR_PTR(-EINVAL); |
|---|
| 782 | + |
|---|
| 783 | + if (buflen <= OVL_FH_WIRE_OFFSET) |
|---|
| 784 | + return ERR_PTR(-EINVAL); |
|---|
| 785 | + |
|---|
| 786 | + fh = kzalloc(buflen, GFP_KERNEL); |
|---|
| 787 | + if (!fh) |
|---|
| 788 | + return ERR_PTR(-ENOMEM); |
|---|
| 789 | + |
|---|
| 790 | + /* Copy unaligned inner fh into aligned buffer */ |
|---|
| 791 | + memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET); |
|---|
| 792 | + return fh; |
|---|
| 793 | +} |
|---|
| 794 | + |
|---|
| 783 | 795 | static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, |
|---|
| 784 | 796 | int fh_len, int fh_type) |
|---|
| 785 | 797 | { |
|---|
| 786 | 798 | struct dentry *dentry = NULL; |
|---|
| 787 | | - struct ovl_fh *fh = (struct ovl_fh *) fid; |
|---|
| 799 | + struct ovl_fh *fh = NULL; |
|---|
| 788 | 800 | int len = fh_len << 2; |
|---|
| 789 | 801 | unsigned int flags = 0; |
|---|
| 790 | 802 | int err; |
|---|
| 791 | 803 | |
|---|
| 792 | | - err = -EINVAL; |
|---|
| 793 | | - if (fh_type != OVL_FILEID) |
|---|
| 804 | + fh = ovl_fid_to_fh(fid, len, fh_type); |
|---|
| 805 | + err = PTR_ERR(fh); |
|---|
| 806 | + if (IS_ERR(fh)) |
|---|
| 794 | 807 | goto out_err; |
|---|
| 795 | 808 | |
|---|
| 796 | 809 | err = ovl_check_fh_len(fh, len); |
|---|
| 797 | 810 | if (err) |
|---|
| 798 | 811 | goto out_err; |
|---|
| 799 | 812 | |
|---|
| 800 | | - flags = fh->flags; |
|---|
| 813 | + flags = fh->fb.flags; |
|---|
| 801 | 814 | dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ? |
|---|
| 802 | 815 | ovl_upper_fh_to_d(sb, fh) : |
|---|
| 803 | 816 | ovl_lower_fh_to_d(sb, fh); |
|---|
| .. | .. |
|---|
| 805 | 818 | if (IS_ERR(dentry) && err != -ESTALE) |
|---|
| 806 | 819 | goto out_err; |
|---|
| 807 | 820 | |
|---|
| 821 | +out: |
|---|
| 822 | + /* We may have needed to re-align OVL_FILEID_V0 */ |
|---|
| 823 | + if (!IS_ERR_OR_NULL(fh) && fh != (void *)fid) |
|---|
| 824 | + kfree(fh); |
|---|
| 825 | + |
|---|
| 808 | 826 | return dentry; |
|---|
| 809 | 827 | |
|---|
| 810 | 828 | out_err: |
|---|
| 811 | | - pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n", |
|---|
| 812 | | - len, fh_type, flags, err); |
|---|
| 813 | | - return ERR_PTR(err); |
|---|
| 829 | + pr_warn_ratelimited("failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n", |
|---|
| 830 | + fh_len, fh_type, flags, err); |
|---|
| 831 | + dentry = ERR_PTR(err); |
|---|
| 832 | + goto out; |
|---|
| 814 | 833 | } |
|---|
| 815 | 834 | |
|---|
| 816 | 835 | static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid, |
|---|
| 817 | 836 | int fh_len, int fh_type) |
|---|
| 818 | 837 | { |
|---|
| 819 | | - pr_warn_ratelimited("overlayfs: connectable file handles not supported; use 'no_subtree_check' exportfs option.\n"); |
|---|
| 838 | + pr_warn_ratelimited("connectable file handles not supported; use 'no_subtree_check' exportfs option.\n"); |
|---|
| 820 | 839 | return ERR_PTR(-EACCES); |
|---|
| 821 | 840 | } |
|---|
| 822 | 841 | |
|---|