Skip to content

Commit ddebbe5

Browse files
committed
Merge pull request #11358 from Snowflake-Labs:xuzhoyin-mmap-fix
PiperOrigin-RevId: 720973349
2 parents 63c9278 + 191b53d commit ddebbe5

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

pkg/sentry/syscalls/linux/sys_mmap.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ func Mmap(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *
9898
opts.MaxPerms.Write = false
9999
}
100100

101+
// mmap requires volume NO_EXEC be false if request has PROT_EXEC flag.
102+
if file.Mount().MountFlags()&linux.ST_NOEXEC != 0 {
103+
if opts.Perms.Execute {
104+
return 0, nil, linuxerr.EPERM
105+
}
106+
107+
opts.MaxPerms.Execute = false
108+
}
109+
101110
if err := file.ConfigureMMap(t, &opts); err != nil {
102111
return 0, nil, err
103112
}

test/syscalls/linux/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,7 @@ cc_binary(
14321432
"//test/util:file_descriptor",
14331433
"//test/util:fs_util",
14341434
"//test/util:logging",
1435+
"//test/util:memory_util",
14351436
"//test/util:mount_util",
14361437
"//test/util:multiprocess_util",
14371438
"//test/util:posix_error",

test/syscalls/linux/mount.cc

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "test/util/fs_util.h"
6363
#include "test/util/linux_capability_util.h"
6464
#include "test/util/logging.h"
65+
#include "test/util/memory_util.h"
6566
#include "test/util/mount_util.h"
6667
#include "test/util/multiprocess_util.h"
6768
#include "test/util/posix_error.h"
@@ -252,6 +253,83 @@ TEST(MountTest, UmountDetach) {
252253
OpenAt(mounted_dir.get(), "..", O_DIRECTORY | O_RDONLY));
253254
}
254255

256+
TEST(MountTest, MMapWithExecProtFailsOnNoExecFile) {
257+
// Skips the test if test does not have needed capability to create the volume
258+
// mount.
259+
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
260+
261+
auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
262+
auto ret = ASSERT_NO_ERRNO_AND_VALUE(
263+
Mount("", dir.path(), kTmpfs, MS_NOEXEC, "", 0));
264+
auto file = ASSERT_NO_ERRNO_AND_VALUE(
265+
TempPath::CreateFileWith(dir.path(), "random1", 0777));
266+
267+
FileDescriptor fd =
268+
ASSERT_NO_ERRNO_AND_VALUE(Open(file.path().c_str(), O_RDWR));
269+
ASSERT_THAT(reinterpret_cast<uintptr_t>(
270+
mmap(0, kPageSize, PROT_EXEC, MAP_PRIVATE, fd.get(), 0)),
271+
SyscallFailsWithErrno(EPERM));
272+
}
273+
274+
TEST(MountTest, MMapWithExecProtSucceedsOnExecutableVolumeFile) {
275+
// Capability is needed to create tmpfs.
276+
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
277+
278+
auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
279+
auto ret = ASSERT_NO_ERRNO_AND_VALUE(Mount("", dir.path(), kTmpfs, 0, "", 0));
280+
auto file = ASSERT_NO_ERRNO_AND_VALUE(
281+
TempPath::CreateFileWith(dir.path(), "random1", 0777));
282+
283+
FileDescriptor fd =
284+
ASSERT_NO_ERRNO_AND_VALUE(Open(file.path().c_str(), O_RDWR));
285+
286+
void* address = mmap(0, kPageSize, PROT_EXEC, MAP_PRIVATE, fd.get(), 0);
287+
EXPECT_NE(address, MAP_FAILED);
288+
289+
MunmapSafe(address, kPageSize);
290+
}
291+
292+
TEST(MountTest, MMapWithoutNoExecProtSucceedsOnNoExecFile) {
293+
// Capability is needed to create tmpfs.
294+
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
295+
296+
auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
297+
auto ret = ASSERT_NO_ERRNO_AND_VALUE(
298+
Mount("", dir.path(), kTmpfs, MS_NOEXEC, "", 0));
299+
auto file = ASSERT_NO_ERRNO_AND_VALUE(
300+
TempPath::CreateFileWith(dir.path(), "random1", 0777));
301+
FileDescriptor fd =
302+
ASSERT_NO_ERRNO_AND_VALUE(Open(file.path().c_str(), O_RDWR));
303+
304+
void* address =
305+
mmap(0, kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd.get(), 0);
306+
EXPECT_NE(address, MAP_FAILED);
307+
308+
MunmapSafe(address, kPageSize);
309+
}
310+
311+
TEST(MountTest, MProtectWithNoExecProtFailsOnNoExecFile) {
312+
// Capability is needed to create tmpfs.
313+
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
314+
315+
auto const dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
316+
auto ret = ASSERT_NO_ERRNO_AND_VALUE(
317+
Mount("", dir.path(), kTmpfs, MS_NOEXEC, "", 0));
318+
auto file = ASSERT_NO_ERRNO_AND_VALUE(
319+
TempPath::CreateFileWith(dir.path(), "random1", 0777));
320+
FileDescriptor fd =
321+
ASSERT_NO_ERRNO_AND_VALUE(Open(file.path().c_str(), O_RDWR));
322+
323+
void* address =
324+
mmap(0, kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd.get(), 0);
325+
EXPECT_NE(address, MAP_FAILED);
326+
327+
ASSERT_THAT(mprotect(address, kPageSize, PROT_EXEC),
328+
SyscallFailsWithErrno(EACCES));
329+
330+
MunmapSafe(address, kPageSize);
331+
}
332+
255333
TEST(MountTest, UmountMountsStackedOnDot) {
256334
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN)));
257335
// Verify that unmounting at "." properly unmounts the mount at the top of

0 commit comments

Comments
 (0)