Skip to content

Commit 9c27e5c

Browse files
committed
Merge patch series "ovl: add override_creds mount option"
Christian Brauner <[email protected]> says: Currently overlayfs uses the mounter's credentials for it's override_creds() calls. That provides a consistent permission model. This patches allows a caller to instruct overlayfs to use its credentials instead. The caller must be located in the same user namespace hierarchy as the user namespace the overlayfs instance will be mounted in. This provides a consistent and simple security model. With this it is possible to e.g., mount an overlayfs instance where the mounter must have CAP_SYS_ADMIN but the credentials used for override_creds() have dropped CAP_SYS_ADMIN. It also allows the usage of custom fs{g,u}id different from the callers and other tweaks. * patches from https://lore.kernel.org/r/[email protected]: selftests/ovl: add third selftest for "override_creds" selftests/ovl: add second selftest for "override_creds" selftests/filesystems: add utils.{c,h} selftests/ovl: add first selftest for "override_creds" ovl: allow to specify override credentials Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
2 parents 2014c95 + a1579f6 commit 9c27e5c

File tree

7 files changed

+924
-10
lines changed

7 files changed

+924
-10
lines changed

Documentation/filesystems/overlayfs.rst

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,21 +292,35 @@ rename or unlink will of course be noticed and handled).
292292
Permission model
293293
----------------
294294

295+
An overlay filesystem stashes credentials that will be used when
296+
accessing lower or upper filesystems.
297+
298+
In the old mount api the credentials of the task calling mount(2) are
299+
stashed. In the new mount api the credentials of the task creating the
300+
superblock through FSCONFIG_CMD_CREATE command of fsconfig(2) are
301+
stashed.
302+
303+
Starting with kernel v6.15 it is possible to use the "override_creds"
304+
mount option which will cause the credentials of the calling task to be
305+
recorded. Note that "override_creds" is only meaningful when used with
306+
the new mount api as the old mount api combines setting options and
307+
superblock creation in a single mount(2) syscall.
308+
295309
Permission checking in the overlay filesystem follows these principles:
296310

297311
1) permission check SHOULD return the same result before and after copy up
298312

299313
2) task creating the overlay mount MUST NOT gain additional privileges
300314

301-
3) non-mounting task MAY gain additional privileges through the overlay,
315+
3) task[*] MAY gain additional privileges through the overlay,
302316
compared to direct access on underlying lower or upper filesystems
303317

304318
This is achieved by performing two permission checks on each access:
305319

306320
a) check if current task is allowed access based on local DAC (owner,
307321
group, mode and posix acl), as well as MAC checks
308322

309-
b) check if mounting task would be allowed real operation on lower or
323+
b) check if stashed credentials would be allowed real operation on lower or
310324
upper layer based on underlying filesystem permissions, again including
311325
MAC checks
312326

@@ -315,10 +329,10 @@ are copied up. On the other hand it can result in server enforced
315329
permissions (used by NFS, for example) being ignored (3).
316330

317331
Check (b) ensures that no task gains permissions to underlying layers that
318-
the mounting task does not have (2). This also means that it is possible
332+
the stashed credentials do not have (2). This also means that it is possible
319333
to create setups where the consistency rule (1) does not hold; normally,
320-
however, the mounting task will have sufficient privileges to perform all
321-
operations.
334+
however, the stashed credentials will have sufficient privileges to
335+
perform all operations.
322336

323337
Another way to demonstrate this model is drawing parallels between::
324338

fs/overlayfs/params.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ enum ovl_opt {
5959
Opt_metacopy,
6060
Opt_verity,
6161
Opt_volatile,
62+
Opt_override_creds,
6263
};
6364

6465
static const struct constant_table ovl_parameter_bool[] = {
@@ -155,6 +156,7 @@ const struct fs_parameter_spec ovl_parameter_spec[] = {
155156
fsparam_enum("metacopy", Opt_metacopy, ovl_parameter_bool),
156157
fsparam_enum("verity", Opt_verity, ovl_parameter_verity),
157158
fsparam_flag("volatile", Opt_volatile),
159+
fsparam_flag_no("override_creds", Opt_override_creds),
158160
{}
159161
};
160162

@@ -662,6 +664,29 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param)
662664
case Opt_userxattr:
663665
config->userxattr = true;
664666
break;
667+
case Opt_override_creds: {
668+
const struct cred *cred = NULL;
669+
670+
if (result.negated) {
671+
swap(cred, ofs->creator_cred);
672+
put_cred(cred);
673+
break;
674+
}
675+
676+
if (!current_in_userns(fc->user_ns)) {
677+
err = -EINVAL;
678+
break;
679+
}
680+
681+
cred = prepare_creds();
682+
if (cred)
683+
swap(cred, ofs->creator_cred);
684+
else
685+
err = -ENOMEM;
686+
687+
put_cred(cred);
688+
break;
689+
}
665690
default:
666691
pr_err("unrecognized mount option \"%s\" or missing value\n",
667692
param->key);

fs/overlayfs/super.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
13051305
{
13061306
struct ovl_fs *ofs = sb->s_fs_info;
13071307
struct ovl_fs_context *ctx = fc->fs_private;
1308+
const struct cred *old_cred = NULL;
13081309
struct dentry *root_dentry;
13091310
struct ovl_entry *oe;
13101311
struct ovl_layer *layers;
@@ -1318,10 +1319,15 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
13181319
sb->s_d_op = &ovl_dentry_operations;
13191320

13201321
err = -ENOMEM;
1321-
ofs->creator_cred = cred = prepare_creds();
1322+
if (!ofs->creator_cred)
1323+
ofs->creator_cred = cred = prepare_creds();
1324+
else
1325+
cred = (struct cred *)ofs->creator_cred;
13221326
if (!cred)
13231327
goto out_err;
13241328

1329+
old_cred = ovl_override_creds(sb);
1330+
13251331
err = ovl_fs_params_verify(ctx, &ofs->config);
13261332
if (err)
13271333
goto out_err;
@@ -1481,11 +1487,19 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
14811487

14821488
sb->s_root = root_dentry;
14831489

1490+
ovl_revert_creds(old_cred);
14841491
return 0;
14851492

14861493
out_free_oe:
14871494
ovl_free_entry(oe);
14881495
out_err:
1496+
/*
1497+
* Revert creds before calling ovl_free_fs() which will call
1498+
* put_cred() and put_cred() requires that the cred's that are
1499+
* put are not the caller's creds, i.e., current->cred.
1500+
*/
1501+
if (old_cred)
1502+
ovl_revert_creds(old_cred);
14891503
ovl_free_fs(ofs);
14901504
sb->s_fs_info = NULL;
14911505
return err;
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
# SPDX-License-Identifier: GPL-2.0
22

3-
TEST_GEN_PROGS := dev_in_maps set_layers_via_fds
3+
CFLAGS += -Wall
4+
CFLAGS += $(KHDR_INCLUDES)
5+
LDLIBS += -lcap
46

5-
CFLAGS := -Wall -Werror
7+
LOCAL_HDRS += wrappers.h log.h
8+
9+
TEST_GEN_PROGS := dev_in_maps
10+
TEST_GEN_PROGS += set_layers_via_fds
611

712
include ../../lib.mk
13+
14+
$(OUTPUT)/set_layers_via_fds: ../utils.c

0 commit comments

Comments
 (0)