| 74 | |
| 75 | |
| 76 | Try<int_fd> cloneSealedFile(const std::string& filePath) |
| 77 | { |
| 78 | if (!os::stat::isfile(filePath)) { |
| 79 | return Error("The original file '" + filePath + "' is not a regular file"); |
| 80 | } |
| 81 | |
| 82 | Try<Bytes> size = os::stat::size(filePath); |
| 83 | if (size.isError()) { |
| 84 | return Error("Failed to get the size of the source file: " + size.error()); |
| 85 | } |
| 86 | |
| 87 | Try<int_fd> fileFd = os::open(filePath, O_CLOEXEC | O_RDONLY); |
| 88 | if (fileFd.isError()) { |
| 89 | return Error("Failed to open source file: " + fileFd.error()); |
| 90 | } |
| 91 | |
| 92 | Try<int_fd> memFd = create(filePath, MFD_CLOEXEC | MFD_ALLOW_SEALING); |
| 93 | if (memFd.isError()) { |
| 94 | os::close(fileFd.get()); |
| 95 | return Error("Failed to open memfd file: " + memFd.error()); |
| 96 | } |
| 97 | |
| 98 | size_t remaining = size->bytes(); |
| 99 | while (remaining > 0) { |
| 100 | ssize_t written = sendfile(memFd.get(), fileFd.get(), nullptr, remaining); |
| 101 | if (written == -1) { |
| 102 | ErrnoError error("Failed to copy file"); |
| 103 | os::close(fileFd.get()); |
| 104 | os::close(memFd.get()); |
| 105 | return error; |
| 106 | } else if (static_cast<size_t>(written) > remaining) { |
| 107 | os::close(fileFd.get()); |
| 108 | os::close(memFd.get()); |
| 109 | return Error("More bytes written than requested"); |
| 110 | } else { |
| 111 | remaining -= written; |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | os::close(fileFd.get()); |
| 116 | |
| 117 | int ret = fchmod(memFd.get(), S_IRWXU | S_IRWXG | S_IRWXO); |
| 118 | if (ret == -1) { |
| 119 | ErrnoError error("Failed to chmod"); |
| 120 | os::close(memFd.get()); |
| 121 | return error; |
| 122 | } |
| 123 | |
| 124 | // Seal the memfd file. |
| 125 | ret = fcntl( |
| 126 | memFd.get(), |
| 127 | F_ADD_SEALS, |
| 128 | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL); |
| 129 | |
| 130 | if (ret == -1) { |
| 131 | ErrnoError error("Failed to seal the memfd"); |
| 132 | os::close(memFd.get()); |
| 133 | return error; |