| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /** |
|---|
| 2 | 3 | * eCryptfs: Linux filesystem encryption layer |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * Copyright (C) 2004-2007 International Business Machines Corp. |
|---|
| 7 | 8 | * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> |
|---|
| 8 | 9 | * Michael C. Thompsion <mcthomps@us.ibm.com> |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or |
|---|
| 11 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 12 | | - * published by the Free Software Foundation; either version 2 of the |
|---|
| 13 | | - * License, or (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 16 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 18 | | - * General Public License for more details. |
|---|
| 19 | | - * |
|---|
| 20 | | - * You should have received a copy of the GNU General Public License |
|---|
| 21 | | - * along with this program; if not, write to the Free Software |
|---|
| 22 | | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
|---|
| 23 | | - * 02111-1307, USA. |
|---|
| 24 | 10 | */ |
|---|
| 25 | 11 | |
|---|
| 26 | 12 | #include <linux/file.h> |
|---|
| .. | .. |
|---|
| 142 | 128 | struct inode *inode) |
|---|
| 143 | 129 | { |
|---|
| 144 | 130 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); |
|---|
| 145 | | - struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); |
|---|
| 146 | 131 | struct dentry *lower_dir_dentry; |
|---|
| 132 | + struct inode *lower_dir_inode; |
|---|
| 147 | 133 | int rc; |
|---|
| 148 | 134 | |
|---|
| 149 | | - dget(lower_dentry); |
|---|
| 150 | | - lower_dir_dentry = lock_parent(lower_dentry); |
|---|
| 151 | | - rc = vfs_unlink(lower_dir_inode, lower_dentry, NULL); |
|---|
| 135 | + lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); |
|---|
| 136 | + lower_dir_inode = d_inode(lower_dir_dentry); |
|---|
| 137 | + inode_lock_nested(lower_dir_inode, I_MUTEX_PARENT); |
|---|
| 138 | + dget(lower_dentry); // don't even try to make the lower negative |
|---|
| 139 | + if (lower_dentry->d_parent != lower_dir_dentry) |
|---|
| 140 | + rc = -EINVAL; |
|---|
| 141 | + else if (d_unhashed(lower_dentry)) |
|---|
| 142 | + rc = -EINVAL; |
|---|
| 143 | + else |
|---|
| 144 | + rc = vfs_unlink(lower_dir_inode, lower_dentry, NULL); |
|---|
| 152 | 145 | if (rc) { |
|---|
| 153 | 146 | printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); |
|---|
| 154 | 147 | goto out_unlock; |
|---|
| .. | .. |
|---|
| 156 | 149 | fsstack_copy_attr_times(dir, lower_dir_inode); |
|---|
| 157 | 150 | set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); |
|---|
| 158 | 151 | inode->i_ctime = dir->i_ctime; |
|---|
| 159 | | - d_drop(dentry); |
|---|
| 160 | 152 | out_unlock: |
|---|
| 161 | | - unlock_dir(lower_dir_dentry); |
|---|
| 162 | 153 | dput(lower_dentry); |
|---|
| 154 | + inode_unlock(lower_dir_inode); |
|---|
| 155 | + if (!rc) |
|---|
| 156 | + d_drop(dentry); |
|---|
| 163 | 157 | return rc; |
|---|
| 164 | 158 | } |
|---|
| 165 | 159 | |
|---|
| .. | .. |
|---|
| 533 | 527 | { |
|---|
| 534 | 528 | struct dentry *lower_dentry; |
|---|
| 535 | 529 | struct dentry *lower_dir_dentry; |
|---|
| 530 | + struct inode *lower_dir_inode; |
|---|
| 536 | 531 | int rc; |
|---|
| 537 | 532 | |
|---|
| 538 | 533 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
|---|
| 539 | | - dget(dentry); |
|---|
| 540 | | - lower_dir_dentry = lock_parent(lower_dentry); |
|---|
| 541 | | - dget(lower_dentry); |
|---|
| 542 | | - rc = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry); |
|---|
| 543 | | - dput(lower_dentry); |
|---|
| 544 | | - if (!rc && d_really_is_positive(dentry)) |
|---|
| 534 | + lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); |
|---|
| 535 | + lower_dir_inode = d_inode(lower_dir_dentry); |
|---|
| 536 | + |
|---|
| 537 | + inode_lock_nested(lower_dir_inode, I_MUTEX_PARENT); |
|---|
| 538 | + dget(lower_dentry); // don't even try to make the lower negative |
|---|
| 539 | + if (lower_dentry->d_parent != lower_dir_dentry) |
|---|
| 540 | + rc = -EINVAL; |
|---|
| 541 | + else if (d_unhashed(lower_dentry)) |
|---|
| 542 | + rc = -EINVAL; |
|---|
| 543 | + else |
|---|
| 544 | + rc = vfs_rmdir(lower_dir_inode, lower_dentry); |
|---|
| 545 | + if (!rc) { |
|---|
| 545 | 546 | clear_nlink(d_inode(dentry)); |
|---|
| 546 | | - fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); |
|---|
| 547 | | - set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink); |
|---|
| 548 | | - unlock_dir(lower_dir_dentry); |
|---|
| 547 | + fsstack_copy_attr_times(dir, lower_dir_inode); |
|---|
| 548 | + set_nlink(dir, lower_dir_inode->i_nlink); |
|---|
| 549 | + } |
|---|
| 550 | + dput(lower_dentry); |
|---|
| 551 | + inode_unlock(lower_dir_inode); |
|---|
| 549 | 552 | if (!rc) |
|---|
| 550 | 553 | d_drop(dentry); |
|---|
| 551 | | - dput(dentry); |
|---|
| 552 | 554 | return rc; |
|---|
| 553 | 555 | } |
|---|
| 554 | 556 | |
|---|
| .. | .. |
|---|
| 586 | 588 | struct dentry *lower_new_dentry; |
|---|
| 587 | 589 | struct dentry *lower_old_dir_dentry; |
|---|
| 588 | 590 | struct dentry *lower_new_dir_dentry; |
|---|
| 589 | | - struct dentry *trap = NULL; |
|---|
| 591 | + struct dentry *trap; |
|---|
| 590 | 592 | struct inode *target_inode; |
|---|
| 591 | 593 | |
|---|
| 592 | 594 | if (flags) |
|---|
| 593 | 595 | return -EINVAL; |
|---|
| 594 | 596 | |
|---|
| 597 | + lower_old_dir_dentry = ecryptfs_dentry_to_lower(old_dentry->d_parent); |
|---|
| 598 | + lower_new_dir_dentry = ecryptfs_dentry_to_lower(new_dentry->d_parent); |
|---|
| 599 | + |
|---|
| 595 | 600 | lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); |
|---|
| 596 | 601 | lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); |
|---|
| 597 | | - dget(lower_old_dentry); |
|---|
| 598 | | - dget(lower_new_dentry); |
|---|
| 599 | | - lower_old_dir_dentry = dget_parent(lower_old_dentry); |
|---|
| 600 | | - lower_new_dir_dentry = dget_parent(lower_new_dentry); |
|---|
| 602 | + |
|---|
| 601 | 603 | target_inode = d_inode(new_dentry); |
|---|
| 604 | + |
|---|
| 602 | 605 | trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); |
|---|
| 603 | | - /* source should not be ancestor of target */ |
|---|
| 604 | | - if (trap == lower_old_dentry) { |
|---|
| 605 | | - rc = -EINVAL; |
|---|
| 606 | + dget(lower_new_dentry); |
|---|
| 607 | + rc = -EINVAL; |
|---|
| 608 | + if (lower_old_dentry->d_parent != lower_old_dir_dentry) |
|---|
| 606 | 609 | goto out_lock; |
|---|
| 607 | | - } |
|---|
| 610 | + if (lower_new_dentry->d_parent != lower_new_dir_dentry) |
|---|
| 611 | + goto out_lock; |
|---|
| 612 | + if (d_unhashed(lower_old_dentry) || d_unhashed(lower_new_dentry)) |
|---|
| 613 | + goto out_lock; |
|---|
| 614 | + /* source should not be ancestor of target */ |
|---|
| 615 | + if (trap == lower_old_dentry) |
|---|
| 616 | + goto out_lock; |
|---|
| 608 | 617 | /* target should not be ancestor of source */ |
|---|
| 609 | 618 | if (trap == lower_new_dentry) { |
|---|
| 610 | 619 | rc = -ENOTEMPTY; |
|---|
| .. | .. |
|---|
| 622 | 631 | if (new_dir != old_dir) |
|---|
| 623 | 632 | fsstack_copy_attr_all(old_dir, d_inode(lower_old_dir_dentry)); |
|---|
| 624 | 633 | out_lock: |
|---|
| 625 | | - unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); |
|---|
| 626 | | - dput(lower_new_dir_dentry); |
|---|
| 627 | | - dput(lower_old_dir_dentry); |
|---|
| 628 | 634 | dput(lower_new_dentry); |
|---|
| 629 | | - dput(lower_old_dentry); |
|---|
| 635 | + unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); |
|---|
| 630 | 636 | return rc; |
|---|
| 631 | 637 | } |
|---|
| 632 | 638 | |
|---|
| .. | .. |
|---|
| 1034 | 1040 | goto out; |
|---|
| 1035 | 1041 | } |
|---|
| 1036 | 1042 | inode_lock(lower_inode); |
|---|
| 1037 | | - rc = __vfs_getxattr(lower_dentry, lower_inode, name, value, size); |
|---|
| 1043 | + rc = __vfs_getxattr(lower_dentry, lower_inode, name, value, size, |
|---|
| 1044 | + XATTR_NOSECURITY); |
|---|
| 1038 | 1045 | inode_unlock(lower_inode); |
|---|
| 1039 | 1046 | out: |
|---|
| 1040 | 1047 | return rc; |
|---|
| .. | .. |
|---|
| 1119 | 1126 | |
|---|
| 1120 | 1127 | static int ecryptfs_xattr_get(const struct xattr_handler *handler, |
|---|
| 1121 | 1128 | struct dentry *dentry, struct inode *inode, |
|---|
| 1122 | | - const char *name, void *buffer, size_t size) |
|---|
| 1129 | + const char *name, void *buffer, size_t size, |
|---|
| 1130 | + int flags) |
|---|
| 1123 | 1131 | { |
|---|
| 1124 | 1132 | return ecryptfs_getxattr(dentry, inode, name, buffer, size); |
|---|
| 1125 | 1133 | } |
|---|
| .. | .. |
|---|
| 1137 | 1145 | } |
|---|
| 1138 | 1146 | } |
|---|
| 1139 | 1147 | |
|---|
| 1140 | | -const struct xattr_handler ecryptfs_xattr_handler = { |
|---|
| 1148 | +static const struct xattr_handler ecryptfs_xattr_handler = { |
|---|
| 1141 | 1149 | .prefix = "", /* match anything */ |
|---|
| 1142 | 1150 | .get = ecryptfs_xattr_get, |
|---|
| 1143 | 1151 | .set = ecryptfs_xattr_set, |
|---|