Skip to content

Commit 6af36ae

Browse files
committed
lsm: add backing_file LSM hooks
Stacked filesystems such as overlayfs do not currently provide the necessary mechanisms for LSMs to properly enforce access controls on the mmap() and mprotect() operations. In order to resolve this gap, a LSM security blob is being added to the backing_file struct and the following new LSM hooks are being created: security_backing_file_alloc() security_backing_file_free() security_mmap_backing_file() The first two hooks are to manage the lifecycle of the LSM security blob in the backing_file struct, while the third provides a new mmap() access control point for the underlying backing file. It is also expected that LSMs will likely want to update their security_file_mprotect() callback to address issues with their mprotect() controls, but that does not require a change to the security_file_mprotect() LSM hook. There are a three other small changes to support these new LSM hooks: * Pass the user file associated with a backing file down to alloc_empty_backing_file() so it can be included in the security_backing_file_alloc() hook. * Add getter and setter functions for the backing_file struct LSM blob as the backing_file struct remains private to fs/file_table.c. * Constify the file struct field in the LSM common_audit_data struct to better support LSMs that need to pass a const file struct pointer into the common LSM audit code. Thanks to Arnd Bergmann for identifying the missing EXPORT_SYMBOL_GPL() and supplying a fixup. Cc: stable@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Cc: linux-unionfs@vger.kernel.org Cc: linux-erofs@lists.ozlabs.org Reviewed-by: Amir Goldstein <amir73il@gmail.com> Reviewed-by: Serge Hallyn <serge@hallyn.com> Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Paul Moore <paul@paul-moore.com>
1 parent 880bd49 commit 6af36ae

16 files changed

Lines changed: 206 additions & 17 deletions

File tree

fs/backing-file.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/backing-file.h>
1313
#include <linux/splice.h>
1414
#include <linux/mm.h>
15+
#include <linux/security.h>
1516

1617
#include "internal.h"
1718

@@ -29,14 +30,15 @@
2930
* returned file into a container structure that also stores the stacked
3031
* file's path, which can be retrieved using backing_file_user_path().
3132
*/
32-
struct file *backing_file_open(const struct path *user_path, int flags,
33+
struct file *backing_file_open(const struct file *user_file, int flags,
3334
const struct path *real_path,
3435
const struct cred *cred)
3536
{
37+
const struct path *user_path = &user_file->f_path;
3638
struct file *f;
3739
int error;
3840

39-
f = alloc_empty_backing_file(flags, cred);
41+
f = alloc_empty_backing_file(flags, cred, user_file);
4042
if (IS_ERR(f))
4143
return f;
4244

@@ -52,15 +54,16 @@ struct file *backing_file_open(const struct path *user_path, int flags,
5254
}
5355
EXPORT_SYMBOL_GPL(backing_file_open);
5456

55-
struct file *backing_tmpfile_open(const struct path *user_path, int flags,
57+
struct file *backing_tmpfile_open(const struct file *user_file, int flags,
5658
const struct path *real_parentpath,
5759
umode_t mode, const struct cred *cred)
5860
{
5961
struct mnt_idmap *real_idmap = mnt_idmap(real_parentpath->mnt);
62+
const struct path *user_path = &user_file->f_path;
6063
struct file *f;
6164
int error;
6265

63-
f = alloc_empty_backing_file(flags, cred);
66+
f = alloc_empty_backing_file(flags, cred, user_file);
6467
if (IS_ERR(f))
6568
return f;
6669

@@ -336,8 +339,13 @@ int backing_file_mmap(struct file *file, struct vm_area_struct *vma,
336339

337340
vma_set_file(vma, file);
338341

339-
scoped_with_creds(ctx->cred)
342+
scoped_with_creds(ctx->cred) {
343+
ret = security_mmap_backing_file(vma, file, user_file);
344+
if (ret)
345+
return ret;
346+
340347
ret = vfs_mmap(vma->vm_file, vma);
348+
}
341349

342350
if (ctx->accessed)
343351
ctx->accessed(user_file);

fs/erofs/ishare.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
#include <linux/xxhash.h>
66
#include <linux/mount.h>
7+
#include <linux/security.h>
78
#include "internal.h"
89
#include "xattr.h"
910

@@ -102,7 +103,8 @@ static int erofs_ishare_file_open(struct inode *inode, struct file *file)
102103

103104
if (file->f_flags & O_DIRECT)
104105
return -EINVAL;
105-
realfile = alloc_empty_backing_file(O_RDONLY|O_NOATIME, current_cred());
106+
realfile = alloc_empty_backing_file(O_RDONLY|O_NOATIME, current_cred(),
107+
file);
106108
if (IS_ERR(realfile))
107109
return PTR_ERR(realfile);
108110
ihold(sharedinode);
@@ -146,8 +148,14 @@ static ssize_t erofs_ishare_file_read_iter(struct kiocb *iocb,
146148
static int erofs_ishare_mmap(struct file *file, struct vm_area_struct *vma)
147149
{
148150
struct file *realfile = file->private_data;
151+
int err;
149152

150153
vma_set_file(vma, realfile);
154+
155+
err = security_mmap_backing_file(vma, realfile, file);
156+
if (err)
157+
return err;
158+
151159
return generic_file_readonly_mmap(file, vma);
152160
}
153161

fs/file_table.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ struct backing_file {
5050
struct path user_path;
5151
freeptr_t bf_freeptr;
5252
};
53+
#ifdef CONFIG_SECURITY
54+
void *security;
55+
#endif
5356
};
5457

5558
#define backing_file(f) container_of(f, struct backing_file, file)
@@ -66,8 +69,21 @@ void backing_file_set_user_path(struct file *f, const struct path *path)
6669
}
6770
EXPORT_SYMBOL_GPL(backing_file_set_user_path);
6871

72+
#ifdef CONFIG_SECURITY
73+
void *backing_file_security(const struct file *f)
74+
{
75+
return backing_file(f)->security;
76+
}
77+
78+
void backing_file_set_security(struct file *f, void *security)
79+
{
80+
backing_file(f)->security = security;
81+
}
82+
#endif /* CONFIG_SECURITY */
83+
6984
static inline void backing_file_free(struct backing_file *ff)
7085
{
86+
security_backing_file_free(&ff->file);
7187
path_put(&ff->user_path);
7288
kmem_cache_free(bfilp_cachep, ff);
7389
}
@@ -288,10 +304,12 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)
288304
return f;
289305
}
290306

291-
static int init_backing_file(struct backing_file *ff)
307+
static int init_backing_file(struct backing_file *ff,
308+
const struct file *user_file)
292309
{
293310
memset(&ff->user_path, 0, sizeof(ff->user_path));
294-
return 0;
311+
backing_file_set_security(&ff->file, NULL);
312+
return security_backing_file_alloc(&ff->file, user_file);
295313
}
296314

297315
/*
@@ -301,7 +319,8 @@ static int init_backing_file(struct backing_file *ff)
301319
* This is only for kernel internal use, and the allocate file must not be
302320
* installed into file tables or such.
303321
*/
304-
struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
322+
struct file *alloc_empty_backing_file(int flags, const struct cred *cred,
323+
const struct file *user_file)
305324
{
306325
struct backing_file *ff;
307326
int error;
@@ -318,7 +337,7 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
318337

319338
/* The f_mode flags must be set before fput(). */
320339
ff->file.f_mode |= FMODE_BACKING | FMODE_NOACCOUNT;
321-
error = init_backing_file(ff);
340+
error = init_backing_file(ff, user_file);
322341
if (unlikely(error)) {
323342
fput(&ff->file);
324343
return ERR_PTR(error);

fs/fuse/passthrough.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
167167
goto out;
168168

169169
/* Allocate backing file per fuse file to store fuse path */
170-
backing_file = backing_file_open(&file->f_path, file->f_flags,
170+
backing_file = backing_file_open(file, file->f_flags,
171171
&fb->file->f_path, fb->cred);
172172
err = PTR_ERR(backing_file);
173173
if (IS_ERR(backing_file)) {

fs/internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
106106
*/
107107
struct file *alloc_empty_file(int flags, const struct cred *cred);
108108
struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
109-
struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
109+
struct file *alloc_empty_backing_file(int flags, const struct cred *cred,
110+
const struct file *user_file);
110111
void backing_file_set_user_path(struct file *f, const struct path *path);
111112

112113
static inline void file_put_write_access(struct file *file)

fs/overlayfs/dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1374,7 +1374,7 @@ static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
13741374
return PTR_ERR(cred);
13751375

13761376
ovl_path_upper(dentry->d_parent, &realparentpath);
1377-
realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath,
1377+
realfile = backing_tmpfile_open(file, flags, &realparentpath,
13781378
mode, current_cred());
13791379
err = PTR_ERR_OR_ZERO(realfile);
13801380
pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err);

fs/overlayfs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static struct file *ovl_open_realfile(const struct file *file,
4848
if (!inode_owner_or_capable(real_idmap, realinode))
4949
flags &= ~O_NOATIME;
5050

51-
realfile = backing_file_open(file_user_path(file),
51+
realfile = backing_file_open(file,
5252
flags, realpath, current_cred());
5353
}
5454
}

include/linux/backing-file.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ struct backing_file_ctx {
1818
void (*end_write)(struct kiocb *iocb, ssize_t);
1919
};
2020

21-
struct file *backing_file_open(const struct path *user_path, int flags,
21+
struct file *backing_file_open(const struct file *user_file, int flags,
2222
const struct path *real_path,
2323
const struct cred *cred);
24-
struct file *backing_tmpfile_open(const struct path *user_path, int flags,
24+
struct file *backing_tmpfile_open(const struct file *user_file, int flags,
2525
const struct path *real_parentpath,
2626
umode_t mode, const struct cred *cred);
2727
ssize_t backing_file_read_iter(struct file *file, struct iov_iter *iter,

include/linux/fs.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2475,6 +2475,19 @@ struct file *dentry_create(struct path *path, int flags, umode_t mode,
24752475
const struct cred *cred);
24762476
const struct path *backing_file_user_path(const struct file *f);
24772477

2478+
#ifdef CONFIG_SECURITY
2479+
void *backing_file_security(const struct file *f);
2480+
void backing_file_set_security(struct file *f, void *security);
2481+
#else
2482+
static inline void *backing_file_security(const struct file *f)
2483+
{
2484+
return NULL;
2485+
}
2486+
static inline void backing_file_set_security(struct file *f, void *security)
2487+
{
2488+
}
2489+
#endif /* CONFIG_SECURITY */
2490+
24782491
/*
24792492
* When mmapping a file on a stackable filesystem (e.g., overlayfs), the file
24802493
* stored in ->vm_file is a backing file whose f_inode is on the underlying

include/linux/lsm_audit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct common_audit_data {
9494
#endif
9595
char *kmod_name;
9696
struct lsm_ioctlop_audit *op;
97-
struct file *file;
97+
const struct file *file;
9898
struct lsm_ibpkey_audit *ibpkey;
9999
struct lsm_ibendport_audit *ibendport;
100100
int reason;

0 commit comments

Comments
 (0)