This is an automated email from the ASF dual-hosted git repository.

gilbert pushed a commit to branch 1.6.x
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 620bf29c611caaa633c5f39c71d296e07621d5aa
Author: Jie Yu <[email protected]>
AuthorDate: Mon Feb 11 12:51:19 2019 -0800

    Added Linux memfd support.
    
    This patch adds the memfd support to allow us to copy a regular file
    into a sealed memfd. This can be useful when one wants to protect a file
    from being overwritten.
    
    Review: https://reviews.apache.org/r/69943/
    (cherry picked from commit e4ac39b123c892ec2593381918600c260a75fc32)
---
 src/CMakeLists.txt  |   1 +
 src/Makefile.am     |   1 +
 src/linux/memfd.cpp | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/linux/memfd.hpp |  39 ++++++++++++++
 4 files changed, 185 insertions(+)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index de9b5b8..bb7b535 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -276,6 +276,7 @@ set(LINUX_SRC
   linux/fs.cpp
   linux/ldcache.cpp
   linux/ldd.cpp
+  linux/memfd.cpp
   linux/ns.cpp
   linux/perf.cpp
   linux/systemd.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index 1485229..1eb6ff0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1310,6 +1310,7 @@ MESOS_LINUX_FILES =                                       
                                \
   linux/fs.cpp                                                                 
        \
   linux/ldcache.cpp                                                            
        \
   linux/ldd.cpp                                                                
                \
+  linux/memfd.cpp                                                              
        \
   linux/ns.cpp                                                                 
        \
   linux/perf.cpp                                                               
        \
   linux/systemd.cpp                                                            
        \
diff --git a/src/linux/memfd.cpp b/src/linux/memfd.cpp
new file mode 100644
index 0000000..706dc0c
--- /dev/null
+++ b/src/linux/memfd.cpp
@@ -0,0 +1,144 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/sendfile.h>
+#include <sys/syscall.h>
+
+#include <stout/stringify.hpp>
+
+#include <stout/os/close.hpp>
+#include <stout/os/open.hpp>
+#include <stout/os/stat.hpp>
+
+using std::string;
+
+#if !defined(MFD_CLOEXEC)
+#define MFD_CLOEXEC 0x0001U
+#endif
+
+#if !defined(MFD_ALLOW_SEALING)
+#define MFD_ALLOW_SEALING 0x0002U
+#endif
+
+#if !defined(F_ADD_SEALS)
+#define F_ADD_SEALS 1033
+#endif
+
+#if !defined(F_GET_SEALS)
+#define F_GET_SEALS 1034
+#endif
+
+#if !defined(F_SEAL_SEAL)
+#define F_SEAL_SEAL   0x0001
+#endif
+
+#if !defined(F_SEAL_SHRINK)
+#define F_SEAL_SHRINK 0x0002
+#endif
+
+#if !defined(F_SEAL_GROW)
+#define F_SEAL_GROW   0x0004
+#endif
+
+#if !defined(F_SEAL_WRITE)
+#define F_SEAL_WRITE  0x0008
+#endif
+
+namespace mesos {
+namespace internal {
+namespace memfd {
+
+static Try<int_fd> create(const string& name, unsigned int flags)
+{
+#ifdef __NR_memfd_create
+  int_fd fd = ::syscall(__NR_memfd_create, name.c_str(), flags);
+  if (fd == -1) {
+    return ErrnoError("Failed to create memfd");
+  }
+
+  return fd;
+#else
+#error "The memfd syscall is not available."
+#endif
+}
+
+
+Try<int_fd> cloneSealedFile(const std::string& filePath)
+{
+  if (!os::stat::isfile(filePath)) {
+    return Error("The original file '" + filePath + "' is not a regular file");
+  }
+
+  Try<Bytes> size = os::stat::size(filePath);
+  if (size.isError()) {
+    return Error("Failed to get the size of the source file: " + size.error());
+  }
+
+  Try<int_fd> fileFd = os::open(filePath, O_CLOEXEC | O_RDONLY);
+  if (fileFd.isError()) {
+    return Error("Failed to open source file: " + fileFd.error());
+  }
+
+  Try<int_fd> memFd = create(filePath, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+  if (memFd.isError()) {
+    os::close(fileFd.get());
+    return Error("Failed to open memfd file: " + memFd.error());
+  }
+
+  ssize_t written = sendfile(memFd.get(), fileFd.get(), nullptr, 
size->bytes());
+  if (written == -1) {
+    ErrnoError error("Failed to copy file");
+    os::close(fileFd.get());
+    os::close(memFd.get());
+    return error;
+  } else if (static_cast<uint64_t>(written) != size->bytes()) {
+    os::close(fileFd.get());
+    os::close(memFd.get());
+    return Error(
+        "Expect to write " + stringify(size->bytes()) + " bytes, "
+        "but only " + stringify(written) + " is written");
+  }
+
+  os::close(fileFd.get());
+
+  int ret = fchmod(memFd.get(), S_IRWXU | S_IRWXG | S_IRWXO);
+  if (ret == -1) {
+    ErrnoError error("Failed to chmod");
+    os::close(memFd.get());
+    return error;
+  }
+
+  // Seal the memfd file.
+  ret = fcntl(
+      memFd.get(),
+      F_ADD_SEALS,
+      F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
+
+  if (ret == -1) {
+    ErrnoError error("Failed to seal the memfd");
+    os::close(memFd.get());
+    return error;
+  }
+
+  return memFd.get();
+}
+
+} // namespace memfd {
+} // namespace internal {
+} // namespace mesos {
diff --git a/src/linux/memfd.hpp b/src/linux/memfd.hpp
new file mode 100644
index 0000000..4cf9906
--- /dev/null
+++ b/src/linux/memfd.hpp
@@ -0,0 +1,39 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __LINUX_MEMFD_HPP__
+#define __LINUX_MEMFD_HPP__
+
+#include <string>
+
+#include <stout/try.hpp>
+
+#include <stout/os/int_fd.hpp>
+
+namespace mesos {
+namespace internal {
+namespace memfd {
+
+// Clone a file into a sealed private copy such that any attempt to
+// modify it will not modify the original binary. Returns the memfd of
+// the sealed copy.
+Try<int_fd> cloneSealedFile(const std::string& filePath);
+
+} // namespace memfd {
+} // namespace internal {
+} // namespace mesos {
+
+#endif // __LINUX_MEMFD_HPP__

Reply via email to