Skip to content

Commit a1da840

Browse files
committed
ovl: refactor ovl_rename()
Extract the code that runs under overridden credentials into a separate ovl_rename_upper() helper function and the code that runs before/after to ovl_rename_start/end(). Error handling is simplified. The helpers returns errors directly instead of using goto labels. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Link: https://patch.msgid.link/20251117-work-ovl-cred-guard-v4-34-b31603935724@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent fb9f31f commit a1da840

1 file changed

Lines changed: 78 additions & 57 deletions

File tree

fs/overlayfs/dir.c

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,49 +1102,30 @@ struct ovl_renamedata {
11021102
bool overwrite;
11031103
};
11041104

1105-
static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
1106-
struct dentry *old, struct inode *newdir,
1107-
struct dentry *new, unsigned int flags)
1105+
static int ovl_rename_start(struct ovl_renamedata *ovlrd, struct list_head *list)
11081106
{
1109-
int err;
1110-
struct dentry *old_upperdir;
1111-
struct dentry *new_upperdir;
1112-
struct renamedata rd = {};
1113-
bool old_opaque;
1114-
bool new_opaque;
1107+
struct dentry *old = ovlrd->old_dentry;
1108+
struct dentry *new = ovlrd->new_dentry;
11151109
bool is_dir = d_is_dir(old);
11161110
bool new_is_dir = d_is_dir(new);
1117-
bool samedir = old->d_parent == new->d_parent;
1118-
struct dentry *whiteout = NULL;
1119-
const struct cred *old_cred = NULL;
1120-
struct ovl_fs *ofs = OVL_FS(old->d_sb);
1121-
struct ovl_renamedata _ovlrd = {
1122-
.old_dentry = old,
1123-
.new_dentry = new,
1124-
.flags = flags,
1125-
.cleanup_whiteout = false,
1126-
.overwrite = !(flags & RENAME_EXCHANGE),
1127-
};
1128-
struct ovl_renamedata *ovlrd = &_ovlrd;
1129-
LIST_HEAD(list);
1111+
int err;
11301112

1131-
err = -EINVAL;
11321113
if (ovlrd->flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
1133-
goto out;
1114+
return -EINVAL;
11341115

11351116
ovlrd->flags &= ~RENAME_NOREPLACE;
11361117

11371118
/* Don't copy up directory trees */
11381119
err = -EXDEV;
11391120
if (!ovl_can_move(old))
1140-
goto out;
1121+
return err;
11411122
if (!ovlrd->overwrite && !ovl_can_move(new))
1142-
goto out;
1123+
return err;
11431124

11441125
if (ovlrd->overwrite && new_is_dir && !ovl_pure_upper(new)) {
1145-
err = ovl_check_empty_dir(new, &list);
1126+
err = ovl_check_empty_dir(new, list);
11461127
if (err)
1147-
goto out;
1128+
return err;
11481129
}
11491130

11501131
if (ovlrd->overwrite) {
@@ -1164,19 +1145,20 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
11641145

11651146
err = ovl_copy_up(old);
11661147
if (err)
1167-
goto out;
1148+
return err;
11681149

11691150
err = ovl_copy_up(new->d_parent);
11701151
if (err)
1171-
goto out;
1152+
return err;
1153+
11721154
if (!ovlrd->overwrite) {
11731155
err = ovl_copy_up(new);
11741156
if (err)
1175-
goto out;
1157+
return err;
11761158
} else if (d_inode(new)) {
11771159
err = ovl_nlink_start(new);
11781160
if (err)
1179-
goto out;
1161+
return err;
11801162

11811163
ovlrd->update_nlink = true;
11821164
}
@@ -1185,22 +1167,34 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
11851167
/* ovl_nlink_start() took ovl_want_write() */
11861168
err = ovl_want_write(old);
11871169
if (err)
1188-
goto out;
1170+
return err;
11891171
}
11901172

1191-
old_cred = ovl_override_creds(old->d_sb);
1173+
return 0;
1174+
}
11921175

1193-
if (!list_empty(&list)) {
1194-
ovlrd->opaquedir = ovl_clear_empty(new, &list);
1195-
err = PTR_ERR(ovlrd->opaquedir);
1196-
if (IS_ERR(ovlrd->opaquedir)) {
1197-
ovlrd->opaquedir = NULL;
1198-
goto out_revert_creds;
1199-
}
1200-
}
1176+
static int ovl_rename_upper(struct ovl_renamedata *ovlrd, struct list_head *list)
1177+
{
1178+
struct dentry *old = ovlrd->old_dentry;
1179+
struct dentry *new = ovlrd->new_dentry;
1180+
struct ovl_fs *ofs = OVL_FS(old->d_sb);
1181+
struct dentry *old_upperdir = ovl_dentry_upper(old->d_parent);
1182+
struct dentry *new_upperdir = ovl_dentry_upper(new->d_parent);
1183+
bool is_dir = d_is_dir(old);
1184+
bool new_is_dir = d_is_dir(new);
1185+
bool samedir = old->d_parent == new->d_parent;
1186+
struct renamedata rd = {};
1187+
struct dentry *de;
1188+
struct dentry *whiteout = NULL;
1189+
bool old_opaque, new_opaque;
1190+
int err;
12011191

1202-
old_upperdir = ovl_dentry_upper(old->d_parent);
1203-
new_upperdir = ovl_dentry_upper(new->d_parent);
1192+
if (!list_empty(list)) {
1193+
de = ovl_clear_empty(new, list);
1194+
if (IS_ERR(de))
1195+
return PTR_ERR(de);
1196+
ovlrd->opaquedir = de;
1197+
}
12041198

12051199
if (!samedir) {
12061200
/*
@@ -1212,12 +1206,12 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
12121206
if (ovl_type_origin(old)) {
12131207
err = ovl_set_impure(new->d_parent, new_upperdir);
12141208
if (err)
1215-
goto out_revert_creds;
1209+
return err;
12161210
}
12171211
if (!ovlrd->overwrite && ovl_type_origin(new)) {
12181212
err = ovl_set_impure(old->d_parent, old_upperdir);
12191213
if (err)
1220-
goto out_revert_creds;
1214+
return err;
12211215
}
12221216
}
12231217

@@ -1229,9 +1223,8 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
12291223
err = start_renaming(&rd, 0,
12301224
&QSTR_LEN(old->d_name.name, old->d_name.len),
12311225
&QSTR_LEN(new->d_name.name, new->d_name.len));
1232-
12331226
if (err)
1234-
goto out_revert_creds;
1227+
return err;
12351228

12361229
err = -ESTALE;
12371230
if (!ovl_matches_upper(old, rd.old_dentry))
@@ -1283,10 +1276,11 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
12831276
if (!err && ovlrd->cleanup_whiteout)
12841277
whiteout = dget(rd.new_dentry);
12851278

1279+
out_unlock:
12861280
end_renaming(&rd);
12871281

12881282
if (err)
1289-
goto out_revert_creds;
1283+
return err;
12901284

12911285
if (whiteout) {
12921286
ovl_cleanup(ofs, old_upperdir, whiteout);
@@ -1310,20 +1304,47 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
13101304
if (d_inode(new) && ovl_dentry_upper(new))
13111305
ovl_copyattr(d_inode(new));
13121306

1313-
out_revert_creds:
1314-
ovl_revert_creds(old_cred);
1307+
return err;
1308+
}
1309+
1310+
static void ovl_rename_end(struct ovl_renamedata *ovlrd)
1311+
{
13151312
if (ovlrd->update_nlink)
1316-
ovl_nlink_end(new);
1313+
ovl_nlink_end(ovlrd->new_dentry);
13171314
else
1318-
ovl_drop_write(old);
1315+
ovl_drop_write(ovlrd->old_dentry);
1316+
}
1317+
1318+
static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
1319+
struct dentry *old, struct inode *newdir,
1320+
struct dentry *new, unsigned int flags)
1321+
{
1322+
const struct cred *old_cred = NULL;
1323+
struct ovl_renamedata ovlrd = {
1324+
.old_parent = old->d_parent,
1325+
.old_dentry = old,
1326+
.new_parent = new->d_parent,
1327+
.new_dentry = new,
1328+
.flags = flags,
1329+
.overwrite = !(flags & RENAME_EXCHANGE),
1330+
};
1331+
LIST_HEAD(list);
1332+
int err;
1333+
1334+
err = ovl_rename_start(&ovlrd, &list);
1335+
if (err)
1336+
goto out;
1337+
1338+
old_cred = ovl_override_creds(old->d_sb);
1339+
1340+
err = ovl_rename_upper(&ovlrd, &list);
1341+
1342+
ovl_revert_creds(old_cred);
1343+
ovl_rename_end(&ovlrd);
13191344
out:
13201345
dput(ovlrd->opaquedir);
13211346
ovl_cache_free(&list);
13221347
return err;
1323-
1324-
out_unlock:
1325-
end_renaming(&rd);
1326-
goto out_revert_creds;
13271348
}
13281349

13291350
static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,

0 commit comments

Comments
 (0)