Skip to content

Commit c0fb968

Browse files
committed
Merge patch series "ovl: convert creation credential override to cred guard"
Christian Brauner <brauner@kernel.org> says: This cleans up the creation specific credential override. The current code to override credentials for creation operations is pretty difficult to understand as we override the credentials twice: (1) override with the mounter's credentials (2) copy the mounts credentials and override the fs{g,u}id with the inode {u,g}id And then we elide the revert_creds() because it would be an idempotent revert. That elision doesn't buy us anything anymore though because it's all reference count less anyway. The fact that this is done in a function and that the revert is happening in the original override makes this a lot to grasp. By introducing a cleanup guard for the creation case we can make this a lot easier to understand and extremely visually prevalent: with_ovl_creds(dentry->d_sb) { scoped_class(prepare_creds_ovl, cred, dentry, inode, mode) { if (IS_ERR(cred)) return PTR_ERR(cred); ovl_path_upper(dentry->d_parent, &realparentpath); /* more stuff you want to do */ } I think this is a big improvement over what we have now. * patches from https://patch.msgid.link/20251117-work-ovl-cred-guard-prepare-v2-0-bd1c97a36d7b@kernel.org: 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 Link: https://patch.msgid.link/20251117-work-ovl-cred-guard-prepare-v2-0-bd1c97a36d7b@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
2 parents 5c06bc9 + 89a11f0 commit c0fb968

1 file changed

Lines changed: 79 additions & 68 deletions

File tree

fs/overlayfs/dir.c

Lines changed: 79 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -581,47 +581,59 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
581581
goto out_dput;
582582
}
583583

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)
588585
{
589586
int err;
590-
struct cred *override_cred;
591587

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)();
593592
if (!override_cred)
594593
return ERR_PTR(-ENOMEM);
595594

596595
override_cred->fsuid = inode->i_uid;
597596
override_cred->fsgid = inode->i_gid;
597+
598598
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)
602601
return ERR_PTR(err);
603-
}
604602

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+
}
613605

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);
615628
}
616629

617630
static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
618631
struct ovl_cattr *attr, bool origin)
619632
{
620633
int err;
621-
const struct cred *new_cred __free(put_cred) = NULL;
622634
struct dentry *parent = dentry->d_parent;
623635

624-
scoped_class(override_creds_ovl, old_cred, dentry->d_sb) {
636+
with_ovl_creds(dentry->d_sb) {
625637
/*
626638
* When linking a file with copy up origin into a new parent, mark the
627639
* new parent dir "impure".
@@ -632,29 +644,28 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
632644
return err;
633645
}
634646

635-
if (!attr->hardlink) {
636-
/*
637-
* In the creation cases(create, mkdir, mknod, symlink),
638-
* ovl should transfer current's fs{u,g}id to underlying
639-
* fs. Because underlying fs want to initialize its new
640-
* inode owner using current's fs{u,g}id. And in this
641-
* case, the @inode is a new inode that is initialized
642-
* in inode_init_owner() to current's fs{u,g}id. So use
643-
* the inode's i_{u,g}id to override the cred's fs{u,g}id.
644-
*
645-
* But in the other hardlink case, ovl_link() does not
646-
* create a new inode, so just use the ovl mounter's
647-
* fs{u,g}id.
648-
*/
649-
new_cred = ovl_setup_cred_for_create(dentry, inode, attr->mode, old_cred);
650-
if (IS_ERR(new_cred))
651-
return PTR_ERR(new_cred);
652-
}
647+
/*
648+
* In the creation cases(create, mkdir, mknod, symlink),
649+
* ovl should transfer current's fs{u,g}id to underlying
650+
* fs. Because underlying fs want to initialize its new
651+
* inode owner using current's fs{u,g}id. And in this
652+
* case, the @inode is a new inode that is initialized
653+
* in inode_init_owner() to current's fs{u,g}id. So use
654+
* the inode's i_{u,g}id to override the cred's fs{u,g}id.
655+
*
656+
* But in the other hardlink case, ovl_link() does not
657+
* create a new inode, so just use the ovl mounter's
658+
* fs{u,g}id.
659+
*/
653660

654-
if (!ovl_dentry_is_whiteout(dentry))
655-
return ovl_create_upper(dentry, inode, attr);
661+
if (attr->hardlink)
662+
return ovl_create_handle_whiteouts(dentry, inode, attr);
656663

657-
return ovl_create_over_whiteout(dentry, inode, attr);
664+
scoped_class(ovl_override_creator_creds, cred, dentry, inode, attr->mode) {
665+
if (IS_ERR(cred))
666+
return PTR_ERR(cred);
667+
return ovl_create_handle_whiteouts(dentry, inode, attr);
668+
}
658669
}
659670
return err;
660671
}
@@ -1345,7 +1356,6 @@ static int ovl_rename(struct mnt_idmap *idmap, struct inode *olddir,
13451356
static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
13461357
struct inode *inode, umode_t mode)
13471358
{
1348-
const struct cred *new_cred __free(put_cred) = NULL;
13491359
struct path realparentpath;
13501360
struct file *realfile;
13511361
struct ovl_file *of;
@@ -1354,33 +1364,34 @@ static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
13541364
int flags = file->f_flags | OVL_OPEN_FLAGS;
13551365
int err;
13561366

1357-
scoped_class(override_creds_ovl, old_cred, dentry->d_sb) {
1358-
new_cred = ovl_setup_cred_for_create(dentry, inode, mode, old_cred);
1359-
if (IS_ERR(new_cred))
1360-
return PTR_ERR(new_cred);
1361-
1362-
ovl_path_upper(dentry->d_parent, &realparentpath);
1363-
realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath,
1364-
mode, current_cred());
1365-
err = PTR_ERR_OR_ZERO(realfile);
1366-
pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err);
1367-
if (err)
1368-
return err;
1367+
with_ovl_creds(dentry->d_sb) {
1368+
scoped_class(ovl_override_creator_creds, cred, dentry, inode, mode) {
1369+
if (IS_ERR(cred))
1370+
return PTR_ERR(cred);
1371+
1372+
ovl_path_upper(dentry->d_parent, &realparentpath);
1373+
realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath,
1374+
mode, current_cred());
1375+
err = PTR_ERR_OR_ZERO(realfile);
1376+
pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err);
1377+
if (err)
1378+
return err;
13691379

1370-
of = ovl_file_alloc(realfile);
1371-
if (!of) {
1372-
fput(realfile);
1373-
return -ENOMEM;
1374-
}
1380+
of = ovl_file_alloc(realfile);
1381+
if (!of) {
1382+
fput(realfile);
1383+
return -ENOMEM;
1384+
}
13751385

1376-
/* ovl_instantiate() consumes the newdentry reference on success */
1377-
newdentry = dget(realfile->f_path.dentry);
1378-
err = ovl_instantiate(dentry, inode, newdentry, false, file);
1379-
if (!err) {
1380-
file->private_data = of;
1381-
} else {
1382-
dput(newdentry);
1383-
ovl_file_free(of);
1386+
/* ovl_instantiate() consumes the newdentry reference on success */
1387+
newdentry = dget(realfile->f_path.dentry);
1388+
err = ovl_instantiate(dentry, inode, newdentry, false, file);
1389+
if (!err) {
1390+
file->private_data = of;
1391+
} else {
1392+
dput(newdentry);
1393+
ovl_file_free(of);
1394+
}
13841395
}
13851396
}
13861397
return err;

0 commit comments

Comments
 (0)