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__
