Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'vfs-6.19-rc1.ovl' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull overlayfs cred guard conversion from Christian Brauner:
"This converts all of overlayfs to use credential guards, eliminating
manual credential management throughout the filesystem.

Credential guard conversion:

- Convert all of overlayfs to use credential guards, replacing the
manual ovl_override_creds()/ovl_revert_creds() pattern with scoped
guards.

This makes credential handling visually explicit and eliminates a
class of potential bugs from mismatched override/revert calls.

(1) Basic credential guard (with_ovl_creds)
(2) Creator credential guard (ovl_override_creator_creds):

Introduced a specialized guard for file creation operations
that handles the two-phase credential override (mounter
credentials, then fs{g,u}id override). The new pattern is much
clearer:

with_ovl_creds(dentry->d_sb) {
scoped_class(prepare_creds_ovl, cred, dentry, inode, mode) {
if (IS_ERR(cred))
return PTR_ERR(cred);
/* creation operations */
}
}

(3) Copy-up credential guard (ovl_cu_creds):

Introduced a specialized guard for copy-up operations,
simplifying the previous struct ovl_cu_creds helper and
associated functions.

Ported ovl_copy_up_workdir() and ovl_copy_up_tmpfile() to this
pattern.

Cleanups:

- Remove ovl_revert_creds() after all callers converted to guards

- Remove struct ovl_cu_creds and associated functions

- Drop ovl_setup_cred_for_create() after conversion

- Refactor ovl_fill_super(), ovl_lookup(), ovl_iterate(),
ovl_rename() for cleaner credential guard scope

- Introduce struct ovl_renamedata to simplify rename handling

- Don't override credentials for ovl_check_whiteouts() (unnecessary)

- Remove unneeded semicolon"

* tag 'vfs-6.19-rc1.ovl' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (54 commits)
ovl: remove unneeded semicolon
ovl: remove struct ovl_cu_creds and associated functions
ovl: port ovl_copy_up_tmpfile() to cred guard
ovl: mark *_cu_creds() as unused temporarily
ovl: port ovl_copy_up_workdir() to cred guard
ovl: add copy up credential guard
ovl: drop ovl_setup_cred_for_create()
ovl: port ovl_create_or_link() to new ovl_override_creator_creds cleanup guard
ovl: mark ovl_setup_cred_for_create() as unused temporarily
ovl: reflow ovl_create_or_link()
ovl: port ovl_create_tmpfile() to new ovl_override_creator_creds cleanup guard
ovl: add ovl_override_creator_creds cred guard
ovl: remove ovl_revert_creds()
ovl: port ovl_fill_super() to cred guard
ovl: refactor ovl_fill_super()
ovl: port ovl_lower_positive() to cred guard
ovl: port ovl_lookup() to cred guard
ovl: refactor ovl_lookup()
ovl: port ovl_copyfile() to cred guard
ovl: port ovl_rename() to cred guard
...

+625 -668
+33 -37
fs/overlayfs/copy_up.c
··· 724 724 return err; 725 725 } 726 726 727 - struct ovl_cu_creds { 728 - const struct cred *old; 729 - struct cred *new; 730 - }; 731 - 732 - static int ovl_prep_cu_creds(struct dentry *dentry, struct ovl_cu_creds *cc) 727 + static const struct cred *ovl_prepare_copy_up_creds(struct dentry *dentry) 733 728 { 729 + struct cred *copy_up_cred = NULL; 734 730 int err; 735 731 736 - cc->old = cc->new = NULL; 737 - err = security_inode_copy_up(dentry, &cc->new); 732 + err = security_inode_copy_up(dentry, &copy_up_cred); 738 733 if (err < 0) 739 - return err; 734 + return ERR_PTR(err); 740 735 741 - if (cc->new) 742 - cc->old = override_creds(cc->new); 736 + if (!copy_up_cred) 737 + return NULL; 743 738 744 - return 0; 739 + return override_creds(copy_up_cred); 745 740 } 746 741 747 - static void ovl_revert_cu_creds(struct ovl_cu_creds *cc) 742 + static void ovl_revert_copy_up_creds(const struct cred *orig_cred) 748 743 { 749 - if (cc->new) { 750 - revert_creds(cc->old); 751 - put_cred(cc->new); 752 - } 744 + const struct cred *copy_up_cred; 745 + 746 + copy_up_cred = revert_creds(orig_cred); 747 + put_cred(copy_up_cred); 753 748 } 749 + 750 + DEFINE_CLASS(copy_up_creds, const struct cred *, 751 + if (!IS_ERR_OR_NULL(_T)) ovl_revert_copy_up_creds(_T), 752 + ovl_prepare_copy_up_creds(dentry), struct dentry *dentry) 754 753 755 754 /* 756 755 * Copyup using workdir to prepare temp file. Used when copying up directories, ··· 762 763 struct path path = { .mnt = ovl_upper_mnt(ofs) }; 763 764 struct renamedata rd = {}; 764 765 struct dentry *temp; 765 - struct ovl_cu_creds cc; 766 766 int err; 767 767 struct ovl_cattr cattr = { 768 768 /* Can't properly set mode on creation because of the umask */ ··· 770 772 .link = c->link 771 773 }; 772 774 773 - err = ovl_prep_cu_creds(c->dentry, &cc); 774 - if (err) 775 - return err; 775 + scoped_class(copy_up_creds, copy_up_creds, c->dentry) { 776 + if (IS_ERR(copy_up_creds)) 777 + return PTR_ERR(copy_up_creds); 776 778 777 - ovl_start_write(c->dentry); 778 - temp = ovl_create_temp(ofs, c->workdir, &cattr); 779 - ovl_end_write(c->dentry); 780 - ovl_revert_cu_creds(&cc); 779 + ovl_start_write(c->dentry); 780 + temp = ovl_create_temp(ofs, c->workdir, &cattr); 781 + ovl_end_write(c->dentry); 782 + } 781 783 782 784 if (IS_ERR(temp)) 783 785 return PTR_ERR(temp); ··· 855 857 struct inode *udir = d_inode(c->destdir); 856 858 struct dentry *temp, *upper; 857 859 struct file *tmpfile; 858 - struct ovl_cu_creds cc; 859 860 int err; 860 861 861 - err = ovl_prep_cu_creds(c->dentry, &cc); 862 - if (err) 863 - return err; 862 + scoped_class(copy_up_creds, copy_up_creds, c->dentry) { 863 + if (IS_ERR(copy_up_creds)) 864 + return PTR_ERR(copy_up_creds); 864 865 865 - ovl_start_write(c->dentry); 866 - tmpfile = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode); 867 - ovl_end_write(c->dentry); 868 - ovl_revert_cu_creds(&cc); 866 + ovl_start_write(c->dentry); 867 + tmpfile = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode); 868 + ovl_end_write(c->dentry); 869 + } 870 + 869 871 if (IS_ERR(tmpfile)) 870 872 return PTR_ERR(tmpfile); 871 873 ··· 1201 1203 static int ovl_copy_up_flags(struct dentry *dentry, int flags) 1202 1204 { 1203 1205 int err = 0; 1204 - const struct cred *old_cred; 1205 1206 bool disconnected = (dentry->d_flags & DCACHE_DISCONNECTED); 1206 1207 1207 1208 /* ··· 1220 1223 if (err) 1221 1224 return err; 1222 1225 1223 - old_cred = ovl_override_creds(dentry->d_sb); 1224 1226 while (!err) { 1225 1227 struct dentry *next; 1226 1228 struct dentry *parent = NULL; ··· 1239 1243 next = parent; 1240 1244 } 1241 1245 1242 - err = ovl_copy_up_one(parent, next, flags); 1246 + with_ovl_creds(dentry->d_sb) 1247 + err = ovl_copy_up_one(parent, next, flags); 1243 1248 1244 1249 dput(parent); 1245 1250 dput(next); 1246 1251 } 1247 - ovl_revert_creds(old_cred); 1248 1252 1249 1253 return err; 1250 1254 }
+191 -173
fs/overlayfs/dir.c
··· 105 105 whiteout = dget(link); 106 106 end_creating(link); 107 107 if (!err) 108 - return whiteout;; 108 + return whiteout; 109 109 110 110 if (err != -EMLINK) { 111 111 pr_warn("Failed to link whiteout - disabling whiteout inode sharing(nlink=%u, err=%u)\n", ··· 581 581 goto out_dput; 582 582 } 583 583 584 - static const struct cred *ovl_setup_cred_for_create(struct dentry *dentry, 585 - struct inode *inode, 586 - umode_t mode, 587 - const struct cred *old_cred) 584 + static const struct cred *ovl_override_creator_creds(struct dentry *dentry, struct inode *inode, umode_t mode) 588 585 { 589 586 int err; 590 - struct cred *override_cred; 591 587 592 - override_cred = prepare_creds(); 588 + if (WARN_ON_ONCE(current->cred != ovl_creds(dentry->d_sb))) 589 + return ERR_PTR(-EINVAL); 590 + 591 + CLASS(prepare_creds, override_cred)(); 593 592 if (!override_cred) 594 593 return ERR_PTR(-ENOMEM); 595 594 596 595 override_cred->fsuid = inode->i_uid; 597 596 override_cred->fsgid = inode->i_gid; 597 + 598 598 err = security_dentry_create_files_as(dentry, mode, &dentry->d_name, 599 - old_cred, override_cred); 600 - if (err) { 601 - put_cred(override_cred); 599 + current->cred, override_cred); 600 + if (err) 602 601 return ERR_PTR(err); 603 - } 604 602 605 - /* 606 - * Caller is going to match this with revert_creds() and drop 607 - * referenec on the returned creds. 608 - * We must be called with creator creds already, otherwise we risk 609 - * leaking creds. 610 - */ 611 - old_cred = override_creds(override_cred); 612 - WARN_ON_ONCE(old_cred != ovl_creds(dentry->d_sb)); 603 + return override_creds(no_free_ptr(override_cred)); 604 + } 613 605 614 - return override_cred; 606 + static void ovl_revert_creator_creds(const struct cred *old_cred) 607 + { 608 + const struct cred *override_cred; 609 + 610 + override_cred = revert_creds(old_cred); 611 + put_cred(override_cred); 612 + } 613 + 614 + DEFINE_CLASS(ovl_override_creator_creds, 615 + const struct cred *, 616 + if (!IS_ERR_OR_NULL(_T)) ovl_revert_creator_creds(_T), 617 + ovl_override_creator_creds(dentry, inode, mode), 618 + struct dentry *dentry, struct inode *inode, umode_t mode) 619 + 620 + static int ovl_create_handle_whiteouts(struct dentry *dentry, 621 + struct inode *inode, 622 + struct ovl_cattr *attr) 623 + { 624 + if (!ovl_dentry_is_whiteout(dentry)) 625 + return ovl_create_upper(dentry, inode, attr); 626 + 627 + return ovl_create_over_whiteout(dentry, inode, attr); 615 628 } 616 629 617 630 static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, 618 631 struct ovl_cattr *attr, bool origin) 619 632 { 620 633 int err; 621 - const struct cred *old_cred, *new_cred = NULL; 622 634 struct dentry *parent = dentry->d_parent; 623 635 624 - old_cred = ovl_override_creds(dentry->d_sb); 636 + with_ovl_creds(dentry->d_sb) { 637 + /* 638 + * When linking a file with copy up origin into a new parent, mark the 639 + * new parent dir "impure". 640 + */ 641 + if (origin) { 642 + err = ovl_set_impure(parent, ovl_dentry_upper(parent)); 643 + if (err) 644 + return err; 645 + } 625 646 626 - /* 627 - * When linking a file with copy up origin into a new parent, mark the 628 - * new parent dir "impure". 629 - */ 630 - if (origin) { 631 - err = ovl_set_impure(parent, ovl_dentry_upper(parent)); 632 - if (err) 633 - goto out_revert_creds; 634 - } 635 - 636 - if (!attr->hardlink) { 637 647 /* 638 648 * In the creation cases(create, mkdir, mknod, symlink), 639 649 * ovl should transfer current's fs{u,g}id to underlying ··· 657 647 * create a new inode, so just use the ovl mounter's 658 648 * fs{u,g}id. 659 649 */ 660 - new_cred = ovl_setup_cred_for_create(dentry, inode, attr->mode, 661 - old_cred); 662 - err = PTR_ERR(new_cred); 663 - if (IS_ERR(new_cred)) { 664 - new_cred = NULL; 665 - goto out_revert_creds; 650 + 651 + if (attr->hardlink) 652 + return ovl_create_handle_whiteouts(dentry, inode, attr); 653 + 654 + scoped_class(ovl_override_creator_creds, cred, dentry, inode, attr->mode) { 655 + if (IS_ERR(cred)) 656 + return PTR_ERR(cred); 657 + return ovl_create_handle_whiteouts(dentry, inode, attr); 666 658 } 667 659 } 668 - 669 - if (!ovl_dentry_is_whiteout(dentry)) 670 - err = ovl_create_upper(dentry, inode, attr); 671 - else 672 - err = ovl_create_over_whiteout(dentry, inode, attr); 673 - 674 - out_revert_creds: 675 - ovl_revert_creds(old_cred); 676 - put_cred(new_cred); 677 660 return err; 678 661 } 679 662 ··· 742 739 743 740 static int ovl_set_link_redirect(struct dentry *dentry) 744 741 { 745 - const struct cred *old_cred; 746 - int err; 747 - 748 - old_cred = ovl_override_creds(dentry->d_sb); 749 - err = ovl_set_redirect(dentry, false); 750 - ovl_revert_creds(old_cred); 751 - 752 - return err; 742 + with_ovl_creds(dentry->d_sb) 743 + return ovl_set_redirect(dentry, false); 753 744 } 754 745 755 746 static int ovl_link(struct dentry *old, struct inode *newdir, ··· 918 921 static int ovl_do_remove(struct dentry *dentry, bool is_dir) 919 922 { 920 923 int err; 921 - const struct cred *old_cred; 922 924 bool lower_positive = ovl_lower_positive(dentry); 923 925 LIST_HEAD(list); 924 926 ··· 936 940 if (err) 937 941 goto out; 938 942 939 - old_cred = ovl_override_creds(dentry->d_sb); 940 - if (!lower_positive) 941 - err = ovl_remove_upper(dentry, is_dir, &list); 942 - else 943 - err = ovl_remove_and_whiteout(dentry, &list); 944 - ovl_revert_creds(old_cred); 943 + with_ovl_creds(dentry->d_sb) { 944 + if (!lower_positive) 945 + err = ovl_remove_upper(dentry, is_dir, &list); 946 + else 947 + err = ovl_remove_and_whiteout(dentry, &list); 948 + } 945 949 if (!err) { 946 950 if (is_dir) 947 951 clear_nlink(dentry->d_inode); ··· 1105 1109 return err; 1106 1110 } 1107 1111 1108 - static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir, 1109 - struct dentry *old, struct inode *newdir, 1110 - struct dentry *new, unsigned int flags) 1112 + struct ovl_renamedata { 1113 + struct renamedata; 1114 + struct dentry *opaquedir; 1115 + bool cleanup_whiteout; 1116 + bool update_nlink; 1117 + bool overwrite; 1118 + }; 1119 + 1120 + static int ovl_rename_start(struct ovl_renamedata *ovlrd, struct list_head *list) 1111 1121 { 1112 - int err; 1113 - struct dentry *old_upperdir; 1114 - struct dentry *new_upperdir; 1115 - struct renamedata rd = {}; 1116 - bool old_opaque; 1117 - bool new_opaque; 1118 - bool cleanup_whiteout = false; 1119 - bool update_nlink = false; 1120 - bool overwrite = !(flags & RENAME_EXCHANGE); 1122 + struct dentry *old = ovlrd->old_dentry; 1123 + struct dentry *new = ovlrd->new_dentry; 1121 1124 bool is_dir = d_is_dir(old); 1122 1125 bool new_is_dir = d_is_dir(new); 1123 - bool samedir = olddir == newdir; 1124 - struct dentry *opaquedir = NULL; 1125 - struct dentry *whiteout = NULL; 1126 - const struct cred *old_cred = NULL; 1127 - struct ovl_fs *ofs = OVL_FS(old->d_sb); 1128 - LIST_HEAD(list); 1126 + int err; 1129 1127 1130 - err = -EINVAL; 1131 - if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE)) 1132 - goto out; 1128 + if (ovlrd->flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE)) 1129 + return -EINVAL; 1133 1130 1134 - flags &= ~RENAME_NOREPLACE; 1131 + ovlrd->flags &= ~RENAME_NOREPLACE; 1135 1132 1136 1133 /* Don't copy up directory trees */ 1137 1134 err = -EXDEV; 1138 1135 if (!ovl_can_move(old)) 1139 - goto out; 1140 - if (!overwrite && !ovl_can_move(new)) 1141 - goto out; 1136 + return err; 1137 + if (!ovlrd->overwrite && !ovl_can_move(new)) 1138 + return err; 1142 1139 1143 - if (overwrite && new_is_dir && !ovl_pure_upper(new)) { 1144 - err = ovl_check_empty_dir(new, &list); 1140 + if (ovlrd->overwrite && new_is_dir && !ovl_pure_upper(new)) { 1141 + err = ovl_check_empty_dir(new, list); 1145 1142 if (err) 1146 - goto out; 1143 + return err; 1147 1144 } 1148 1145 1149 - if (overwrite) { 1146 + if (ovlrd->overwrite) { 1150 1147 if (ovl_lower_positive(old)) { 1151 1148 if (!ovl_dentry_is_whiteout(new)) { 1152 1149 /* Whiteout source */ 1153 - flags |= RENAME_WHITEOUT; 1150 + ovlrd->flags |= RENAME_WHITEOUT; 1154 1151 } else { 1155 1152 /* Switch whiteouts */ 1156 - flags |= RENAME_EXCHANGE; 1153 + ovlrd->flags |= RENAME_EXCHANGE; 1157 1154 } 1158 1155 } else if (is_dir && ovl_dentry_is_whiteout(new)) { 1159 - flags |= RENAME_EXCHANGE; 1160 - cleanup_whiteout = true; 1156 + ovlrd->flags |= RENAME_EXCHANGE; 1157 + ovlrd->cleanup_whiteout = true; 1161 1158 } 1162 1159 } 1163 1160 1164 1161 err = ovl_copy_up(old); 1165 1162 if (err) 1166 - goto out; 1163 + return err; 1167 1164 1168 1165 err = ovl_copy_up(new->d_parent); 1169 1166 if (err) 1170 - goto out; 1171 - if (!overwrite) { 1167 + return err; 1168 + 1169 + if (!ovlrd->overwrite) { 1172 1170 err = ovl_copy_up(new); 1173 1171 if (err) 1174 - goto out; 1172 + return err; 1175 1173 } else if (d_inode(new)) { 1176 1174 err = ovl_nlink_start(new); 1177 1175 if (err) 1178 - goto out; 1176 + return err; 1179 1177 1180 - update_nlink = true; 1178 + ovlrd->update_nlink = true; 1181 1179 } 1182 1180 1183 - if (!update_nlink) { 1181 + if (!ovlrd->update_nlink) { 1184 1182 /* ovl_nlink_start() took ovl_want_write() */ 1185 1183 err = ovl_want_write(old); 1186 1184 if (err) 1187 - goto out; 1185 + return err; 1188 1186 } 1189 1187 1190 - old_cred = ovl_override_creds(old->d_sb); 1188 + return 0; 1189 + } 1191 1190 1192 - if (!list_empty(&list)) { 1193 - opaquedir = ovl_clear_empty(new, &list); 1194 - err = PTR_ERR(opaquedir); 1195 - if (IS_ERR(opaquedir)) { 1196 - opaquedir = NULL; 1197 - goto out_revert_creds; 1198 - } 1191 + static int ovl_rename_upper(struct ovl_renamedata *ovlrd, struct list_head *list) 1192 + { 1193 + struct dentry *old = ovlrd->old_dentry; 1194 + struct dentry *new = ovlrd->new_dentry; 1195 + struct ovl_fs *ofs = OVL_FS(old->d_sb); 1196 + struct dentry *old_upperdir = ovl_dentry_upper(old->d_parent); 1197 + struct dentry *new_upperdir = ovl_dentry_upper(new->d_parent); 1198 + bool is_dir = d_is_dir(old); 1199 + bool new_is_dir = d_is_dir(new); 1200 + bool samedir = old->d_parent == new->d_parent; 1201 + struct renamedata rd = {}; 1202 + struct dentry *de; 1203 + struct dentry *whiteout = NULL; 1204 + bool old_opaque, new_opaque; 1205 + int err; 1206 + 1207 + if (!list_empty(list)) { 1208 + de = ovl_clear_empty(new, list); 1209 + if (IS_ERR(de)) 1210 + return PTR_ERR(de); 1211 + ovlrd->opaquedir = de; 1199 1212 } 1200 - 1201 - old_upperdir = ovl_dentry_upper(old->d_parent); 1202 - new_upperdir = ovl_dentry_upper(new->d_parent); 1203 1213 1204 1214 if (!samedir) { 1205 1215 /* ··· 1217 1215 if (ovl_type_origin(old)) { 1218 1216 err = ovl_set_impure(new->d_parent, new_upperdir); 1219 1217 if (err) 1220 - goto out_revert_creds; 1218 + return err; 1221 1219 } 1222 - if (!overwrite && ovl_type_origin(new)) { 1220 + if (!ovlrd->overwrite && ovl_type_origin(new)) { 1223 1221 err = ovl_set_impure(old->d_parent, old_upperdir); 1224 1222 if (err) 1225 - goto out_revert_creds; 1223 + return err; 1226 1224 } 1227 1225 } 1228 1226 1229 1227 rd.mnt_idmap = ovl_upper_mnt_idmap(ofs); 1230 1228 rd.old_parent = old_upperdir; 1231 1229 rd.new_parent = new_upperdir; 1232 - rd.flags = flags; 1230 + rd.flags = ovlrd->flags; 1233 1231 1234 1232 err = start_renaming(&rd, 0, 1235 1233 &QSTR_LEN(old->d_name.name, old->d_name.len), 1236 1234 &QSTR_LEN(new->d_name.name, new->d_name.len)); 1237 - 1238 1235 if (err) 1239 - goto out_revert_creds; 1236 + return err; 1240 1237 1241 1238 err = -ESTALE; 1242 1239 if (!ovl_matches_upper(old, rd.old_dentry)) ··· 1246 1245 1247 1246 err = -ESTALE; 1248 1247 if (d_inode(new) && ovl_dentry_upper(new)) { 1249 - if (opaquedir) { 1250 - if (rd.new_dentry != opaquedir) 1248 + if (ovlrd->opaquedir) { 1249 + if (rd.new_dentry != ovlrd->opaquedir) 1251 1250 goto out_unlock; 1252 1251 } else { 1253 1252 if (!ovl_matches_upper(new, rd.new_dentry)) ··· 1258 1257 if (!new_opaque || !ovl_upper_is_whiteout(ofs, rd.new_dentry)) 1259 1258 goto out_unlock; 1260 1259 } else { 1261 - if (flags & RENAME_EXCHANGE) 1260 + if (ovlrd->flags & RENAME_EXCHANGE) 1262 1261 goto out_unlock; 1263 1262 } 1264 1263 } ··· 1274 1273 if (err) 1275 1274 goto out_unlock; 1276 1275 1277 - if (!overwrite && ovl_type_merge_or_lower(new)) 1276 + if (!ovlrd->overwrite && ovl_type_merge_or_lower(new)) 1278 1277 err = ovl_set_redirect(new, samedir); 1279 - else if (!overwrite && new_is_dir && !new_opaque && 1278 + else if (!ovlrd->overwrite && new_is_dir && !new_opaque && 1280 1279 ovl_type_merge(old->d_parent)) 1281 1280 err = ovl_set_opaque_xerr(new, rd.new_dentry, -EXDEV); 1282 1281 if (err) ··· 1284 1283 1285 1284 err = ovl_do_rename_rd(&rd); 1286 1285 1287 - if (!err && cleanup_whiteout) 1286 + if (!err && ovlrd->cleanup_whiteout) 1288 1287 whiteout = dget(rd.new_dentry); 1289 1288 1289 + out_unlock: 1290 1290 end_renaming(&rd); 1291 1291 1292 1292 if (err) 1293 - goto out_revert_creds; 1293 + return err; 1294 1294 1295 1295 if (whiteout) { 1296 1296 ovl_cleanup(ofs, old_upperdir, whiteout); 1297 1297 dput(whiteout); 1298 1298 } 1299 1299 1300 - if (overwrite && d_inode(new)) { 1300 + if (ovlrd->overwrite && d_inode(new)) { 1301 1301 if (new_is_dir) 1302 1302 clear_nlink(d_inode(new)); 1303 1303 else ··· 1306 1304 } 1307 1305 1308 1306 ovl_dir_modified(old->d_parent, ovl_type_origin(old) || 1309 - (!overwrite && ovl_type_origin(new))); 1307 + (!ovlrd->overwrite && ovl_type_origin(new))); 1310 1308 ovl_dir_modified(new->d_parent, ovl_type_origin(old) || 1311 1309 (d_inode(new) && ovl_type_origin(new))); 1312 1310 ··· 1315 1313 if (d_inode(new) && ovl_dentry_upper(new)) 1316 1314 ovl_copyattr(d_inode(new)); 1317 1315 1318 - out_revert_creds: 1319 - ovl_revert_creds(old_cred); 1320 - if (update_nlink) 1321 - ovl_nlink_end(new); 1316 + return err; 1317 + } 1318 + 1319 + static void ovl_rename_end(struct ovl_renamedata *ovlrd) 1320 + { 1321 + if (ovlrd->update_nlink) 1322 + ovl_nlink_end(ovlrd->new_dentry); 1322 1323 else 1323 - ovl_drop_write(old); 1324 - out: 1325 - dput(opaquedir); 1324 + ovl_drop_write(ovlrd->old_dentry); 1325 + } 1326 + 1327 + static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir, 1328 + struct dentry *old, struct inode *newdir, 1329 + struct dentry *new, unsigned int flags) 1330 + { 1331 + struct ovl_renamedata ovlrd = { 1332 + .old_parent = old->d_parent, 1333 + .old_dentry = old, 1334 + .new_parent = new->d_parent, 1335 + .new_dentry = new, 1336 + .flags = flags, 1337 + .overwrite = !(flags & RENAME_EXCHANGE), 1338 + }; 1339 + LIST_HEAD(list); 1340 + int err; 1341 + 1342 + err = ovl_rename_start(&ovlrd, &list); 1343 + if (!err) { 1344 + with_ovl_creds(old->d_sb) 1345 + err = ovl_rename_upper(&ovlrd, &list); 1346 + ovl_rename_end(&ovlrd); 1347 + } 1348 + 1349 + dput(ovlrd.opaquedir); 1326 1350 ovl_cache_free(&list); 1327 1351 return err; 1328 - 1329 - out_unlock: 1330 - end_renaming(&rd); 1331 - goto out_revert_creds; 1332 1352 } 1333 1353 1334 1354 static int ovl_create_tmpfile(struct file *file, struct dentry *dentry, 1335 1355 struct inode *inode, umode_t mode) 1336 1356 { 1337 - const struct cred *old_cred, *new_cred = NULL; 1338 1357 struct path realparentpath; 1339 1358 struct file *realfile; 1340 1359 struct ovl_file *of; ··· 1364 1341 int flags = file->f_flags | OVL_OPEN_FLAGS; 1365 1342 int err; 1366 1343 1367 - old_cred = ovl_override_creds(dentry->d_sb); 1368 - new_cred = ovl_setup_cred_for_create(dentry, inode, mode, old_cred); 1369 - err = PTR_ERR(new_cred); 1370 - if (IS_ERR(new_cred)) { 1371 - new_cred = NULL; 1372 - goto out_revert_creds; 1373 - } 1344 + with_ovl_creds(dentry->d_sb) { 1345 + scoped_class(ovl_override_creator_creds, cred, dentry, inode, mode) { 1346 + if (IS_ERR(cred)) 1347 + return PTR_ERR(cred); 1374 1348 1375 - ovl_path_upper(dentry->d_parent, &realparentpath); 1376 - realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath, 1377 - mode, current_cred()); 1378 - err = PTR_ERR_OR_ZERO(realfile); 1379 - pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err); 1380 - if (err) 1381 - goto out_revert_creds; 1349 + ovl_path_upper(dentry->d_parent, &realparentpath); 1350 + realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath, 1351 + mode, current_cred()); 1352 + err = PTR_ERR_OR_ZERO(realfile); 1353 + pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err); 1354 + if (err) 1355 + return err; 1382 1356 1383 - of = ovl_file_alloc(realfile); 1384 - if (!of) { 1385 - fput(realfile); 1386 - err = -ENOMEM; 1387 - goto out_revert_creds; 1388 - } 1357 + of = ovl_file_alloc(realfile); 1358 + if (!of) { 1359 + fput(realfile); 1360 + return -ENOMEM; 1361 + } 1389 1362 1390 - /* ovl_instantiate() consumes the newdentry reference on success */ 1391 - newdentry = dget(realfile->f_path.dentry); 1392 - err = ovl_instantiate(dentry, inode, newdentry, false, file); 1393 - if (!err) { 1394 - file->private_data = of; 1395 - } else { 1396 - dput(newdentry); 1397 - ovl_file_free(of); 1363 + /* ovl_instantiate() consumes the newdentry reference on success */ 1364 + newdentry = dget(realfile->f_path.dentry); 1365 + err = ovl_instantiate(dentry, inode, newdentry, false, file); 1366 + if (!err) { 1367 + file->private_data = of; 1368 + } else { 1369 + dput(newdentry); 1370 + ovl_file_free(of); 1371 + } 1372 + } 1398 1373 } 1399 - out_revert_creds: 1400 - ovl_revert_creds(old_cred); 1401 - put_cred(new_cred); 1402 1374 return err; 1403 1375 } 1404 1376
+37 -54
fs/overlayfs/file.c
··· 31 31 struct inode *inode = file_inode(file); 32 32 struct mnt_idmap *real_idmap; 33 33 struct file *realfile; 34 - const struct cred *old_cred; 35 34 int flags = file->f_flags | OVL_OPEN_FLAGS; 36 35 int acc_mode = ACC_MODE(flags); 37 36 int err; ··· 38 39 if (flags & O_APPEND) 39 40 acc_mode |= MAY_APPEND; 40 41 41 - old_cred = ovl_override_creds(inode->i_sb); 42 - real_idmap = mnt_idmap(realpath->mnt); 43 - err = inode_permission(real_idmap, realinode, MAY_OPEN | acc_mode); 44 - if (err) { 45 - realfile = ERR_PTR(err); 46 - } else { 47 - if (!inode_owner_or_capable(real_idmap, realinode)) 48 - flags &= ~O_NOATIME; 42 + with_ovl_creds(inode->i_sb) { 43 + real_idmap = mnt_idmap(realpath->mnt); 44 + err = inode_permission(real_idmap, realinode, MAY_OPEN | acc_mode); 45 + if (err) { 46 + realfile = ERR_PTR(err); 47 + } else { 48 + if (!inode_owner_or_capable(real_idmap, realinode)) 49 + flags &= ~O_NOATIME; 49 50 50 - realfile = backing_file_open(file_user_path(file), 51 - flags, realpath, current_cred()); 51 + realfile = backing_file_open(file_user_path(file), 52 + flags, realpath, current_cred()); 53 + } 52 54 } 53 - ovl_revert_creds(old_cred); 54 55 55 56 pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n", 56 57 file, file, ovl_whatisit(inode, realinode), file->f_flags, ··· 243 244 { 244 245 struct inode *inode = file_inode(file); 245 246 struct file *realfile; 246 - const struct cred *old_cred; 247 247 loff_t ret; 248 248 249 249 /* ··· 271 273 ovl_inode_lock(inode); 272 274 realfile->f_pos = file->f_pos; 273 275 274 - old_cred = ovl_override_creds(inode->i_sb); 275 - ret = vfs_llseek(realfile, offset, whence); 276 - ovl_revert_creds(old_cred); 276 + with_ovl_creds(inode->i_sb) 277 + ret = vfs_llseek(realfile, offset, whence); 277 278 278 279 file->f_pos = realfile->f_pos; 279 280 ovl_inode_unlock(inode); ··· 444 447 enum ovl_path_type type; 445 448 struct path upperpath; 446 449 struct file *upperfile; 447 - const struct cred *old_cred; 448 450 int ret; 449 451 450 452 ret = ovl_sync_status(OVL_FS(file_inode(file)->i_sb)); ··· 460 464 if (IS_ERR(upperfile)) 461 465 return PTR_ERR(upperfile); 462 466 463 - old_cred = ovl_override_creds(file_inode(file)->i_sb); 464 - ret = vfs_fsync_range(upperfile, start, end, datasync); 465 - ovl_revert_creds(old_cred); 466 - 467 - return ret; 467 + with_ovl_creds(file_inode(file)->i_sb) 468 + return vfs_fsync_range(upperfile, start, end, datasync); 468 469 } 469 470 470 471 static int ovl_mmap(struct file *file, struct vm_area_struct *vma) ··· 479 486 { 480 487 struct inode *inode = file_inode(file); 481 488 struct file *realfile; 482 - const struct cred *old_cred; 483 489 int ret; 484 490 485 491 inode_lock(inode); ··· 493 501 if (IS_ERR(realfile)) 494 502 goto out_unlock; 495 503 496 - old_cred = ovl_override_creds(file_inode(file)->i_sb); 497 - ret = vfs_fallocate(realfile, mode, offset, len); 498 - ovl_revert_creds(old_cred); 504 + with_ovl_creds(inode->i_sb) 505 + ret = vfs_fallocate(realfile, mode, offset, len); 499 506 500 507 /* Update size */ 501 508 ovl_file_modified(file); ··· 508 517 static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice) 509 518 { 510 519 struct file *realfile; 511 - const struct cred *old_cred; 512 - int ret; 513 520 514 521 realfile = ovl_real_file(file); 515 522 if (IS_ERR(realfile)) 516 523 return PTR_ERR(realfile); 517 524 518 - old_cred = ovl_override_creds(file_inode(file)->i_sb); 519 - ret = vfs_fadvise(realfile, offset, len, advice); 520 - ovl_revert_creds(old_cred); 521 - 522 - return ret; 525 + with_ovl_creds(file_inode(file)->i_sb) 526 + return vfs_fadvise(realfile, offset, len, advice); 523 527 } 524 528 525 529 enum ovl_copyop { ··· 529 543 { 530 544 struct inode *inode_out = file_inode(file_out); 531 545 struct file *realfile_in, *realfile_out; 532 - const struct cred *old_cred; 533 546 loff_t ret; 534 547 535 548 inode_lock(inode_out); ··· 550 565 if (IS_ERR(realfile_in)) 551 566 goto out_unlock; 552 567 553 - old_cred = ovl_override_creds(file_inode(file_out)->i_sb); 554 - switch (op) { 555 - case OVL_COPY: 556 - ret = vfs_copy_file_range(realfile_in, pos_in, 557 - realfile_out, pos_out, len, flags); 558 - break; 568 + with_ovl_creds(file_inode(file_out)->i_sb) { 569 + switch (op) { 570 + case OVL_COPY: 571 + ret = vfs_copy_file_range(realfile_in, pos_in, 572 + realfile_out, pos_out, len, flags); 573 + break; 559 574 560 - case OVL_CLONE: 561 - ret = vfs_clone_file_range(realfile_in, pos_in, 562 - realfile_out, pos_out, len, flags); 563 - break; 575 + case OVL_CLONE: 576 + ret = vfs_clone_file_range(realfile_in, pos_in, 577 + realfile_out, pos_out, len, flags); 578 + break; 564 579 565 - case OVL_DEDUPE: 566 - ret = vfs_dedupe_file_range_one(realfile_in, pos_in, 567 - realfile_out, pos_out, len, 568 - flags); 569 - break; 580 + case OVL_DEDUPE: 581 + ret = vfs_dedupe_file_range_one(realfile_in, pos_in, 582 + realfile_out, pos_out, len, 583 + flags); 584 + break; 585 + } 570 586 } 571 - ovl_revert_creds(old_cred); 572 587 573 588 /* Update size */ 574 589 ovl_file_modified(file_out); ··· 617 632 static int ovl_flush(struct file *file, fl_owner_t id) 618 633 { 619 634 struct file *realfile; 620 - const struct cred *old_cred; 621 635 int err = 0; 622 636 623 637 realfile = ovl_real_file(file); ··· 624 640 return PTR_ERR(realfile); 625 641 626 642 if (realfile->f_op->flush) { 627 - old_cred = ovl_override_creds(file_inode(file)->i_sb); 628 - err = realfile->f_op->flush(realfile, id); 629 - ovl_revert_creds(old_cred); 643 + with_ovl_creds(file_inode(file)->i_sb) 644 + err = realfile->f_op->flush(realfile, id); 630 645 } 631 646 632 647 return err;
+49 -69
fs/overlayfs/inode.c
··· 25 25 struct ovl_fs *ofs = OVL_FS(dentry->d_sb); 26 26 bool full_copy_up = false; 27 27 struct dentry *upperdentry; 28 - const struct cred *old_cred; 29 28 30 29 err = setattr_prepare(&nop_mnt_idmap, dentry, attr); 31 30 if (err) ··· 77 78 goto out_put_write; 78 79 79 80 inode_lock(upperdentry->d_inode); 80 - old_cred = ovl_override_creds(dentry->d_sb); 81 - err = ovl_do_notify_change(ofs, upperdentry, attr); 82 - ovl_revert_creds(old_cred); 81 + with_ovl_creds(dentry->d_sb) 82 + err = ovl_do_notify_change(ofs, upperdentry, attr); 83 83 if (!err) 84 84 ovl_copyattr(dentry->d_inode); 85 85 inode_unlock(upperdentry->d_inode); ··· 151 153 } 152 154 } 153 155 156 + static inline int ovl_real_getattr_nosec(struct super_block *sb, 157 + const struct path *path, 158 + struct kstat *stat, u32 request_mask, 159 + unsigned int flags) 160 + { 161 + with_ovl_creds(sb) 162 + return vfs_getattr_nosec(path, stat, request_mask, flags); 163 + } 164 + 154 165 int ovl_getattr(struct mnt_idmap *idmap, const struct path *path, 155 166 struct kstat *stat, u32 request_mask, unsigned int flags) 156 167 { 157 168 struct dentry *dentry = path->dentry; 169 + struct super_block *sb = dentry->d_sb; 158 170 enum ovl_path_type type; 159 171 struct path realpath; 160 - const struct cred *old_cred; 161 172 struct inode *inode = d_inode(dentry); 162 173 bool is_dir = S_ISDIR(inode->i_mode); 163 174 int fsid = 0; ··· 176 169 metacopy_blocks = ovl_is_metacopy_dentry(dentry); 177 170 178 171 type = ovl_path_real(dentry, &realpath); 179 - old_cred = ovl_override_creds(dentry->d_sb); 180 - err = vfs_getattr_nosec(&realpath, stat, request_mask, flags); 172 + err = ovl_real_getattr_nosec(sb, &realpath, stat, request_mask, flags); 181 173 if (err) 182 - goto out; 174 + return err; 183 175 184 176 /* Report the effective immutable/append-only STATX flags */ 185 177 generic_fill_statx_attr(inode, stat); ··· 201 195 (!is_dir ? STATX_NLINK : 0); 202 196 203 197 ovl_path_lower(dentry, &realpath); 204 - err = vfs_getattr_nosec(&realpath, &lowerstat, lowermask, 205 - flags); 198 + err = ovl_real_getattr_nosec(sb, &realpath, &lowerstat, lowermask, flags); 206 199 if (err) 207 - goto out; 200 + return err; 208 201 209 202 /* 210 203 * Lower hardlinks may be broken on copy up to different ··· 253 248 254 249 ovl_path_lowerdata(dentry, &realpath); 255 250 if (realpath.dentry) { 256 - err = vfs_getattr_nosec(&realpath, &lowerdatastat, 257 - lowermask, flags); 251 + err = ovl_real_getattr_nosec(sb, &realpath, &lowerdatastat, 252 + lowermask, flags); 258 253 if (err) 259 - goto out; 254 + return err; 260 255 } else { 261 256 lowerdatastat.blocks = 262 257 round_up(stat->size, stat->blksize) >> 9; ··· 284 279 if (!is_dir && ovl_test_flag(OVL_INDEX, d_inode(dentry))) 285 280 stat->nlink = dentry->d_inode->i_nlink; 286 281 287 - out: 288 - ovl_revert_creds(old_cred); 289 - 290 282 return err; 291 283 } 292 284 ··· 293 291 struct inode *upperinode = ovl_inode_upper(inode); 294 292 struct inode *realinode; 295 293 struct path realpath; 296 - const struct cred *old_cred; 297 294 int err; 298 295 299 296 /* Careful in RCU walk mode */ ··· 310 309 if (err) 311 310 return err; 312 311 313 - old_cred = ovl_override_creds(inode->i_sb); 314 312 if (!upperinode && 315 313 !special_file(realinode->i_mode) && mask & MAY_WRITE) { 316 314 mask &= ~(MAY_WRITE | MAY_APPEND); 317 315 /* Make sure mounter can read file for copy up later */ 318 316 mask |= MAY_READ; 319 317 } 320 - err = inode_permission(mnt_idmap(realpath.mnt), realinode, mask); 321 - ovl_revert_creds(old_cred); 322 318 323 - return err; 319 + with_ovl_creds(inode->i_sb) 320 + return inode_permission(mnt_idmap(realpath.mnt), realinode, mask); 324 321 } 325 322 326 323 static const char *ovl_get_link(struct dentry *dentry, 327 324 struct inode *inode, 328 325 struct delayed_call *done) 329 326 { 330 - const struct cred *old_cred; 331 - const char *p; 332 - 333 327 if (!dentry) 334 328 return ERR_PTR(-ECHILD); 335 329 336 - old_cred = ovl_override_creds(dentry->d_sb); 337 - p = vfs_get_link(ovl_dentry_real(dentry), done); 338 - ovl_revert_creds(old_cred); 339 - return p; 330 + with_ovl_creds(dentry->d_sb) 331 + return vfs_get_link(ovl_dentry_real(dentry), done); 340 332 } 341 333 342 334 #ifdef CONFIG_FS_POSIX_ACL ··· 459 465 460 466 acl = get_cached_acl_rcu(realinode, type); 461 467 } else { 462 - const struct cred *old_cred; 463 - 464 - old_cred = ovl_override_creds(inode->i_sb); 465 - acl = ovl_get_acl_path(&realpath, posix_acl_xattr_name(type), noperm); 466 - ovl_revert_creds(old_cred); 468 + with_ovl_creds(inode->i_sb) 469 + acl = ovl_get_acl_path(&realpath, posix_acl_xattr_name(type), noperm); 467 470 } 468 471 469 472 return acl; ··· 472 481 int err; 473 482 struct path realpath; 474 483 const char *acl_name; 475 - const struct cred *old_cred; 476 484 struct ovl_fs *ofs = OVL_FS(dentry->d_sb); 477 485 struct dentry *upperdentry = ovl_dentry_upper(dentry); 478 486 struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry); ··· 485 495 struct posix_acl *real_acl; 486 496 487 497 ovl_path_lower(dentry, &realpath); 488 - old_cred = ovl_override_creds(dentry->d_sb); 489 - real_acl = vfs_get_acl(mnt_idmap(realpath.mnt), realdentry, 490 - acl_name); 491 - ovl_revert_creds(old_cred); 498 + with_ovl_creds(dentry->d_sb) 499 + real_acl = vfs_get_acl(mnt_idmap(realpath.mnt), realdentry, acl_name); 492 500 if (IS_ERR(real_acl)) { 493 501 err = PTR_ERR(real_acl); 494 502 goto out; ··· 506 518 if (err) 507 519 goto out; 508 520 509 - old_cred = ovl_override_creds(dentry->d_sb); 510 - if (acl) 511 - err = ovl_do_set_acl(ofs, realdentry, acl_name, acl); 512 - else 513 - err = ovl_do_remove_acl(ofs, realdentry, acl_name); 514 - ovl_revert_creds(old_cred); 521 + with_ovl_creds(dentry->d_sb) { 522 + if (acl) 523 + err = ovl_do_set_acl(ofs, realdentry, acl_name, acl); 524 + else 525 + err = ovl_do_remove_acl(ofs, realdentry, acl_name); 526 + } 515 527 ovl_drop_write(dentry); 516 528 517 529 /* copy c/mtime */ ··· 576 588 static int ovl_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 577 589 u64 start, u64 len) 578 590 { 579 - int err; 580 591 struct inode *realinode = ovl_inode_realdata(inode); 581 - const struct cred *old_cred; 582 592 583 593 if (!realinode) 584 594 return -EIO; ··· 584 598 if (!realinode->i_op->fiemap) 585 599 return -EOPNOTSUPP; 586 600 587 - old_cred = ovl_override_creds(inode->i_sb); 588 - err = realinode->i_op->fiemap(realinode, fieinfo, start, len); 589 - ovl_revert_creds(old_cred); 590 - 591 - return err; 601 + with_ovl_creds(inode->i_sb) 602 + return realinode->i_op->fiemap(realinode, fieinfo, start, len); 592 603 } 593 604 594 605 /* ··· 636 653 { 637 654 struct inode *inode = d_inode(dentry); 638 655 struct path upperpath; 639 - const struct cred *old_cred; 640 656 unsigned int flags; 641 657 int err; 642 658 ··· 647 665 if (err) 648 666 goto out; 649 667 650 - old_cred = ovl_override_creds(inode->i_sb); 651 - /* 652 - * Store immutable/append-only flags in xattr and clear them 653 - * in upper fileattr (in case they were set by older kernel) 654 - * so children of "ovl-immutable" directories lower aliases of 655 - * "ovl-immutable" hardlinks could be copied up. 656 - * Clear xattr when flags are cleared. 657 - */ 658 - err = ovl_set_protattr(inode, upperpath.dentry, fa); 659 - if (!err) 660 - err = ovl_real_fileattr_set(&upperpath, fa); 661 - ovl_revert_creds(old_cred); 668 + with_ovl_creds(inode->i_sb) { 669 + /* 670 + * Store immutable/append-only flags in xattr and clear them 671 + * in upper fileattr (in case they were set by older kernel) 672 + * so children of "ovl-immutable" directories lower aliases of 673 + * "ovl-immutable" hardlinks could be copied up. 674 + * Clear xattr when flags are cleared. 675 + */ 676 + err = ovl_set_protattr(inode, upperpath.dentry, fa); 677 + if (!err) 678 + err = ovl_real_fileattr_set(&upperpath, fa); 679 + } 662 680 ovl_drop_write(dentry); 663 681 664 682 /* ··· 712 730 { 713 731 struct inode *inode = d_inode(dentry); 714 732 struct path realpath; 715 - const struct cred *old_cred; 716 733 int err; 717 734 718 735 ovl_path_real(dentry, &realpath); 719 736 720 - old_cred = ovl_override_creds(inode->i_sb); 721 - err = ovl_real_fileattr_get(&realpath, fa); 737 + with_ovl_creds(inode->i_sb) 738 + err = ovl_real_fileattr_get(&realpath, fa); 722 739 ovl_fileattr_prot_flags(inode, fa); 723 - ovl_revert_creds(old_cred); 724 740 725 741 return err; 726 742 }
+198 -202
fs/overlayfs/namei.c
··· 979 979 return err; 980 980 981 981 if (!ovl_test_flag(OVL_VERIFIED_DIGEST, inode)) { 982 - const struct cred *old_cred; 983 - 984 - old_cred = ovl_override_creds(dentry->d_sb); 985 - 986 - err = ovl_validate_verity(ofs, &metapath, &datapath); 982 + with_ovl_creds(dentry->d_sb) 983 + err = ovl_validate_verity(ofs, &metapath, &datapath); 987 984 if (err == 0) 988 985 ovl_set_flag(OVL_VERIFIED_DIGEST, inode); 989 - 990 - ovl_revert_creds(old_cred); 991 986 } 992 987 993 988 ovl_inode_unlock(inode); ··· 996 1001 struct inode *inode = d_inode(dentry); 997 1002 const char *redirect = ovl_lowerdata_redirect(inode); 998 1003 struct ovl_path datapath = {}; 999 - const struct cred *old_cred; 1000 1004 int err; 1001 1005 1002 1006 if (!redirect || ovl_dentry_lowerdata(dentry)) ··· 1013 1019 if (ovl_dentry_lowerdata(dentry)) 1014 1020 goto out; 1015 1021 1016 - old_cred = ovl_override_creds(dentry->d_sb); 1017 - err = ovl_lookup_data_layers(dentry, redirect, &datapath); 1018 - ovl_revert_creds(old_cred); 1022 + with_ovl_creds(dentry->d_sb) 1023 + err = ovl_lookup_data_layers(dentry, redirect, &datapath); 1019 1024 if (err) 1020 1025 goto out_err; 1021 1026 ··· 1070 1077 return true; 1071 1078 } 1072 1079 1073 - struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, 1074 - unsigned int flags) 1080 + struct ovl_lookup_ctx { 1081 + struct dentry *dentry; 1082 + struct ovl_entry *oe; 1083 + struct ovl_path *stack; 1084 + struct ovl_path *origin_path; 1085 + struct dentry *upperdentry; 1086 + struct dentry *index; 1087 + struct inode *inode; 1088 + unsigned int ctr; 1089 + }; 1090 + 1091 + static int ovl_lookup_layers(struct ovl_lookup_ctx *ctx, struct ovl_lookup_data *d) 1075 1092 { 1076 - struct ovl_entry *oe = NULL; 1077 - const struct cred *old_cred; 1093 + struct dentry *dentry = ctx->dentry; 1078 1094 struct ovl_fs *ofs = OVL_FS(dentry->d_sb); 1079 1095 struct ovl_entry *poe = OVL_E(dentry->d_parent); 1080 1096 struct ovl_entry *roe = OVL_E(dentry->d_sb->s_root); 1081 - struct ovl_path *stack = NULL, *origin_path = NULL; 1082 - struct dentry *upperdir, *upperdentry = NULL; 1083 - struct dentry *origin = NULL; 1084 - struct dentry *index = NULL; 1085 - unsigned int ctr = 0; 1086 - struct inode *inode = NULL; 1087 - bool upperopaque = false; 1088 1097 bool check_redirect = (ovl_redirect_follow(ofs) || ofs->numdatalayer); 1098 + struct dentry *upperdir; 1089 1099 struct dentry *this; 1090 - unsigned int i; 1091 - int err; 1100 + struct dentry *origin = NULL; 1101 + bool upperopaque = false; 1092 1102 bool uppermetacopy = false; 1093 1103 int metacopy_size = 0; 1094 - struct ovl_lookup_data d = { 1095 - .sb = dentry->d_sb, 1096 - .dentry = dentry, 1097 - .name = dentry->d_name, 1098 - .is_dir = false, 1099 - .opaque = false, 1100 - .stop = false, 1101 - .last = check_redirect ? false : !ovl_numlower(poe), 1102 - .redirect = NULL, 1103 - .upperredirect = NULL, 1104 - .metacopy = 0, 1105 - }; 1104 + unsigned int i; 1105 + int err; 1106 1106 1107 - if (dentry->d_name.len > ofs->namelen) 1108 - return ERR_PTR(-ENAMETOOLONG); 1109 - 1110 - old_cred = ovl_override_creds(dentry->d_sb); 1111 1107 upperdir = ovl_dentry_upper(dentry->d_parent); 1112 1108 if (upperdir) { 1113 - d.layer = &ofs->layers[0]; 1114 - err = ovl_lookup_layer(upperdir, &d, &upperdentry, true); 1109 + d->layer = &ofs->layers[0]; 1110 + err = ovl_lookup_layer(upperdir, d, &ctx->upperdentry, true); 1115 1111 if (err) 1116 - goto out; 1112 + return err; 1117 1113 1118 - if (upperdentry && upperdentry->d_flags & DCACHE_OP_REAL) { 1119 - dput(upperdentry); 1120 - err = -EREMOTE; 1121 - goto out; 1122 - } 1123 - if (upperdentry && !d.is_dir) { 1114 + if (ctx->upperdentry && ctx->upperdentry->d_flags & DCACHE_OP_REAL) 1115 + return -EREMOTE; 1116 + 1117 + if (ctx->upperdentry && !d->is_dir) { 1124 1118 /* 1125 1119 * Lookup copy up origin by decoding origin file handle. 1126 1120 * We may get a disconnected dentry, which is fine, ··· 1118 1138 * number - it's the same as if we held a reference 1119 1139 * to a dentry in lower layer that was moved under us. 1120 1140 */ 1121 - err = ovl_check_origin(ofs, upperdentry, &origin_path); 1141 + err = ovl_check_origin(ofs, ctx->upperdentry, &ctx->origin_path); 1122 1142 if (err) 1123 - goto out_put_upper; 1143 + return err; 1124 1144 1125 - if (d.metacopy) 1145 + if (d->metacopy) 1126 1146 uppermetacopy = true; 1127 - metacopy_size = d.metacopy; 1147 + metacopy_size = d->metacopy; 1128 1148 } 1129 1149 1130 - if (d.redirect) { 1150 + if (d->redirect) { 1131 1151 err = -ENOMEM; 1132 - d.upperredirect = kstrdup(d.redirect, GFP_KERNEL); 1133 - if (!d.upperredirect) 1134 - goto out_put_upper; 1135 - if (d.redirect[0] == '/') 1152 + d->upperredirect = kstrdup(d->redirect, GFP_KERNEL); 1153 + if (!d->upperredirect) 1154 + return err; 1155 + if (d->redirect[0] == '/') 1136 1156 poe = roe; 1137 1157 } 1138 - upperopaque = d.opaque; 1158 + upperopaque = d->opaque; 1139 1159 } 1140 1160 1141 - if (!d.stop && ovl_numlower(poe)) { 1161 + if (!d->stop && ovl_numlower(poe)) { 1142 1162 err = -ENOMEM; 1143 - stack = ovl_stack_alloc(ofs->numlayer - 1); 1144 - if (!stack) 1145 - goto out_put_upper; 1163 + ctx->stack = ovl_stack_alloc(ofs->numlayer - 1); 1164 + if (!ctx->stack) 1165 + return err; 1146 1166 } 1147 1167 1148 - for (i = 0; !d.stop && i < ovl_numlower(poe); i++) { 1168 + for (i = 0; !d->stop && i < ovl_numlower(poe); i++) { 1149 1169 struct ovl_path lower = ovl_lowerstack(poe)[i]; 1150 1170 1151 - if (!ovl_check_follow_redirect(&d)) { 1171 + if (!ovl_check_follow_redirect(d)) { 1152 1172 err = -EPERM; 1153 - goto out_put; 1173 + return err; 1154 1174 } 1155 1175 1156 1176 if (!check_redirect) 1157 - d.last = i == ovl_numlower(poe) - 1; 1158 - else if (d.is_dir || !ofs->numdatalayer) 1159 - d.last = lower.layer->idx == ovl_numlower(roe); 1177 + d->last = i == ovl_numlower(poe) - 1; 1178 + else if (d->is_dir || !ofs->numdatalayer) 1179 + d->last = lower.layer->idx == ovl_numlower(roe); 1160 1180 1161 - d.layer = lower.layer; 1162 - err = ovl_lookup_layer(lower.dentry, &d, &this, false); 1181 + d->layer = lower.layer; 1182 + err = ovl_lookup_layer(lower.dentry, d, &this, false); 1163 1183 if (err) 1164 - goto out_put; 1184 + return err; 1165 1185 1166 1186 if (!this) 1167 1187 continue; ··· 1170 1190 * If no origin fh is stored in upper of a merge dir, store fh 1171 1191 * of lower dir and set upper parent "impure". 1172 1192 */ 1173 - if (upperdentry && !ctr && !ofs->noxattr && d.is_dir) { 1174 - err = ovl_fix_origin(ofs, dentry, this, upperdentry); 1193 + if (ctx->upperdentry && !ctx->ctr && !ofs->noxattr && d->is_dir) { 1194 + err = ovl_fix_origin(ofs, dentry, this, ctx->upperdentry); 1175 1195 if (err) { 1176 1196 dput(this); 1177 - goto out_put; 1197 + return err; 1178 1198 } 1179 1199 } 1180 1200 ··· 1187 1207 * matches the dentry found using path based lookup, 1188 1208 * otherwise error out. 1189 1209 */ 1190 - if (upperdentry && !ctr && 1191 - ((d.is_dir && ovl_verify_lower(dentry->d_sb)) || 1192 - (!d.is_dir && ofs->config.index && origin_path))) { 1193 - err = ovl_verify_origin(ofs, upperdentry, this, false); 1210 + if (ctx->upperdentry && !ctx->ctr && 1211 + ((d->is_dir && ovl_verify_lower(dentry->d_sb)) || 1212 + (!d->is_dir && ofs->config.index && ctx->origin_path))) { 1213 + err = ovl_verify_origin(ofs, ctx->upperdentry, this, false); 1194 1214 if (err) { 1195 1215 dput(this); 1196 - if (d.is_dir) 1216 + if (d->is_dir) 1197 1217 break; 1198 - goto out_put; 1218 + return err; 1199 1219 } 1200 1220 origin = this; 1201 1221 } 1202 1222 1203 - if (!upperdentry && !d.is_dir && !ctr && d.metacopy) 1204 - metacopy_size = d.metacopy; 1223 + if (!ctx->upperdentry && !d->is_dir && !ctx->ctr && d->metacopy) 1224 + metacopy_size = d->metacopy; 1205 1225 1206 - if (d.metacopy && ctr) { 1226 + if (d->metacopy && ctx->ctr) { 1207 1227 /* 1208 1228 * Do not store intermediate metacopy dentries in 1209 1229 * lower chain, except top most lower metacopy dentry. ··· 1213 1233 dput(this); 1214 1234 this = NULL; 1215 1235 } else { 1216 - stack[ctr].dentry = this; 1217 - stack[ctr].layer = lower.layer; 1218 - ctr++; 1236 + ctx->stack[ctx->ctr].dentry = this; 1237 + ctx->stack[ctx->ctr].layer = lower.layer; 1238 + ctx->ctr++; 1219 1239 } 1220 1240 1221 - if (d.stop) 1241 + if (d->stop) 1222 1242 break; 1223 1243 1224 - if (d.redirect && d.redirect[0] == '/' && poe != roe) { 1244 + if (d->redirect && d->redirect[0] == '/' && poe != roe) { 1225 1245 poe = roe; 1226 1246 /* Find the current layer on the root dentry */ 1227 1247 i = lower.layer->idx - 1; ··· 1232 1252 * Defer lookup of lowerdata in data-only layers to first access. 1233 1253 * Don't require redirect=follow and metacopy=on in this case. 1234 1254 */ 1235 - if (d.metacopy && ctr && ofs->numdatalayer && d.absolute_redirect) { 1236 - d.metacopy = 0; 1237 - ctr++; 1238 - } else if (!ovl_check_follow_redirect(&d)) { 1255 + if (d->metacopy && ctx->ctr && ofs->numdatalayer && d->absolute_redirect) { 1256 + d->metacopy = 0; 1257 + ctx->ctr++; 1258 + } else if (!ovl_check_follow_redirect(d)) { 1239 1259 err = -EPERM; 1240 - goto out_put; 1260 + return err; 1241 1261 } 1242 1262 1243 1263 /* ··· 1248 1268 * For metacopy dentry, path based lookup will find lower dentries. 1249 1269 * Just make sure a corresponding data dentry has been found. 1250 1270 */ 1251 - if (d.metacopy || (uppermetacopy && !ctr)) { 1271 + if (d->metacopy || (uppermetacopy && !ctx->ctr)) { 1252 1272 pr_warn_ratelimited("metacopy with no lower data found - abort lookup (%pd2)\n", 1253 1273 dentry); 1254 1274 err = -EIO; 1255 - goto out_put; 1256 - } else if (!d.is_dir && upperdentry && !ctr && origin_path) { 1257 - if (WARN_ON(stack != NULL)) { 1275 + return err; 1276 + } else if (!d->is_dir && ctx->upperdentry && !ctx->ctr && ctx->origin_path) { 1277 + if (WARN_ON(ctx->stack != NULL)) { 1258 1278 err = -EIO; 1259 - goto out_put; 1279 + return err; 1260 1280 } 1261 - stack = origin_path; 1262 - ctr = 1; 1263 - origin = origin_path->dentry; 1264 - origin_path = NULL; 1281 + ctx->stack = ctx->origin_path; 1282 + ctx->ctr = 1; 1283 + origin = ctx->origin_path->dentry; 1284 + ctx->origin_path = NULL; 1265 1285 } 1266 1286 1267 1287 /* ··· 1283 1303 * is enabled and if upper had an ORIGIN xattr. 1284 1304 * 1285 1305 */ 1286 - if (!upperdentry && ctr) 1287 - origin = stack[0].dentry; 1306 + if (!ctx->upperdentry && ctx->ctr) 1307 + origin = ctx->stack[0].dentry; 1288 1308 1289 1309 if (origin && ovl_indexdir(dentry->d_sb) && 1290 - (!d.is_dir || ovl_index_all(dentry->d_sb))) { 1291 - index = ovl_lookup_index(ofs, upperdentry, origin, true); 1292 - if (IS_ERR(index)) { 1293 - err = PTR_ERR(index); 1294 - index = NULL; 1295 - goto out_put; 1310 + (!d->is_dir || ovl_index_all(dentry->d_sb))) { 1311 + ctx->index = ovl_lookup_index(ofs, ctx->upperdentry, origin, true); 1312 + if (IS_ERR(ctx->index)) { 1313 + err = PTR_ERR(ctx->index); 1314 + ctx->index = NULL; 1315 + return err; 1296 1316 } 1297 1317 } 1298 1318 1299 - if (ctr) { 1300 - oe = ovl_alloc_entry(ctr); 1319 + if (ctx->ctr) { 1320 + ctx->oe = ovl_alloc_entry(ctx->ctr); 1301 1321 err = -ENOMEM; 1302 - if (!oe) 1303 - goto out_put; 1322 + if (!ctx->oe) 1323 + return err; 1304 1324 1305 - ovl_stack_cpy(ovl_lowerstack(oe), stack, ctr); 1325 + ovl_stack_cpy(ovl_lowerstack(ctx->oe), ctx->stack, ctx->ctr); 1306 1326 } 1307 1327 1308 1328 if (upperopaque) 1309 1329 ovl_dentry_set_opaque(dentry); 1310 - if (d.xwhiteouts) 1330 + if (d->xwhiteouts) 1311 1331 ovl_dentry_set_xwhiteouts(dentry); 1312 1332 1313 - if (upperdentry) 1333 + if (ctx->upperdentry) 1314 1334 ovl_dentry_set_upper_alias(dentry); 1315 - else if (index) { 1335 + else if (ctx->index) { 1336 + char *upperredirect; 1316 1337 struct path upperpath = { 1317 - .dentry = upperdentry = dget(index), 1338 + .dentry = ctx->upperdentry = dget(ctx->index), 1318 1339 .mnt = ovl_upper_mnt(ofs), 1319 1340 }; 1320 1341 ··· 1324 1343 * assignment happens only if upperdentry is non-NULL, and 1325 1344 * this one only if upperdentry is NULL. 1326 1345 */ 1327 - d.upperredirect = ovl_get_redirect_xattr(ofs, &upperpath, 0); 1328 - if (IS_ERR(d.upperredirect)) { 1329 - err = PTR_ERR(d.upperredirect); 1330 - d.upperredirect = NULL; 1331 - goto out_free_oe; 1332 - } 1346 + upperredirect = ovl_get_redirect_xattr(ofs, &upperpath, 0); 1347 + if (IS_ERR(upperredirect)) 1348 + return PTR_ERR(upperredirect); 1349 + d->upperredirect = upperredirect; 1333 1350 1334 1351 err = ovl_check_metacopy_xattr(ofs, &upperpath, NULL); 1335 1352 if (err < 0) 1336 - goto out_free_oe; 1337 - d.metacopy = uppermetacopy = err; 1353 + return err; 1354 + d->metacopy = uppermetacopy = err; 1338 1355 metacopy_size = err; 1339 1356 1340 - if (!ovl_check_follow_redirect(&d)) { 1357 + if (!ovl_check_follow_redirect(d)) { 1341 1358 err = -EPERM; 1342 - goto out_free_oe; 1359 + return err; 1343 1360 } 1344 1361 } 1345 1362 1346 - if (upperdentry || ctr) { 1363 + if (ctx->upperdentry || ctx->ctr) { 1364 + struct inode *inode; 1347 1365 struct ovl_inode_params oip = { 1348 - .upperdentry = upperdentry, 1349 - .oe = oe, 1350 - .index = index, 1351 - .redirect = d.upperredirect, 1366 + .upperdentry = ctx->upperdentry, 1367 + .oe = ctx->oe, 1368 + .index = ctx->index, 1369 + .redirect = d->upperredirect, 1352 1370 }; 1353 1371 1354 1372 /* Store lowerdata redirect for lazy lookup */ 1355 - if (ctr > 1 && !d.is_dir && !stack[ctr - 1].dentry) { 1356 - oip.lowerdata_redirect = d.redirect; 1357 - d.redirect = NULL; 1373 + if (ctx->ctr > 1 && !d->is_dir && !ctx->stack[ctx->ctr - 1].dentry) { 1374 + oip.lowerdata_redirect = d->redirect; 1375 + d->redirect = NULL; 1358 1376 } 1377 + 1359 1378 inode = ovl_get_inode(dentry->d_sb, &oip); 1360 - err = PTR_ERR(inode); 1361 1379 if (IS_ERR(inode)) 1362 - goto out_free_oe; 1363 - if (upperdentry && !uppermetacopy) 1364 - ovl_set_flag(OVL_UPPERDATA, inode); 1380 + return PTR_ERR(inode); 1381 + 1382 + ctx->inode = inode; 1383 + if (ctx->upperdentry && !uppermetacopy) 1384 + ovl_set_flag(OVL_UPPERDATA, ctx->inode); 1365 1385 1366 1386 if (metacopy_size > OVL_METACOPY_MIN_SIZE) 1367 - ovl_set_flag(OVL_HAS_DIGEST, inode); 1387 + ovl_set_flag(OVL_HAS_DIGEST, ctx->inode); 1368 1388 } 1369 1389 1370 - ovl_dentry_init_reval(dentry, upperdentry, OVL_I_E(inode)); 1390 + ovl_dentry_init_reval(dentry, ctx->upperdentry, OVL_I_E(ctx->inode)); 1371 1391 1372 - ovl_revert_creds(old_cred); 1373 - if (origin_path) { 1374 - dput(origin_path->dentry); 1375 - kfree(origin_path); 1392 + return 0; 1393 + } 1394 + 1395 + struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, 1396 + unsigned int flags) 1397 + { 1398 + struct ovl_fs *ofs = OVL_FS(dentry->d_sb); 1399 + struct ovl_entry *poe = OVL_E(dentry->d_parent); 1400 + bool check_redirect = (ovl_redirect_follow(ofs) || ofs->numdatalayer); 1401 + int err; 1402 + struct ovl_lookup_ctx ctx = { 1403 + .dentry = dentry, 1404 + }; 1405 + struct ovl_lookup_data d = { 1406 + .sb = dentry->d_sb, 1407 + .dentry = dentry, 1408 + .name = dentry->d_name, 1409 + .last = check_redirect ? false : !ovl_numlower(poe), 1410 + }; 1411 + 1412 + if (dentry->d_name.len > ofs->namelen) 1413 + return ERR_PTR(-ENAMETOOLONG); 1414 + 1415 + with_ovl_creds(dentry->d_sb) 1416 + err = ovl_lookup_layers(&ctx, &d); 1417 + 1418 + if (ctx.origin_path) { 1419 + dput(ctx.origin_path->dentry); 1420 + kfree(ctx.origin_path); 1376 1421 } 1377 - dput(index); 1378 - ovl_stack_free(stack, ctr); 1422 + dput(ctx.index); 1423 + ovl_stack_free(ctx.stack, ctx.ctr); 1379 1424 kfree(d.redirect); 1380 - return d_splice_alias(inode, dentry); 1381 1425 1382 - out_free_oe: 1383 - ovl_free_entry(oe); 1384 - out_put: 1385 - dput(index); 1386 - ovl_stack_free(stack, ctr); 1387 - out_put_upper: 1388 - if (origin_path) { 1389 - dput(origin_path->dentry); 1390 - kfree(origin_path); 1426 + if (err) { 1427 + ovl_free_entry(ctx.oe); 1428 + dput(ctx.upperdentry); 1429 + kfree(d.upperredirect); 1430 + return ERR_PTR(err); 1391 1431 } 1392 - dput(upperdentry); 1393 - kfree(d.upperredirect); 1394 - out: 1395 - kfree(d.redirect); 1396 - ovl_revert_creds(old_cred); 1397 - return ERR_PTR(err); 1432 + 1433 + return d_splice_alias(ctx.inode, dentry); 1398 1434 } 1399 1435 1400 1436 bool ovl_lower_positive(struct dentry *dentry) 1401 1437 { 1402 1438 struct ovl_entry *poe = OVL_E(dentry->d_parent); 1403 1439 const struct qstr *name = &dentry->d_name; 1404 - const struct cred *old_cred; 1405 1440 unsigned int i; 1406 1441 bool positive = false; 1407 1442 bool done = false; ··· 1433 1436 if (!ovl_dentry_upper(dentry)) 1434 1437 return true; 1435 1438 1436 - old_cred = ovl_override_creds(dentry->d_sb); 1437 - /* Positive upper -> have to look up lower to see whether it exists */ 1438 - for (i = 0; !done && !positive && i < ovl_numlower(poe); i++) { 1439 - struct dentry *this; 1440 - struct ovl_path *parentpath = &ovl_lowerstack(poe)[i]; 1439 + with_ovl_creds(dentry->d_sb) { 1440 + /* Positive upper -> have to look up lower to see whether it exists */ 1441 + for (i = 0; !done && !positive && i < ovl_numlower(poe); i++) { 1442 + struct dentry *this; 1443 + struct ovl_path *parentpath = &ovl_lowerstack(poe)[i]; 1441 1444 1442 - /* 1443 - * We need to make a non-const copy of dentry->d_name, 1444 - * because lookup_one_positive_unlocked() will hash name 1445 - * with parentpath base, which is on another (lower fs). 1446 - */ 1447 - this = lookup_one_positive_unlocked( 1448 - mnt_idmap(parentpath->layer->mnt), 1449 - &QSTR_LEN(name->name, name->len), 1450 - parentpath->dentry); 1451 - if (IS_ERR(this)) { 1452 - switch (PTR_ERR(this)) { 1453 - case -ENOENT: 1454 - case -ENAMETOOLONG: 1455 - break; 1445 + /* 1446 + * We need to make a non-const copy of dentry->d_name, 1447 + * because lookup_one_positive_unlocked() will hash name 1448 + * with parentpath base, which is on another (lower fs). 1449 + */ 1450 + this = lookup_one_positive_unlocked(mnt_idmap(parentpath->layer->mnt), 1451 + &QSTR_LEN(name->name, name->len), 1452 + parentpath->dentry); 1453 + if (IS_ERR(this)) { 1454 + switch (PTR_ERR(this)) { 1455 + case -ENOENT: 1456 + case -ENAMETOOLONG: 1457 + break; 1456 1458 1457 - default: 1458 - /* 1459 - * Assume something is there, we just couldn't 1460 - * access it. 1461 - */ 1462 - positive = true; 1463 - break; 1459 + default: 1460 + /* 1461 + * Assume something is there, we just couldn't 1462 + * access it. 1463 + */ 1464 + positive = true; 1465 + break; 1466 + } 1467 + } else { 1468 + struct path path = { 1469 + .dentry = this, 1470 + .mnt = parentpath->layer->mnt, 1471 + }; 1472 + positive = !ovl_path_is_whiteout(OVL_FS(dentry->d_sb), &path); 1473 + done = true; 1474 + dput(this); 1464 1475 } 1465 - } else { 1466 - struct path path = { 1467 - .dentry = this, 1468 - .mnt = parentpath->layer->mnt, 1469 - }; 1470 - positive = !ovl_path_is_whiteout(OVL_FS(dentry->d_sb), &path); 1471 - done = true; 1472 - dput(this); 1473 1476 } 1474 1477 } 1475 - ovl_revert_creds(old_cred); 1476 1478 1477 1479 return positive; 1478 1480 }
+5 -1
fs/overlayfs/overlayfs.h
··· 455 455 void ovl_drop_write(struct dentry *dentry); 456 456 struct dentry *ovl_workdir(struct dentry *dentry); 457 457 const struct cred *ovl_override_creds(struct super_block *sb); 458 - void ovl_revert_creds(const struct cred *old_cred); 458 + 459 + EXTEND_CLASS(override_creds, _ovl, ovl_override_creds(sb), struct super_block *sb) 460 + 461 + #define with_ovl_creds(sb) \ 462 + scoped_class(override_creds_ovl, __UNIQUE_ID(label), sb) 459 463 460 464 static inline const struct cred *ovl_creds(struct super_block *sb) 461 465 {
+51 -51
fs/overlayfs/readdir.c
··· 348 348 349 349 static int ovl_check_whiteouts(const struct path *path, struct ovl_readdir_data *rdd) 350 350 { 351 - int err = 0; 352 351 struct dentry *dentry, *dir = path->dentry; 353 - const struct cred *old_cred; 354 - 355 - old_cred = ovl_override_creds(rdd->dentry->d_sb); 356 352 357 353 while (rdd->first_maybe_whiteout) { 358 354 struct ovl_cache_entry *p = ··· 361 365 p->is_whiteout = ovl_is_whiteout(dentry); 362 366 dput(dentry); 363 367 } else if (PTR_ERR(dentry) == -EINTR) { 364 - err = -EINTR; 365 - break; 368 + return -EINTR; 366 369 } 367 370 } 368 - ovl_revert_creds(old_cred); 369 371 370 - return err; 372 + return 0; 371 373 } 372 374 373 375 static inline int ovl_dir_read(const struct path *realpath, ··· 832 838 return err; 833 839 } 834 840 835 - 836 - static int ovl_iterate(struct file *file, struct dir_context *ctx) 841 + static int ovl_iterate_merged(struct file *file, struct dir_context *ctx) 837 842 { 838 843 struct ovl_dir_file *od = file->private_data; 839 844 struct dentry *dentry = file->f_path.dentry; 840 - struct ovl_fs *ofs = OVL_FS(dentry->d_sb); 841 845 struct ovl_cache_entry *p; 842 - const struct cred *old_cred; 843 - int err; 844 - 845 - old_cred = ovl_override_creds(dentry->d_sb); 846 - if (!ctx->pos) 847 - ovl_dir_reset(file); 848 - 849 - if (od->is_real) { 850 - /* 851 - * If parent is merge, then need to adjust d_ino for '..', if 852 - * dir is impure then need to adjust d_ino for copied up 853 - * entries. 854 - */ 855 - if (ovl_xino_bits(ofs) || 856 - (ovl_same_fs(ofs) && 857 - (ovl_is_impure_dir(file) || 858 - OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) { 859 - err = ovl_iterate_real(file, ctx); 860 - } else { 861 - err = iterate_dir(od->realfile, ctx); 862 - } 863 - goto out; 864 - } 846 + int err = 0; 865 847 866 848 if (!od->cache) { 867 849 struct ovl_dir_cache *cache; ··· 845 875 cache = ovl_cache_get(dentry); 846 876 err = PTR_ERR(cache); 847 877 if (IS_ERR(cache)) 848 - goto out; 878 + return err; 849 879 850 880 od->cache = cache; 851 881 ovl_seek_cursor(od, ctx->pos); ··· 857 887 if (!p->ino || p->check_xwhiteout) { 858 888 err = ovl_cache_update(&file->f_path, p, !p->ino); 859 889 if (err) 860 - goto out; 890 + return err; 861 891 } 862 892 } 863 893 /* ovl_cache_update() sets is_whiteout on stale entry */ ··· 868 898 od->cursor = p->l_node.next; 869 899 ctx->pos++; 870 900 } 871 - err = 0; 872 - out: 873 - ovl_revert_creds(old_cred); 874 901 return err; 902 + } 903 + 904 + static bool ovl_need_adjust_d_ino(struct file *file) 905 + { 906 + struct dentry *dentry = file->f_path.dentry; 907 + struct ovl_fs *ofs = OVL_FS(dentry->d_sb); 908 + 909 + /* If parent is merge, then need to adjust d_ino for '..' */ 910 + if (ovl_xino_bits(ofs)) 911 + return true; 912 + 913 + /* Can't do consistent inode numbering */ 914 + if (!ovl_same_fs(ofs)) 915 + return false; 916 + 917 + /* If dir is impure then need to adjust d_ino for copied up entries */ 918 + if (ovl_is_impure_dir(file) || 919 + OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))) 920 + return true; 921 + 922 + /* Pure: no need to adjust d_ino */ 923 + return false; 924 + } 925 + 926 + 927 + static int ovl_iterate(struct file *file, struct dir_context *ctx) 928 + { 929 + struct ovl_dir_file *od = file->private_data; 930 + 931 + if (!ctx->pos) 932 + ovl_dir_reset(file); 933 + 934 + with_ovl_creds(file_dentry(file)->d_sb) { 935 + if (!od->is_real) 936 + return ovl_iterate_merged(file, ctx); 937 + 938 + if (ovl_need_adjust_d_ino(file)) 939 + return ovl_iterate_real(file, ctx); 940 + 941 + return iterate_dir(od->realfile, ctx); 942 + } 875 943 } 876 944 877 945 static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin) ··· 955 947 static struct file *ovl_dir_open_realfile(const struct file *file, 956 948 const struct path *realpath) 957 949 { 958 - struct file *res; 959 - const struct cred *old_cred; 960 - 961 - old_cred = ovl_override_creds(file_inode(file)->i_sb); 962 - res = ovl_path_open(realpath, O_RDONLY | (file->f_flags & O_LARGEFILE)); 963 - ovl_revert_creds(old_cred); 964 - 965 - return res; 950 + with_ovl_creds(file_inode(file)->i_sb) 951 + return ovl_path_open(realpath, O_RDONLY | (file->f_flags & O_LARGEFILE)); 966 952 } 967 953 968 954 /* ··· 1077 1075 int err; 1078 1076 struct ovl_cache_entry *p, *n; 1079 1077 struct rb_root root = RB_ROOT; 1080 - const struct cred *old_cred; 1081 1078 1082 - old_cred = ovl_override_creds(dentry->d_sb); 1083 - err = ovl_dir_read_merged(dentry, list, &root); 1084 - ovl_revert_creds(old_cred); 1079 + with_ovl_creds(dentry->d_sb) 1080 + err = ovl_dir_read_merged(dentry, list, &root); 1085 1081 if (err) 1086 1082 return err; 1087 1083
+44 -45
fs/overlayfs/super.c
··· 1364 1364 set_default_d_op(sb, &ovl_dentry_operations); 1365 1365 } 1366 1366 1367 - int ovl_fill_super(struct super_block *sb, struct fs_context *fc) 1367 + static int ovl_fill_super_creds(struct fs_context *fc, struct super_block *sb) 1368 1368 { 1369 1369 struct ovl_fs *ofs = sb->s_fs_info; 1370 + struct cred *creator_cred = (struct cred *)ofs->creator_cred; 1370 1371 struct ovl_fs_context *ctx = fc->fs_private; 1371 - const struct cred *old_cred = NULL; 1372 - struct dentry *root_dentry; 1373 - struct ovl_entry *oe; 1374 1372 struct ovl_layer *layers; 1375 - struct cred *cred; 1373 + struct ovl_entry *oe = NULL; 1376 1374 int err; 1377 - 1378 - err = -EIO; 1379 - if (WARN_ON(fc->user_ns != current_user_ns())) 1380 - goto out_err; 1381 - 1382 - ovl_set_d_op(sb); 1383 - 1384 - err = -ENOMEM; 1385 - if (!ofs->creator_cred) 1386 - ofs->creator_cred = cred = prepare_creds(); 1387 - else 1388 - cred = (struct cred *)ofs->creator_cred; 1389 - if (!cred) 1390 - goto out_err; 1391 - 1392 - old_cred = ovl_override_creds(sb); 1393 1375 1394 1376 err = ovl_fs_params_verify(ctx, &ofs->config); 1395 1377 if (err) 1396 - goto out_err; 1378 + return err; 1397 1379 1398 1380 err = -EINVAL; 1399 1381 if (ctx->nr == 0) { 1400 1382 if (!(fc->sb_flags & SB_SILENT)) 1401 1383 pr_err("missing 'lowerdir'\n"); 1402 - goto out_err; 1384 + return err; 1403 1385 } 1404 1386 1405 1387 err = -ENOMEM; 1406 1388 layers = kcalloc(ctx->nr + 1, sizeof(struct ovl_layer), GFP_KERNEL); 1407 1389 if (!layers) 1408 - goto out_err; 1390 + return err; 1409 1391 1410 1392 ofs->config.lowerdirs = kcalloc(ctx->nr + 1, sizeof(char *), GFP_KERNEL); 1411 1393 if (!ofs->config.lowerdirs) { 1412 1394 kfree(layers); 1413 - goto out_err; 1395 + return err; 1414 1396 } 1415 1397 ofs->layers = layers; 1416 1398 /* ··· 1425 1443 err = -EINVAL; 1426 1444 if (!ofs->config.workdir) { 1427 1445 pr_err("missing 'workdir'\n"); 1428 - goto out_err; 1446 + return err; 1429 1447 } 1430 1448 1431 1449 err = ovl_get_upper(sb, ofs, &layers[0], &ctx->upper); 1432 1450 if (err) 1433 - goto out_err; 1451 + return err; 1434 1452 1435 1453 upper_sb = ovl_upper_mnt(ofs)->mnt_sb; 1436 1454 if (!ovl_should_sync(ofs)) { ··· 1438 1456 if (errseq_check(&upper_sb->s_wb_err, ofs->errseq)) { 1439 1457 err = -EIO; 1440 1458 pr_err("Cannot mount volatile when upperdir has an unseen error. Sync upperdir fs to clear state.\n"); 1441 - goto out_err; 1459 + return err; 1442 1460 } 1443 1461 } 1444 1462 1445 1463 err = ovl_get_workdir(sb, ofs, &ctx->upper, &ctx->work); 1446 1464 if (err) 1447 - goto out_err; 1465 + return err; 1448 1466 1449 1467 if (!ofs->workdir) 1450 1468 sb->s_flags |= SB_RDONLY; ··· 1455 1473 oe = ovl_get_lowerstack(sb, ctx, ofs, layers); 1456 1474 err = PTR_ERR(oe); 1457 1475 if (IS_ERR(oe)) 1458 - goto out_err; 1476 + return err; 1459 1477 1460 1478 /* If the upper fs is nonexistent, we mark overlayfs r/o too */ 1461 1479 if (!ovl_upper_mnt(ofs)) ··· 1508 1526 sb->s_export_op = &ovl_export_fid_operations; 1509 1527 1510 1528 /* Never override disk quota limits or use reserved space */ 1511 - cap_lower(cred->cap_effective, CAP_SYS_RESOURCE); 1529 + cap_lower(creator_cred->cap_effective, CAP_SYS_RESOURCE); 1512 1530 1513 1531 sb->s_magic = OVERLAYFS_SUPER_MAGIC; 1514 1532 sb->s_xattr = ovl_xattr_handlers(ofs); ··· 1526 1544 sb->s_iflags |= SB_I_EVM_HMAC_UNSUPPORTED; 1527 1545 1528 1546 err = -ENOMEM; 1529 - root_dentry = ovl_get_root(sb, ctx->upper.dentry, oe); 1530 - if (!root_dentry) 1547 + sb->s_root = ovl_get_root(sb, ctx->upper.dentry, oe); 1548 + if (!sb->s_root) 1531 1549 goto out_free_oe; 1532 1550 1533 - sb->s_root = root_dentry; 1534 - 1535 - ovl_revert_creds(old_cred); 1536 1551 return 0; 1537 1552 1538 1553 out_free_oe: 1539 1554 ovl_free_entry(oe); 1555 + return err; 1556 + } 1557 + 1558 + int ovl_fill_super(struct super_block *sb, struct fs_context *fc) 1559 + { 1560 + struct ovl_fs *ofs = sb->s_fs_info; 1561 + int err; 1562 + 1563 + err = -EIO; 1564 + if (WARN_ON(fc->user_ns != current_user_ns())) 1565 + goto out_err; 1566 + 1567 + ovl_set_d_op(sb); 1568 + 1569 + if (!ofs->creator_cred) { 1570 + err = -ENOMEM; 1571 + ofs->creator_cred = prepare_creds(); 1572 + if (!ofs->creator_cred) 1573 + goto out_err; 1574 + } 1575 + 1576 + with_ovl_creds(sb) 1577 + err = ovl_fill_super_creds(fc, sb); 1578 + 1540 1579 out_err: 1541 - /* 1542 - * Revert creds before calling ovl_free_fs() which will call 1543 - * put_cred() and put_cred() requires that the cred's that are 1544 - * put are not the caller's creds, i.e., current->cred. 1545 - */ 1546 - if (old_cred) 1547 - ovl_revert_creds(old_cred); 1548 - ovl_free_fs(ofs); 1549 - sb->s_fs_info = NULL; 1580 + if (err) { 1581 + ovl_free_fs(ofs); 1582 + sb->s_fs_info = NULL; 1583 + } 1584 + 1550 1585 return err; 1551 1586 } 1552 1587
+4 -14
fs/overlayfs/util.c
··· 69 69 return override_creds(ofs->creator_cred); 70 70 } 71 71 72 - void ovl_revert_creds(const struct cred *old_cred) 73 - { 74 - revert_creds(old_cred); 75 - } 76 - 77 72 /* 78 73 * Check if underlying fs supports file handles and try to determine encoding 79 74 * type, in order to deduce maximum inode number used by fs. ··· 1142 1147 int ovl_nlink_start(struct dentry *dentry) 1143 1148 { 1144 1149 struct inode *inode = d_inode(dentry); 1145 - const struct cred *old_cred; 1146 1150 int err; 1147 1151 1148 1152 if (WARN_ON(!inode)) ··· 1178 1184 if (d_is_dir(dentry) || !ovl_test_flag(OVL_INDEX, inode)) 1179 1185 return 0; 1180 1186 1181 - old_cred = ovl_override_creds(dentry->d_sb); 1182 1187 /* 1183 1188 * The overlay inode nlink should be incremented/decremented IFF the 1184 1189 * upper operation succeeds, along with nlink change of upper inode. 1185 1190 * Therefore, before link/unlink/rename, we store the union nlink 1186 1191 * value relative to the upper inode nlink in an upper inode xattr. 1187 1192 */ 1188 - err = ovl_set_nlink_upper(dentry); 1189 - ovl_revert_creds(old_cred); 1193 + with_ovl_creds(dentry->d_sb) 1194 + err = ovl_set_nlink_upper(dentry); 1190 1195 if (err) 1191 1196 goto out_drop_write; 1192 1197 ··· 1206 1213 ovl_drop_write(dentry); 1207 1214 1208 1215 if (ovl_test_flag(OVL_INDEX, inode) && inode->i_nlink == 0) { 1209 - const struct cred *old_cred; 1210 - 1211 - old_cred = ovl_override_creds(dentry->d_sb); 1212 - ovl_cleanup_index(dentry); 1213 - ovl_revert_creds(old_cred); 1216 + with_ovl_creds(dentry->d_sb) 1217 + ovl_cleanup_index(dentry); 1214 1218 } 1215 1219 1216 1220 ovl_inode_unlock(inode);
+13 -22
fs/overlayfs/xattrs.c
··· 41 41 struct dentry *upperdentry = ovl_i_dentry_upper(inode); 42 42 struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry); 43 43 struct path realpath; 44 - const struct cred *old_cred; 45 44 46 45 if (!value && !upperdentry) { 47 46 ovl_path_lower(dentry, &realpath); 48 - old_cred = ovl_override_creds(dentry->d_sb); 49 - err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0); 50 - ovl_revert_creds(old_cred); 47 + with_ovl_creds(dentry->d_sb) 48 + err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0); 51 49 if (err < 0) 52 50 goto out; 53 51 } ··· 62 64 if (err) 63 65 goto out; 64 66 65 - old_cred = ovl_override_creds(dentry->d_sb); 66 - if (value) { 67 - err = ovl_do_setxattr(ofs, realdentry, name, value, size, 68 - flags); 69 - } else { 70 - WARN_ON(flags != XATTR_REPLACE); 71 - err = ovl_do_removexattr(ofs, realdentry, name); 67 + with_ovl_creds(dentry->d_sb) { 68 + if (value) { 69 + err = ovl_do_setxattr(ofs, realdentry, name, value, size, flags); 70 + } else { 71 + WARN_ON(flags != XATTR_REPLACE); 72 + err = ovl_do_removexattr(ofs, realdentry, name); 73 + } 72 74 } 73 - ovl_revert_creds(old_cred); 74 75 ovl_drop_write(dentry); 75 76 76 77 /* copy c/mtime */ ··· 81 84 static int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name, 82 85 void *value, size_t size) 83 86 { 84 - ssize_t res; 85 - const struct cred *old_cred; 86 87 struct path realpath; 87 88 88 89 ovl_i_path_real(inode, &realpath); 89 - old_cred = ovl_override_creds(dentry->d_sb); 90 - res = vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size); 91 - ovl_revert_creds(old_cred); 92 - return res; 90 + with_ovl_creds(dentry->d_sb) 91 + return vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size); 93 92 } 94 93 95 94 static bool ovl_can_list(struct super_block *sb, const char *s) ··· 109 116 ssize_t res; 110 117 size_t len; 111 118 char *s; 112 - const struct cred *old_cred; 113 119 size_t prefix_len, name_len; 114 120 115 - old_cred = ovl_override_creds(dentry->d_sb); 116 - res = vfs_listxattr(realdentry, list, size); 117 - ovl_revert_creds(old_cred); 121 + with_ovl_creds(dentry->d_sb) 122 + res = vfs_listxattr(realdentry, list, size); 118 123 if (res <= 0 || size == 0) 119 124 return res; 120 125