1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <fcntl.h>
8 : #include <string.h>
9 : #if (NACL_LINUX)
10 : // for shmem cleanup
11 : #include <sys/ipc.h>
12 : #include <sys/shm.h>
13 : #include "native_client/src/trusted/desc/linux/nacl_desc_sysv_shm.h"
14 : #endif
15 :
16 : #include <map>
17 : #include <string>
18 : #include <sstream>
19 :
20 : using std::stringstream;
21 : #include "native_client/src/shared/imc/nacl_imc.h"
22 : #include "native_client/src/shared/platform/nacl_log.h"
23 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
24 : #include "native_client/src/trusted/desc/nacl_desc_sync_socket.h"
25 : #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
26 : #include "native_client/src/trusted/sel_universal/parsing.h"
27 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
28 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
29 :
30 :
31 : namespace {
32 :
33 : const uintptr_t k64KBytes = 0x10000;
34 :
35 : // The main point of this class is to ensure automatic cleanup.
36 : // If the destructor is not invoked you need to manually cleanup
37 : // the shared memory descriptors via "ipcs -m" and "ipcrm -m <id>"
38 : class AddressMap {
39 : public:
40 11 : AddressMap() {}
41 :
42 11 : ~AddressMap() {
43 : // NOTE: you CANNOT call NaClLog - this is called too late
44 : // NaClLog(1, "cleanup\n");
45 : #if (NACL_LINUX)
46 : typedef map<NaClDesc*, uintptr_t>::iterator IT;
47 : for (IT it = map_.begin(); it != map_.end(); ++it) {
48 : shmctl(reinterpret_cast<NaClDescSysvShm*>(it->first)->id, IPC_RMID, NULL);
49 : }
50 : #endif
51 11 : }
52 :
53 0 : void Add(NaClDesc* desc, uintptr_t addr) { map_[desc] = addr; }
54 :
55 : uintptr_t Get(NaClDesc* desc) { return map_[desc]; }
56 :
57 : private:
58 : map<NaClDesc*, uintptr_t> map_;
59 : };
60 :
61 22 : AddressMap GlobalAddressMap;
62 :
63 :
64 0 : uintptr_t MapShmem(nacl::DescWrapper* desc) {
65 : void* addr;
66 : size_t dummy_size;
67 0 : int result = desc->Map(&addr, &dummy_size);
68 0 : if (0 > result) {
69 0 : NaClLog(LOG_ERROR, "error mapping shmem area\n");
70 0 : return 0;
71 : }
72 :
73 0 : GlobalAddressMap.Add(desc->desc(), reinterpret_cast<uintptr_t>(addr));
74 0 : return reinterpret_cast<uintptr_t>(addr);
75 : }
76 :
77 : } // namespace
78 :
79 : bool HandlerSyncSocketCreate(NaClCommandLoop* ncl,
80 0 : const vector<string>& args) {
81 0 : if (args.size() < 3) {
82 0 : NaClLog(LOG_ERROR, "not enough args\n");
83 0 : return false;
84 : }
85 :
86 0 : nacl::Handle handles[2] = {nacl::kInvalidHandle, nacl::kInvalidHandle};
87 0 : if (NaClSocketPair(handles) != 0) {
88 0 : return false;
89 : }
90 :
91 0 : nacl::DescWrapperFactory factory;
92 0 : nacl::DescWrapper* desc1 = factory.ImportSyncSocketHandle(handles[0]);
93 0 : ncl->AddDesc(desc1->desc(), args[1]);
94 :
95 0 : nacl::DescWrapper* desc2 = factory.ImportSyncSocketHandle(handles[1]);
96 0 : ncl->AddDesc(desc2->desc(), args[2]);
97 0 : return true;
98 : }
99 :
100 : bool HandlerSyncSocketWrite(NaClCommandLoop* ncl,
101 0 : const vector<string>& args) {
102 0 : if (args.size() < 3) {
103 0 : NaClLog(LOG_ERROR, "not enough args\n");
104 0 : return false;
105 : }
106 :
107 0 : NaClDesc* raw_desc = ExtractDesc(args[1], ncl);
108 0 : if (raw_desc == NULL) {
109 0 : NaClLog(LOG_ERROR, "cannot find desciptor %s\n", args[1].c_str());
110 0 : return false;
111 : }
112 :
113 0 : const int value = ExtractInt32(args[2]);
114 0 : nacl::DescWrapperFactory factory;
115 : // TODO(robertm): eliminate use of NaClDesc in sel_universal and standardize
116 : // on DescWrapper to eliminate the memory leak here
117 0 : factory.MakeGeneric(raw_desc)->Write(&value, sizeof value);
118 0 : return true;
119 : }
120 :
121 0 : bool HandlerShmem(NaClCommandLoop* ncl, const vector<string>& args) {
122 0 : if (args.size() < 4) {
123 0 : NaClLog(LOG_ERROR, "not enough args\n");
124 0 : return false;
125 : }
126 :
127 0 : const int size = ExtractInt32(args[3]);
128 0 : nacl::DescWrapperFactory factory;
129 0 : nacl::DescWrapper* desc = factory.MakeShm(size);
130 0 : if (desc == NULL) {
131 0 : NaClLog(LOG_ERROR, "could not create shm\n");
132 0 : return false;
133 : }
134 :
135 0 : ncl->AddDesc(desc->desc(), args[1]);
136 :
137 0 : uintptr_t addr = MapShmem(desc);
138 0 : if (addr == 0) {
139 0 : return false;
140 : }
141 0 : stringstream str;
142 0 : str << "0x" << std::hex << addr;
143 0 : ncl->SetVariable(args[2], str.str());
144 0 : return true;
145 : }
146 :
147 :
148 : // create a descriptor representing a readonly file
149 0 : bool HandlerReadonlyFile(NaClCommandLoop* ncl, const vector<string>& args) {
150 0 : if (args.size() < 3) {
151 0 : NaClLog(LOG_ERROR, "not enough args\n");
152 0 : return false;
153 : }
154 :
155 0 : nacl::DescWrapperFactory factory;
156 : nacl::DescWrapper* desc = factory.OpenHostFile(args[2].c_str(),
157 0 : NACL_ABI_O_RDONLY, 0);
158 0 : if (NULL == desc) {
159 0 : NaClLog(LOG_ERROR, "cound not create file desc for %s\n", args[2].c_str());
160 0 : return false;
161 : }
162 0 : ncl->AddDesc(desc->desc(), args[1]);
163 0 : return true;
164 : }
165 :
166 : // create a descriptor representing a read-write file.
167 : // Used for temporary files created by the pnacl translator.
168 0 : bool HandlerReadwriteFile(NaClCommandLoop* ncl, const vector<string>& args) {
169 0 : if (args.size() < 3) {
170 0 : NaClLog(LOG_ERROR, "not enough args\n");
171 0 : return false;
172 : }
173 :
174 0 : nacl::DescWrapperFactory factory;
175 : nacl::DescWrapper* desc =
176 : factory.OpenHostFile(args[2].c_str(),
177 0 : NACL_ABI_O_RDWR | NACL_ABI_O_CREAT, 0666);
178 0 : if (NULL == desc) {
179 0 : NaClLog(LOG_ERROR, "cound not create file desc for %s\n", args[2].c_str());
180 0 : return false;
181 : }
182 0 : ncl->AddDesc(desc->desc(), args[1]);
183 0 : return true;
184 : }
185 :
186 : // create a descriptor representing a read-write file with quota management.
187 : bool HandlerReadwriteFileQuota(NaClCommandLoop* ncl,
188 0 : const vector<string>& args) {
189 0 : if (args.size() < 3) {
190 0 : NaClLog(LOG_ERROR, "not enough args\n");
191 0 : return false;
192 : }
193 :
194 : static const uint8_t kFileId[] = "SelUniversal000";
195 0 : nacl::DescWrapperFactory factory;
196 : nacl::DescWrapper* desc =
197 : factory.OpenHostFileQuota(args[2].c_str(),
198 : NACL_ABI_O_RDWR | NACL_ABI_O_CREAT, 0666,
199 0 : kFileId);
200 0 : if (NULL == desc) {
201 0 : NaClLog(LOG_ERROR, "cound not create file desc for %s\n", args[2].c_str());
202 0 : return false;
203 : }
204 0 : ncl->AddDesc(desc->desc(), args[1]);
205 0 : return true;
206 : }
207 :
208 : // sleep for a given number of seconds
209 0 : bool HandlerSleep(NaClCommandLoop* ncl, const vector<string>& args) {
210 : UNREFERENCED_PARAMETER(ncl);
211 0 : if (args.size() < 2) {
212 0 : NaClLog(LOG_ERROR, "not enough args\n");
213 0 : return false;
214 : }
215 0 : const int secs = ExtractInt32(args[1]);
216 : #if (NACL_LINUX || NACL_OSX)
217 0 : sleep(secs);
218 : #elif NACL_WINDOWS
219 : Sleep(secs * 1000);
220 : #else
221 : #error "Please specify platform as NACL_LINUX, NACL_OSX or NACL_WINDOWS"
222 : #endif
223 0 : return true;
224 : }
225 :
226 : // save a memory region to a file
227 0 : bool HandlerSaveToFile(NaClCommandLoop* ncl, const vector<string>& args) {
228 : UNREFERENCED_PARAMETER(ncl);
229 0 : if (args.size() < 5) {
230 0 : NaClLog(LOG_ERROR, "not enough args\n");
231 0 : return false;
232 : }
233 :
234 0 : const char* filename = args[1].c_str();
235 0 : const char* start = reinterpret_cast<char*>(ExtractInt64(args[2]));
236 0 : const int offset = ExtractInt32(args[3]);
237 0 : const int size = ExtractInt32(args[4]);
238 :
239 0 : NaClLog(1, "opening %s\n", filename);
240 0 : FILE* fp = fopen(filename, "wb");
241 0 : if (fp == NULL) {
242 0 : NaClLog(LOG_ERROR, "cannot open %s\n", filename);
243 0 : return false;
244 : }
245 :
246 :
247 0 : NaClLog(1, "writing %d bytes from %p\n", (int) size, start + offset);
248 0 : const size_t n = fwrite(start + offset, 1, size, fp);
249 0 : if (static_cast<int>(n) != size) {
250 : NaClLog(LOG_ERROR, "wrote %d bytes, expected %d\n",
251 0 : static_cast<int>(n), size);
252 0 : fclose(fp);
253 0 : return false;
254 : }
255 0 : fclose(fp);
256 0 : return true;
257 : }
258 :
259 : // map a shared mem descriptor into memory and save address into var
260 0 : bool HandlerMap(NaClCommandLoop* ncl, const vector<string>& args) {
261 : UNREFERENCED_PARAMETER(ncl);
262 0 : if (args.size() < 3) {
263 0 : NaClLog(LOG_ERROR, "not enough args\n");
264 0 : return false;
265 : }
266 :
267 0 : NaClDesc* raw_desc = ExtractDesc(args[1], ncl);
268 0 : if (raw_desc == NULL) {
269 0 : NaClLog(LOG_ERROR, "cannot find desciptor %s\n", args[1].c_str());
270 0 : return false;
271 : }
272 :
273 0 : nacl::DescWrapperFactory factory;
274 0 : nacl::DescWrapper* desc = factory.MakeGeneric(raw_desc);
275 :
276 0 : uintptr_t addr = MapShmem(desc);
277 0 : if (addr == 0) {
278 0 : return false;
279 : }
280 :
281 0 : NaClLog(1, "region mapped at %p\n", reinterpret_cast<void*>(addr));
282 0 : stringstream str;
283 0 : str << "0x" << std::hex << addr;
284 0 : ncl->SetVariable(args[2], str.str());
285 0 : return true;
286 : }
287 :
288 : // load file into memory region
289 0 : bool HandlerLoadFromFile(NaClCommandLoop* ncl, const vector<string>& args) {
290 : UNREFERENCED_PARAMETER(ncl);
291 0 : if (args.size() < 5) {
292 0 : NaClLog(LOG_ERROR, "not enough args\n");
293 0 : return false;
294 : }
295 :
296 0 : const char* filename = args[1].c_str();
297 0 : char* start = reinterpret_cast<char*>(ExtractInt64(args[2]));
298 0 : const int offset = ExtractInt32(args[3]);
299 0 : const int size = ExtractInt32(args[4]);
300 :
301 0 : NaClLog(1, "opening %s\n", filename);
302 0 : FILE* fp = fopen(filename, "rb");
303 0 : if (fp == NULL) {
304 0 : NaClLog(LOG_ERROR, "cannot open %s\n", filename);
305 0 : return false;
306 : }
307 :
308 0 : NaClLog(1, "loading %d bytes to %p\n", (int) size, start + offset);
309 0 : const size_t n = fread(start + offset, 1, size, fp);
310 0 : if (static_cast<int>(n) != size) {
311 : NaClLog(LOG_ERROR, "read %d bytes, expected %d\n",
312 0 : static_cast<int>(n), size);
313 0 : fclose(fp);
314 0 : return false;
315 : }
316 0 : fclose(fp);
317 0 : return true;
318 : }
319 :
320 : // Determine filesize and write it into a variable
321 0 : bool HandlerFileSize(NaClCommandLoop* ncl, const vector<string>& args) {
322 : UNREFERENCED_PARAMETER(ncl);
323 0 : if (args.size() < 3) {
324 0 : NaClLog(LOG_ERROR, "not enough args\n");
325 0 : return false;
326 : }
327 :
328 0 : const char* filename = args[1].c_str();
329 0 : FILE* fp = fopen(filename, "rb");
330 0 : if (fp == NULL) {
331 0 : NaClLog(LOG_ERROR, "cannot open %s\n", filename);
332 0 : return false;
333 : }
334 0 : fseek(fp, 0, SEEK_END);
335 0 : int size = static_cast<int>(ftell(fp));
336 0 : fclose(fp);
337 :
338 0 : NaClLog(1, "filesize is %d\n", size);
339 :
340 0 : stringstream str;
341 0 : str << size;
342 0 : ncl->SetVariable(args[2], str.str());
343 0 : return true;
344 22 : }
|