diff options
author | Steffen Kieß <kiess@ki4.de> | 2019-10-09 21:49:14 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-10-09 21:49:14 +0300 |
commit | 30886f997fa4fbcd7e7cc585dfd2109941f139c4 (patch) | |
tree | e63b714249cf4e0c917c1d485a1ed777b56e9042 /mcs/class/Mono.Posix | |
parent | 1cf081529e5e37dd9472f7c7b0d0ead659e9b54f (diff) |
[Mono.Posix] Add support for memfd_create() and file sealing (#17225)
* [Mono.Posix] Add support for memfd_create() and file sealing
Add the linux syscall memfd_create() and add support for file sealing with
fcntl().
* Bump API snapshot submodule
Diffstat (limited to 'mcs/class/Mono.Posix')
4 files changed, 214 insertions, 0 deletions
diff --git a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources index 5aee212abe7..c41a3a8f2bf 100644 --- a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources +++ b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources @@ -9,6 +9,7 @@ Mono.Unix/UnixPathTest.cs Mono.Unix/UnixSignalTest.cs Mono.Unix/UnixUserTest.cs Mono.Unix.Android/TestHelper.cs +Mono.Unix.Native/MemfdTest.cs Mono.Unix.Native/OFDLockTest.cs Mono.Unix.Native/RealTimeSignumTests.cs Mono.Unix.Native/SocketTest.cs diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs b/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs index cf538806236..816b1f76729 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs @@ -438,6 +438,38 @@ namespace Mono.Unix.Native { return rval; } + [DllImport (LIB, EntryPoint="Mono_Posix_FromMemfdFlags")] + private static extern int FromMemfdFlags (MemfdFlags value, out UInt32 rval); + + public static bool TryFromMemfdFlags (MemfdFlags value, out UInt32 rval) + { + return FromMemfdFlags (value, out rval) == 0; + } + + public static UInt32 FromMemfdFlags (MemfdFlags value) + { + UInt32 rval; + if (FromMemfdFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMemfdFlags")] + private static extern int ToMemfdFlags (UInt32 value, out MemfdFlags rval); + + public static bool TryToMemfdFlags (UInt32 value, out MemfdFlags rval) + { + return ToMemfdFlags (value, out rval) == 0; + } + + public static MemfdFlags ToMemfdFlags (UInt32 value) + { + MemfdFlags rval; + if (ToMemfdFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + [DllImport (LIB, EntryPoint="Mono_Posix_FromMessageFlags")] private static extern int FromMessageFlags (MessageFlags value, out Int32 rval); @@ -806,6 +838,38 @@ namespace Mono.Unix.Native { return rval; } + [DllImport (LIB, EntryPoint="Mono_Posix_FromSealType")] + private static extern int FromSealType (SealType value, out Int32 rval); + + public static bool TryFromSealType (SealType value, out Int32 rval) + { + return FromSealType (value, out rval) == 0; + } + + public static Int32 FromSealType (SealType value) + { + Int32 rval; + if (FromSealType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSealType")] + private static extern int ToSealType (Int32 value, out SealType rval); + + public static bool TryToSealType (Int32 value, out SealType rval) + { + return ToSealType (value, out rval) == 0; + } + + public static SealType ToSealType (Int32 value) + { + SealType rval; + if (ToSealType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + [DllImport (LIB, EntryPoint="Mono_Posix_FromSeekFlags")] private static extern int FromSeekFlags (SeekFlags value, out Int16 rval); diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs index e4f2b58e19a..c5189618063 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs @@ -231,6 +231,8 @@ namespace Mono.Unix.Native { F_SETLEASE = 1024, // Set a lease. F_GETLEASE = 1025, // Enquire what lease is active. F_NOTIFY = 1026, // Required notifications on a directory + F_ADD_SEALS = 1033, // Add seals. + F_GET_SEALS = 1034, // Get seals. } [Map] @@ -241,6 +243,16 @@ namespace Mono.Unix.Native { F_UNLCK = 2, // Remove lock. } + [Flags][Map] + [CLSCompliant (false)] + public enum SealType : int { + F_SEAL_SEAL = 0x0001, // prevent further seals from being set + F_SEAL_SHRINK = 0x0002, // prevent file from shrinking + F_SEAL_GROW = 0x0004, // prevent file from growing + F_SEAL_WRITE = 0x0008, // prevent writes + F_SEAL_FUTURE_WRITE = 0x0010, // prevent future writes while mapped + } + [Map] [CLSCompliant (false)] public enum SeekFlags : short { @@ -733,6 +745,26 @@ namespace Mono.Unix.Native { MREMAP_MAYMOVE = 0x1, } + [Map][Flags] + [CLSCompliant (false)] + public enum MemfdFlags : uint { + MFD_CLOEXEC = 0x00000001, + MFD_ALLOW_SEALING = 0x00000002, + MFD_HUGETLB = 0x00000004, + MFD_HUGE_64KB = 0x40000000, + MFD_HUGE_512KB = 0x4c000000, + MFD_HUGE_1MB = 0x50000000, + MFD_HUGE_2MB = 0x54000000, + MFD_HUGE_8MB = 0x5c000000, + MFD_HUGE_16MB = 0x60000000, + MFD_HUGE_32MB = 0x64000000, + MFD_HUGE_256MB = 0x70000000, + MFD_HUGE_512MB = 0x74000000, + MFD_HUGE_1GB = 0x78000000, + MFD_HUGE_2GB = 0x7c000000, + MFD_HUGE_16GB = 0x88000000, + } + [Map] [CLSCompliant (false)] public enum UnixSocketType : int { @@ -3021,6 +3053,12 @@ namespace Mono.Unix.Native { return fcntl (fd, FcntlCommand.F_NOTIFY, _arg); } + public static int fcntl (int fd, FcntlCommand cmd, SealType arg) + { + int _arg = NativeConvert.FromSealType (arg); + return fcntl (fd, cmd, _arg); + } + [DllImport (MPH, SetLastError=true, EntryPoint="Mono_Posix_Syscall_fcntl_lock")] public static extern int fcntl (int fd, FcntlCommand cmd, ref Flock @lock); @@ -3857,6 +3895,19 @@ namespace Mono.Unix.Native { public static extern int remap_file_pages (IntPtr start, ulong size, MmapProts prot, long pgoff, MmapFlags flags); + // memfd_create(2) + // int memfd_create(const char *name, unsigned int flags); + [DllImport (LIBC, SetLastError=true, EntryPoint="memfd_create")] + private static extern int sys_memfd_create ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, uint flags); + + public static int memfd_create (string name, MemfdFlags flags) + { + uint _flags = NativeConvert.FromMemfdFlags (flags); + return sys_memfd_create (name, _flags); + } + #endregion #region <sys/poll.h> Declarations diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/MemfdTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/MemfdTest.cs new file mode 100644 index 00000000000..91fdd019e2d --- /dev/null +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/MemfdTest.cs @@ -0,0 +1,98 @@ +// +// Tests for memfd_create and file sealing +// +// Authors: +// Steffen Kiess (kiess@ki4.de) +// +// Copyright (C) 2019 Steffen Kiess +// + +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; + +using Mono.Unix; +using Mono.Unix.Native; + +using NUnit.Framework; + +namespace MonoTests.Mono.Unix.Native +{ + [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows"), Category ("NotOnMac")] + public class MemfdTest { + [Test] + public unsafe void TestMemfd () + { + int fd; + try { + fd = Syscall.memfd_create ("mono-test", 0); + } catch (EntryPointNotFoundException) { + Assert.Ignore ("memfd_create() not available"); + return; + } + if (fd < 0 && Stdlib.GetLastError () == Errno.ENOSYS) + // Might happen on a new libc + old kernel + Assert.Ignore ("memfd_create() returns ENOSYS"); + if (fd < 0) + UnixMarshal.ThrowExceptionForLastError (); + + byte b = 42; + if (Syscall.write (fd, &b, 1) < 0) + UnixMarshal.ThrowExceptionForLastError (); + + // Should fail with EPERM because MFD_ALLOW_SEALING was not used + var res = Syscall.fcntl(fd, FcntlCommand.F_ADD_SEALS, SealType.F_SEAL_WRITE); + Assert.AreEqual (-1, res); + Assert.AreEqual (Errno.EPERM, Stdlib.GetLastError ()); + + //Stdlib.system ("ls -l /proc/$PPID/fd/"); + + if (Syscall.close (fd) < 0) + UnixMarshal.ThrowExceptionForLastError (); + + // Call memfd_create with MFD_ALLOW_SEALING + fd = Syscall.memfd_create ("mono-test", MemfdFlags.MFD_CLOEXEC | MemfdFlags.MFD_ALLOW_SEALING); + if (fd < 0) + UnixMarshal.ThrowExceptionForLastError (); + + if (Syscall.write (fd, &b, 1) < 0) + UnixMarshal.ThrowExceptionForLastError (); + + res = Syscall.fcntl(fd, FcntlCommand.F_GET_SEALS); + if (res < 0) + UnixMarshal.ThrowExceptionForLastError (); + // Need to convert the result to SealType + SealType sealType = NativeConvert.ToSealType (res); + Assert.AreEqual ((SealType)0, sealType); + + if (Syscall.fcntl(fd, FcntlCommand.F_ADD_SEALS, SealType.F_SEAL_WRITE) < 0) + UnixMarshal.ThrowExceptionForLastError (); + + // Should fail with EPERM because the file was sealed for writing + var lres = Syscall.write (fd, &b, 1); + Assert.AreEqual (-1, lres); + Assert.AreEqual (Errno.EPERM, Stdlib.GetLastError ()); + + res = Syscall.fcntl(fd, FcntlCommand.F_GET_SEALS); + if (res < 0) + UnixMarshal.ThrowExceptionForLastError (); + // Need to convert the result to SealType + sealType = NativeConvert.ToSealType (res); + Assert.AreEqual (SealType.F_SEAL_WRITE, sealType); + + //Stdlib.system ("ls -l /proc/$PPID/fd/"); + + if (Syscall.close (fd) < 0) + UnixMarshal.ThrowExceptionForLastError (); + } + } +} + +// vim: noexpandtab +// Local Variables: +// tab-width: 4 +// c-basic-offset: 4 +// indent-tabs-mode: t +// End: |