ANDROID: ashmem: Add toggle to ignore requests to deny PROT_EXEC mappings

Memfd does not support preventing a file from being mapped with PROT_EXEC,
as ashmem does. It would be useful to expose a knob to userspace to
change ashmem's behavior to match memfd to see if any issues arise
during tests.

Therefore, expose a tunable that userspace can use to cause ashmem to
ignore requests to deny PROT_EXEC mappings.

Bug: 111903542
Change-Id: I3da63d899c4753aa704092bf8e8a2568500fa833
Signed-off-by: Isaac J. Manjarres <isaacmanjarres@google.com>
This commit is contained in:
Isaac J. Manjarres
2025-02-18 11:34:06 -08:00
parent ef10c0ef7d
commit b4fef39187

View File

@@ -108,13 +108,15 @@ static struct lock_class_key backing_shmem_inode_class;
static bool unpinning_enable = true;
/*
* memfd does not allow removing permissions to map a buffer with PROT_READ. This variable
* is exposed as a tunable so that it can be used to make ashmem behave more like memfd for
* test purposes.
* memfd does not allow removing permissions to map a buffer with PROT_READ or PROT_EXEC. These
* variables are exposed as tunables so that they can be used to make ashmem behave more like memfd
* for test purposes.
*
* It is set to false by default to retain compatibility with the original behavior of the driver.
* They are set to false by default to retain compatibility with the original behavior of the
* driver.
*/
static bool ignore_unset_prot_read;
static bool ignore_unset_prot_exec;
static inline unsigned long range_size(struct ashmem_range *range)
{
@@ -562,6 +564,10 @@ static int set_prot_mask(struct ashmem_area *asma, unsigned long prot)
if (ignore_unset_prot_read)
prot |= asma->prot_mask & PROT_READ;
/* Ensure the buffer can only be mapped with PROT_EXEC iff it has that permission. */
if (ignore_unset_prot_exec)
prot |= asma->prot_mask & PROT_EXEC;
/* the user can only remove, not add, protection bits */
if ((asma->prot_mask & prot) != prot) {
ret = -EINVAL;
@@ -953,6 +959,12 @@ static int ignore_unset_prot_read_open(struct inode *inode, struct file *file)
return 0;
}
static int ignore_unset_prot_exec_open(struct inode *inode, struct file *file)
{
file->private_data = &ignore_unset_prot_exec;
return 0;
}
static ssize_t attr_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
bool *attrp = file->private_data;
@@ -1019,6 +1031,13 @@ static const struct file_operations ignore_unset_prot_read_fops = {
.write = attr_write,
};
static const struct file_operations ignore_unset_prot_exec_fops = {
.owner = THIS_MODULE,
.open = ignore_unset_prot_exec_open,
.read= attr_read,
.write = attr_write,
};
static struct miscdevice ashmem_miscs[] = {
{
.minor = MISC_DYNAMIC_MINOR,
@@ -1035,6 +1054,11 @@ static struct miscdevice ashmem_miscs[] = {
.name = "ashmem_ignore_unset_prot_read",
.fops = &ignore_unset_prot_read_fops,
},
{
.minor = MISC_DYNAMIC_MINOR,
.name = "ashmem_ignore_unset_prot_exec",
.fops = &ignore_unset_prot_exec_fops,
},
};
static int __init ashmem_init(void)