Skip to content

Commit 82544d3

Browse files
committed
selinux: fix overlayfs mmap() and mprotect() access checks
The existing SELinux security model for overlayfs is to allow access if the current task is able to access the top level file (the "user" file) and the mounter's credentials are sufficient to access the lower level file (the "backing" file). Unfortunately, the current code does not properly enforce these access controls for both mmap() and mprotect() operations on overlayfs filesystems. This patch makes use of the newly created security_mmap_backing_file() LSM hook to provide the missing backing file enforcement for mmap() operations, and leverages the backing file API and new LSM blob to provide the necessary information to properly enforce the mprotect() access controls. Cc: stable@vger.kernel.org Acked-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
1 parent 6af36ae commit 82544d3

2 files changed

Lines changed: 189 additions & 64 deletions

File tree

security/selinux/hooks.c

Lines changed: 178 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,49 +1745,72 @@ static inline int file_path_has_perm(const struct cred *cred,
17451745
static int bpf_fd_pass(const struct file *file, u32 sid);
17461746
#endif
17471747

1748-
/* Check whether a task can use an open file descriptor to
1749-
access an inode in a given way. Check access to the
1750-
descriptor itself, and then use dentry_has_perm to
1751-
check a particular permission to the file.
1752-
Access to the descriptor is implicitly granted if it
1753-
has the same SID as the process. If av is zero, then
1754-
access to the file is not checked, e.g. for cases
1755-
where only the descriptor is affected like seek. */
1756-
static int file_has_perm(const struct cred *cred,
1757-
struct file *file,
1758-
u32 av)
1748+
static int __file_has_perm(const struct cred *cred, const struct file *file,
1749+
u32 av, bool bf_user_file)
1750+
17591751
{
1760-
struct file_security_struct *fsec = selinux_file(file);
1761-
struct inode *inode = file_inode(file);
17621752
struct common_audit_data ad;
1763-
u32 sid = cred_sid(cred);
1753+
struct inode *inode;
1754+
u32 ssid = cred_sid(cred);
1755+
u32 tsid_fd;
17641756
int rc;
17651757

1766-
ad.type = LSM_AUDIT_DATA_FILE;
1767-
ad.u.file = file;
1758+
if (bf_user_file) {
1759+
struct backing_file_security_struct *bfsec;
1760+
const struct path *path;
17681761

1769-
if (sid != fsec->sid) {
1770-
rc = avc_has_perm(sid, fsec->sid,
1771-
SECCLASS_FD,
1772-
FD__USE,
1773-
&ad);
1762+
if (WARN_ON(!(file->f_mode & FMODE_BACKING)))
1763+
return -EIO;
1764+
1765+
bfsec = selinux_backing_file(file);
1766+
path = backing_file_user_path(file);
1767+
tsid_fd = bfsec->uf_sid;
1768+
inode = d_inode(path->dentry);
1769+
1770+
ad.type = LSM_AUDIT_DATA_PATH;
1771+
ad.u.path = *path;
1772+
} else {
1773+
struct file_security_struct *fsec = selinux_file(file);
1774+
1775+
tsid_fd = fsec->sid;
1776+
inode = file_inode(file);
1777+
1778+
ad.type = LSM_AUDIT_DATA_FILE;
1779+
ad.u.file = file;
1780+
}
1781+
1782+
if (ssid != tsid_fd) {
1783+
rc = avc_has_perm(ssid, tsid_fd, SECCLASS_FD, FD__USE, &ad);
17741784
if (rc)
1775-
goto out;
1785+
return rc;
17761786
}
17771787

17781788
#ifdef CONFIG_BPF_SYSCALL
1779-
rc = bpf_fd_pass(file, cred_sid(cred));
1789+
/* regardless of backing vs user file, use the underlying file here */
1790+
rc = bpf_fd_pass(file, ssid);
17801791
if (rc)
17811792
return rc;
17821793
#endif
17831794

17841795
/* av is zero if only checking access to the descriptor. */
1785-
rc = 0;
17861796
if (av)
1787-
rc = inode_has_perm(cred, inode, av, &ad);
1797+
return inode_has_perm(cred, inode, av, &ad);
17881798

1789-
out:
1790-
return rc;
1799+
return 0;
1800+
}
1801+
1802+
/* Check whether a task can use an open file descriptor to
1803+
access an inode in a given way. Check access to the
1804+
descriptor itself, and then use dentry_has_perm to
1805+
check a particular permission to the file.
1806+
Access to the descriptor is implicitly granted if it
1807+
has the same SID as the process. If av is zero, then
1808+
access to the file is not checked, e.g. for cases
1809+
where only the descriptor is affected like seek. */
1810+
static inline int file_has_perm(const struct cred *cred,
1811+
const struct file *file, u32 av)
1812+
{
1813+
return __file_has_perm(cred, file, av, false);
17911814
}
17921815

17931816
/*
@@ -3825,6 +3848,17 @@ static int selinux_file_alloc_security(struct file *file)
38253848
return 0;
38263849
}
38273850

3851+
static int selinux_backing_file_alloc(struct file *backing_file,
3852+
const struct file *user_file)
3853+
{
3854+
struct backing_file_security_struct *bfsec;
3855+
3856+
bfsec = selinux_backing_file(backing_file);
3857+
bfsec->uf_sid = selinux_file(user_file)->sid;
3858+
3859+
return 0;
3860+
}
3861+
38283862
/*
38293863
* Check whether a task has the ioctl permission and cmd
38303864
* operation to an inode.
@@ -3942,42 +3976,55 @@ static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd,
39423976

39433977
static int default_noexec __ro_after_init;
39443978

3945-
static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
3979+
static int __file_map_prot_check(const struct cred *cred,
3980+
const struct file *file, unsigned long prot,
3981+
bool shared, bool bf_user_file)
39463982
{
3947-
const struct cred *cred = current_cred();
3948-
u32 sid = cred_sid(cred);
3949-
int rc = 0;
3983+
struct inode *inode = NULL;
3984+
bool prot_exec = prot & PROT_EXEC;
3985+
bool prot_write = prot & PROT_WRITE;
3986+
3987+
if (file) {
3988+
if (bf_user_file)
3989+
inode = d_inode(backing_file_user_path(file)->dentry);
3990+
else
3991+
inode = file_inode(file);
3992+
}
3993+
3994+
if (default_noexec && prot_exec &&
3995+
(!file || IS_PRIVATE(inode) || (!shared && prot_write))) {
3996+
int rc;
3997+
u32 sid = cred_sid(cred);
39503998

3951-
if (default_noexec &&
3952-
(prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
3953-
(!shared && (prot & PROT_WRITE)))) {
39543999
/*
3955-
* We are making executable an anonymous mapping or a
3956-
* private file mapping that will also be writable.
3957-
* This has an additional check.
4000+
* We are making executable an anonymous mapping or a private
4001+
* file mapping that will also be writable.
39584002
*/
3959-
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
3960-
PROCESS__EXECMEM, NULL);
4003+
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__EXECMEM,
4004+
NULL);
39614005
if (rc)
3962-
goto error;
4006+
return rc;
39634007
}
39644008

39654009
if (file) {
3966-
/* read access is always possible with a mapping */
4010+
/* "read" always possible, "write" only if shared */
39674011
u32 av = FILE__READ;
3968-
3969-
/* write access only matters if the mapping is shared */
3970-
if (shared && (prot & PROT_WRITE))
4012+
if (shared && prot_write)
39714013
av |= FILE__WRITE;
3972-
3973-
if (prot & PROT_EXEC)
4014+
if (prot_exec)
39744015
av |= FILE__EXECUTE;
39754016

3976-
return file_has_perm(cred, file, av);
4017+
return __file_has_perm(cred, file, av, bf_user_file);
39774018
}
39784019

3979-
error:
3980-
return rc;
4020+
return 0;
4021+
}
4022+
4023+
static inline int file_map_prot_check(const struct cred *cred,
4024+
const struct file *file,
4025+
unsigned long prot, bool shared)
4026+
{
4027+
return __file_map_prot_check(cred, file, prot, shared, false);
39814028
}
39824029

39834030
static int selinux_mmap_addr(unsigned long addr)
@@ -3993,36 +4040,80 @@ static int selinux_mmap_addr(unsigned long addr)
39934040
return rc;
39944041
}
39954042

3996-
static int selinux_mmap_file(struct file *file,
3997-
unsigned long reqprot __always_unused,
3998-
unsigned long prot, unsigned long flags)
4043+
static int selinux_mmap_file_common(const struct cred *cred, struct file *file,
4044+
unsigned long prot, bool shared)
39994045
{
4000-
struct common_audit_data ad;
4001-
int rc;
4002-
40034046
if (file) {
4047+
int rc;
4048+
struct common_audit_data ad;
4049+
40044050
ad.type = LSM_AUDIT_DATA_FILE;
40054051
ad.u.file = file;
4006-
rc = inode_has_perm(current_cred(), file_inode(file),
4007-
FILE__MAP, &ad);
4052+
rc = inode_has_perm(cred, file_inode(file), FILE__MAP, &ad);
40084053
if (rc)
40094054
return rc;
40104055
}
40114056

4012-
return file_map_prot_check(file, prot,
4013-
(flags & MAP_TYPE) == MAP_SHARED);
4057+
return file_map_prot_check(cred, file, prot, shared);
4058+
}
4059+
4060+
static int selinux_mmap_file(struct file *file,
4061+
unsigned long reqprot __always_unused,
4062+
unsigned long prot, unsigned long flags)
4063+
{
4064+
return selinux_mmap_file_common(current_cred(), file, prot,
4065+
(flags & MAP_TYPE) == MAP_SHARED);
4066+
}
4067+
4068+
/**
4069+
* selinux_mmap_backing_file - Check mmap permissions on a backing file
4070+
* @vma: memory region
4071+
* @backing_file: stacked filesystem backing file
4072+
* @user_file: user visible file
4073+
*
4074+
* This is called after selinux_mmap_file() on stacked filesystems, and it
4075+
* is this function's responsibility to verify access to @backing_file and
4076+
* setup the SELinux state for possible later use in the mprotect() code path.
4077+
*
4078+
* By the time this function is called, mmap() access to @user_file has already
4079+
* been authorized and @vma->vm_file has been set to point to @backing_file.
4080+
*
4081+
* Return zero on success, negative values otherwise.
4082+
*/
4083+
static int selinux_mmap_backing_file(struct vm_area_struct *vma,
4084+
struct file *backing_file,
4085+
struct file *user_file __always_unused)
4086+
{
4087+
unsigned long prot = 0;
4088+
4089+
/* translate vma->vm_flags perms into PROT perms */
4090+
if (vma->vm_flags & VM_READ)
4091+
prot |= PROT_READ;
4092+
if (vma->vm_flags & VM_WRITE)
4093+
prot |= PROT_WRITE;
4094+
if (vma->vm_flags & VM_EXEC)
4095+
prot |= PROT_EXEC;
4096+
4097+
return selinux_mmap_file_common(backing_file->f_cred, backing_file,
4098+
prot, vma->vm_flags & VM_SHARED);
40144099
}
40154100

40164101
static int selinux_file_mprotect(struct vm_area_struct *vma,
40174102
unsigned long reqprot __always_unused,
40184103
unsigned long prot)
40194104
{
4105+
int rc;
40204106
const struct cred *cred = current_cred();
40214107
u32 sid = cred_sid(cred);
4108+
const struct file *file = vma->vm_file;
4109+
bool backing_file;
4110+
bool shared = vma->vm_flags & VM_SHARED;
4111+
4112+
/* check if we need to trigger the "backing files are awful" mode */
4113+
backing_file = file && (file->f_mode & FMODE_BACKING);
40224114

40234115
if (default_noexec &&
40244116
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
4025-
int rc = 0;
40264117
/*
40274118
* We don't use the vma_is_initial_heap() helper as it has
40284119
* a history of problems and is currently broken on systems
@@ -4036,25 +4127,45 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
40364127
vma->vm_end <= vma->vm_mm->brk) {
40374128
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
40384129
PROCESS__EXECHEAP, NULL);
4039-
} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
4130+
if (rc)
4131+
return rc;
4132+
} else if (!file && (vma_is_initial_stack(vma) ||
40404133
vma_is_stack_for_current(vma))) {
40414134
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
40424135
PROCESS__EXECSTACK, NULL);
4043-
} else if (vma->vm_file && vma->anon_vma) {
4136+
if (rc)
4137+
return rc;
4138+
} else if (file && vma->anon_vma) {
40444139
/*
40454140
* We are making executable a file mapping that has
40464141
* had some COW done. Since pages might have been
40474142
* written, check ability to execute the possibly
40484143
* modified content. This typically should only
40494144
* occur for text relocations.
40504145
*/
4051-
rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
4146+
rc = __file_has_perm(cred, file, FILE__EXECMOD,
4147+
backing_file);
4148+
if (rc)
4149+
return rc;
4150+
if (backing_file) {
4151+
rc = file_has_perm(file->f_cred, file,
4152+
FILE__EXECMOD);
4153+
if (rc)
4154+
return rc;
4155+
}
40524156
}
4157+
}
4158+
4159+
rc = __file_map_prot_check(cred, file, prot, shared, backing_file);
4160+
if (rc)
4161+
return rc;
4162+
if (backing_file) {
4163+
rc = file_map_prot_check(file->f_cred, file, prot, shared);
40534164
if (rc)
40544165
return rc;
40554166
}
40564167

4057-
return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
4168+
return 0;
40584169
}
40594170

40604171
static int selinux_file_lock(struct file *file, unsigned int cmd)
@@ -7393,6 +7504,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
73937504
.lbs_cred = sizeof(struct cred_security_struct),
73947505
.lbs_task = sizeof(struct task_security_struct),
73957506
.lbs_file = sizeof(struct file_security_struct),
7507+
.lbs_backing_file = sizeof(struct backing_file_security_struct),
73967508
.lbs_inode = sizeof(struct inode_security_struct),
73977509
.lbs_ipc = sizeof(struct ipc_security_struct),
73987510
.lbs_key = sizeof(struct key_security_struct),
@@ -7498,9 +7610,11 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
74987610

74997611
LSM_HOOK_INIT(file_permission, selinux_file_permission),
75007612
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
7613+
LSM_HOOK_INIT(backing_file_alloc, selinux_backing_file_alloc),
75017614
LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
75027615
LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
75037616
LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
7617+
LSM_HOOK_INIT(mmap_backing_file, selinux_mmap_backing_file),
75047618
LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
75057619
LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
75067620
LSM_HOOK_INIT(file_lock, selinux_file_lock),

security/selinux/include/objsec.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ struct file_security_struct {
8888
u32 pseqno; /* Policy seqno at the time of file open */
8989
};
9090

91+
struct backing_file_security_struct {
92+
u32 uf_sid; /* associated user file fsec->sid */
93+
};
94+
9195
struct superblock_security_struct {
9296
u32 sid; /* SID of file system superblock */
9397
u32 def_sid; /* default SID for labeling */
@@ -195,6 +199,13 @@ static inline struct file_security_struct *selinux_file(const struct file *file)
195199
return file->f_security + selinux_blob_sizes.lbs_file;
196200
}
197201

202+
static inline struct backing_file_security_struct *
203+
selinux_backing_file(const struct file *backing_file)
204+
{
205+
void *blob = backing_file_security(backing_file);
206+
return blob + selinux_blob_sizes.lbs_backing_file;
207+
}
208+
198209
static inline struct inode_security_struct *
199210
selinux_inode(const struct inode *inode)
200211
{

0 commit comments

Comments
 (0)