Skip to content

mac: allow policies to restrict vnode-backed mmap max_prot#2191

Open
mcoelho80 wants to merge 1 commit into
freebsd:mainfrom
mcoelho80:mac-mmap-maxprot-downgrade
Open

mac: allow policies to restrict vnode-backed mmap max_prot#2191
mcoelho80 wants to merge 1 commit into
freebsd:mainfrom
mcoelho80:mac-mmap-maxprot-downgrade

Conversation

@mcoelho80
Copy link
Copy Markdown

For vnode-backed mappings, MAC policies currently get a chance to check the protection requested by mmap(2). However, a mapping created without PROT_EXEC may still retain VM_PROT_EXECUTE in max_prot and later be upgraded with mprotect(PROT_EXEC):

fd = open(path, O_RDONLY);
addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
mprotect(addr, len, PROT_READ | PROT_EXEC);

At mprotect(2) time, the VM layer no longer has the same vnode context that was available during mmap(2). As a result, a MAC policy that intends to prevent executable mappings from a given vnode may be bypassed by first creating a non-executable mapping and then upgrading it later.

Without this enforcement point, the MAC framework does not provide policy authors with a complete mechanism to enforce vnode-based executable mapping restrictions. This can make a policy look correct while leaving a bypass path open.

Let MAC policies reduce max_prot during the vnode-backed mmap path, while the vnode is still available. This allows a policy to remove VM_PROT_EXECUTE from max_prot, causing a later mprotect(PROT_EXEC) to fail naturally in the VM layer.

If the reduced max_prot no longer contains the protection requested for the initial mmap, fail the mmap with EACCES.

This does not change behavior for policies that do not implement the downgrade hook.

For vnode-backed mappings, MAC policies currently get a chance to
check the protection requested by mmap(2). However, a mapping created
without PROT_EXEC may still retain VM_PROT_EXECUTE in max_prot and later
be upgraded with mprotect(PROT_EXEC):

	fd = open(path, O_RDONLY);
	addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
	mprotect(addr, len, PROT_READ | PROT_EXEC);

At mprotect(2) time, the VM layer no longer has the same vnode context
that was available during mmap(2). As a result, a MAC policy that intends
to prevent executable mappings from a given vnode may be bypassed by
first creating a non-executable mapping and then upgrading it later.

Without this enforcement point, the MAC framework does not provide policy
authors with a complete mechanism to enforce vnode-based executable
mapping restrictions. This can make a policy look correct while leaving a
bypass path open.

Let MAC policies reduce max_prot during the vnode-backed mmap path,
while the vnode is still available. This allows a policy to remove
VM_PROT_EXECUTE from max_prot, causing a later mprotect(PROT_EXEC) to
fail naturally in the VM layer.

If the reduced max_prot no longer contains the protection requested for
the initial mmap, fail the mmap with EACCES.

This does not change behavior for policies that do not implement the
downgrade hook.

Signed-off-by: Marcelo Coelho <mcoelho80@hotmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant