162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/init.h>
362306a36Sopenharmony_ci#include <linux/mm.h>
462306a36Sopenharmony_ci#include <linux/security.h>
562306a36Sopenharmony_ci#include <linux/sysctl.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/* amount of vm to protect from userspace access by both DAC and the LSM*/
862306a36Sopenharmony_ciunsigned long mmap_min_addr;
962306a36Sopenharmony_ci/* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
1062306a36Sopenharmony_ciunsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
1162306a36Sopenharmony_ci/* amount of vm to protect from userspace using the LSM = CONFIG_LSM_MMAP_MIN_ADDR */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * Update mmap_min_addr = max(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR)
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_cistatic void update_mmap_min_addr(void)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci#ifdef CONFIG_LSM_MMAP_MIN_ADDR
1962306a36Sopenharmony_ci	if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR)
2062306a36Sopenharmony_ci		mmap_min_addr = dac_mmap_min_addr;
2162306a36Sopenharmony_ci	else
2262306a36Sopenharmony_ci		mmap_min_addr = CONFIG_LSM_MMAP_MIN_ADDR;
2362306a36Sopenharmony_ci#else
2462306a36Sopenharmony_ci	mmap_min_addr = dac_mmap_min_addr;
2562306a36Sopenharmony_ci#endif
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * sysctl handler which just sets dac_mmap_min_addr = the new value and then
3062306a36Sopenharmony_ci * calls update_mmap_min_addr() so non MAP_FIXED hints get rounded properly
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ciint mmap_min_addr_handler(struct ctl_table *table, int write,
3362306a36Sopenharmony_ci			  void *buffer, size_t *lenp, loff_t *ppos)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	int ret;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (write && !capable(CAP_SYS_RAWIO))
3862306a36Sopenharmony_ci		return -EPERM;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	update_mmap_min_addr();
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return ret;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int __init init_mmap_min_addr(void)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	update_mmap_min_addr();
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_cipure_initcall(init_mmap_min_addr);
54