Add WTF::move()
[WebKit-https.git] / Source / WebKit2 / Shared / linux / SeccompFilters / OpenSyscall.cpp
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
41 namespace WebKit {
42
43 COMPILE_ASSERT(!O_RDONLY, O_RDONLY);
44 COMPILE_ASSERT(O_WRONLY == 1, O_WRONLY);
45 COMPILE_ASSERT(O_RDWR == 2, O_RDWR);
46
47 std::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
96 std::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
108 OpenSyscall::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
121 void 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
133 std::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
164 void OpenSyscall::encode(IPC::ArgumentEncoder& encoder) const
165 {
166     encoder << type();
167     encoder << m_path;
168     encoder << m_flags;
169     encoder << m_mode;
170 }
171
172 bool 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
184 OpenSyscallResult::OpenSyscallResult(int fd, int errorNumber)
185     : SyscallResult(__NR_open)
186     , m_fd(fd)
187     , m_errorNumber(errorNumber)
188 {
189 }
190
191 OpenSyscallResult::~OpenSyscallResult()
192 {
193     if (m_fd >= 0)
194         close(m_fd);
195 }
196
197 void 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
209 bool 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)