1/* 2 * Copyright (C) 2013 Intel Corporation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "OpenSyscall.h" 28 29#if ENABLE(SECCOMP_FILTERS) 30 31#include "ArgumentCoders.h" 32#include "SyscallPolicy.h" 33#include <errno.h> 34#include <fcntl.h> 35#include <seccomp.h> 36#include <sys/stat.h> 37#include <sys/types.h> 38#include <unistd.h> 39#include <wtf/text/WTFString.h> 40 41namespace WebKit { 42 43COMPILE_ASSERT(!O_RDONLY, O_RDONLY); 44COMPILE_ASSERT(O_WRONLY == 1, O_WRONLY); 45COMPILE_ASSERT(O_RDWR == 2, O_RDWR); 46 47std::unique_ptr<Syscall> OpenSyscall::createFromOpenatContext(mcontext_t* context) 48{ 49 auto open = std::make_unique<OpenSyscall>(nullptr); 50 51 open->setFlags(context->gregs[REG_ARG2]); 52 open->setMode(context->gregs[REG_ARG3]); 53 open->setContext(context); 54 55 int fd = context->gregs[REG_ARG0]; 56 char* path = reinterpret_cast<char*>(context->gregs[REG_ARG1]); 57 58 if (path[0] == '/') { 59 open->setPath(path); 60 return WTF::move(open); 61 } 62 63 struct stat pathStat; 64 if (fstat(fd, &pathStat) == -1) { 65 context->gregs[REG_SYSCALL] = -errno; 66 return nullptr; 67 } 68 69 if (!S_ISDIR(pathStat.st_mode)) { 70 context->gregs[REG_SYSCALL] = -ENOTDIR; 71 return nullptr; 72 } 73 74 char fdLinkPath[32]; 75 snprintf(fdLinkPath, sizeof(fdLinkPath), "/proc/self/fd/%d", fd); 76 77 char fdPath[PATH_MAX]; 78 ssize_t size = readlink(fdLinkPath, fdPath, sizeof(fdPath) - 1); 79 if (size == -1) { 80 context->gregs[REG_SYSCALL] = -errno; 81 return nullptr; 82 } 83 84 // The "+ 2" here stands for the '/' and null terminator. 85 if (size + strlen(path) + 2 > PATH_MAX) { 86 context->gregs[REG_SYSCALL] = -ENAMETOOLONG; 87 return nullptr; 88 } 89 90 sprintf(&fdPath[size], "/%s", path); 91 open->setPath(fdPath); 92 93 return WTF::move(open); 94} 95 96std::unique_ptr<Syscall> OpenSyscall::createFromCreatContext(mcontext_t* context) 97{ 98 auto open = std::make_unique<OpenSyscall>(nullptr); 99 100 open->setPath(CString(reinterpret_cast<char*>(context->gregs[REG_ARG0]))); 101 open->setFlags(O_CREAT | O_WRONLY | O_TRUNC); 102 open->setMode(context->gregs[REG_ARG1]); 103 open->setContext(context); 104 105 return WTF::move(open); 106} 107 108OpenSyscall::OpenSyscall(mcontext_t* context) 109 : Syscall(__NR_open, context) 110 , m_flags(0) 111 , m_mode(0) 112{ 113 if (!context) 114 return; 115 116 m_path = CString(reinterpret_cast<char*>(context->gregs[REG_ARG0])); 117 m_flags = context->gregs[REG_ARG1]; 118 m_mode = context->gregs[REG_ARG2]; 119} 120 121void OpenSyscall::setResult(const SyscallResult* result) 122{ 123 ASSERT(context() && result->type() == type()); 124 125 const OpenSyscallResult* openResult = static_cast<const OpenSyscallResult*>(result); 126 127 if (openResult->fd() >= 0) 128 context()->gregs[REG_SYSCALL] = dup(openResult->fd()); 129 else 130 context()->gregs[REG_SYSCALL] = -openResult->errorNumber(); 131} 132 133std::unique_ptr<SyscallResult> OpenSyscall::execute(const SyscallPolicy& policy) 134{ 135 if (!strncmp("/proc/self/", m_path.data(), 11)) { 136 String resolvedSelfPath = ASCIILiteral("/proc/") + String::number(getppid()) + &m_path.data()[10]; 137 m_path = resolvedSelfPath.utf8().data(); 138 } 139 140 SyscallPolicy::Permission permission = SyscallPolicy::NotAllowed; 141 if (m_flags & O_RDWR) 142 permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::ReadAndWrite); 143 else if (m_flags & O_WRONLY) 144 permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::Write); 145 else 146 permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::Read); 147 148 // Create a file implies write permission on the directory. 149 if (m_flags & O_CREAT || m_flags & O_EXCL) 150 permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::Write); 151 152 if (!policy.hasPermissionForPath(m_path.data(), permission)) 153 return std::make_unique<OpenSyscallResult>(-1, EACCES); 154 155 // Permission granted, execute the syscall. The syscall might still 156 // fail because of hard permissions enforced by the filesystem and 157 // things like if the entry does not exist. 158 int fd = open(m_path.data(), m_flags, m_mode); 159 int errorNumber = fd == -1 ? errno : 0; 160 161 return std::make_unique<OpenSyscallResult>(fd, errorNumber); 162} 163 164void OpenSyscall::encode(IPC::ArgumentEncoder& encoder) const 165{ 166 encoder << type(); 167 encoder << m_path; 168 encoder << m_flags; 169 encoder << m_mode; 170} 171 172bool OpenSyscall::decode(IPC::ArgumentDecoder* decoder) 173{ 174 // m_type already decoded by the parent class. 175 176 if (!decoder->decode(m_path)) 177 return false; 178 if (!decoder->decode(m_flags)) 179 return false; 180 181 return decoder->decode(m_mode); 182} 183 184OpenSyscallResult::OpenSyscallResult(int fd, int errorNumber) 185 : SyscallResult(__NR_open) 186 , m_fd(fd) 187 , m_errorNumber(errorNumber) 188{ 189} 190 191OpenSyscallResult::~OpenSyscallResult() 192{ 193 if (m_fd >= 0) 194 close(m_fd); 195} 196 197void OpenSyscallResult::encode(IPC::ArgumentEncoder& encoder) const 198{ 199 encoder << type(); 200 201 if (m_fd >= 0) { 202 IPC::Attachment attachment(m_fd); 203 encoder.addAttachment(attachment); 204 } 205 206 encoder << m_errorNumber; 207} 208 209bool OpenSyscallResult::decode(IPC::ArgumentDecoder* decoder, int fd) 210{ 211 if (fd >= 0) 212 m_fd = fd; 213 214 return decoder->decode(m_errorNumber); 215} 216 217} // namespace WebKit 218 219#endif // ENABLE(SECCOMP_FILTERS) 220