Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: src/trusted/service_runtime/sel_ldr.c

Issue 10914138: Split secure command channel and untrusted application channel (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be 3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file. 4 * found in the LICENSE file.
5 */ 5 */
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 /* 9 /*
10 * NaCl Simple/secure ELF loader (NaCl SEL). 10 * NaCl Simple/secure ELF loader (NaCl SEL).
(...skipping 1242 matching lines...) Expand 10 before | Expand all | Expand 10 after
1253 if (NULL != nap->secure_service) { 1253 if (NULL != nap->secure_service) {
1254 for (;;) { 1254 for (;;) {
1255 struct nacl_abi_timespec req; 1255 struct nacl_abi_timespec req;
1256 req.tv_sec = 1000; 1256 req.tv_sec = 1000;
1257 req.tv_nsec = 0; 1257 req.tv_nsec = 0;
1258 NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL); 1258 NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
1259 } 1259 }
1260 } 1260 }
1261 } 1261 }
1262 1262
1263 static void NaClCommandServiceSetupRpc(struct NaClSrpcRpc *rpc,
1264 struct NaClSrpcArg **in_args,
1265 struct NaClSrpcArg **out_args,
1266 struct NaClSrpcClosure *done) {
1267 struct NaClApp *nap =
1268 (struct NaClApp *) rpc->channel->server_instance_data;
1269 struct NaClCommandService *command_server;
1263 1270
1264 /* 1271 static struct NaClSrpcHandlerDesc const handlers[] = {
1265 * Secure command channels. 1272 { "hard_shutdown::", NaClSecureChannelShutdownRpc, },
1266 */ 1273 { "start_module::i", NaClSecureChannelStartModuleRpc, },
1274 { "load_module:hs:", NaClLoadModuleRpc, },
1275 { "load_irt:h:", NaClLoadIrtRpc, },
1276 { (char const *) NULL, (NaClSrpcMethod) NULL, },
1277 };
1267 1278
1268 struct NaClSecureService { 1279 UNREFERENCED_PARAMETER(in_args);
1269 struct NaClSimpleService base;
1270 struct NaClApp *nap;
1271 };
1272 1280
1273 struct NaClSimpleServiceVtbl const kNaClSecureServiceVtbl; 1281 NaClLog(4, "Entered NaClCommandServiceSetup\n");
1274 1282
1283 NaClXMutexLock(&nap->mu);
1284 if (NULL != nap->command_service) {
1285 NaClLog(LOG_FATAL, "Double command setup RPC\n");
1286 }
1275 1287
1276 struct NaClConnectionHandler { 1288 command_server = (struct NaClCommandService *) malloc(
1277 struct NaClConnectionHandler *next; 1289 sizeof *command_server);
1290 if (NACL_FI_ERROR_COND("NaClCommandService__malloc",
1291 NULL == command_server)) {
1292 NaClLog(LOG_ERROR, "Out of memory for command channel\n");
1293 rpc->result = NACL_SRPC_RESULT_APP_ERROR;
1294 goto done;
1295 }
1296 if (NACL_FI_ERROR_COND("NaClCommandService__NaClSecureServiceCtor",
1297 !NaClCommandServiceCtor(command_server,
1298 handlers, nap))) {
1299 NaClLog(LOG_FATAL, "NaClCommandServiceCtor failed\n");
1300 }
1278 1301
1279 /* used by NaClSimpleRevServiceClient's ClientCallback fn */ 1302 NaClLog(4, "NaClCommandService: starting service thread\n");
1280 void (*handler)( 1303 if (NACL_FI_ERROR_COND(
1281 void *state, 1304 "NaClCommandService__NaClSimpleServiceStartServiceThread",
1282 struct NaClThreadInterface *tif, 1305 !NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1283 struct NaClDesc *conn); 1306 command_server))) {
1284 void *state; 1307 NaClLog(LOG_ERROR, "Could not start command channel service thread\n");
1285 }; 1308 free(command_server);
1309 rpc->result = NACL_SRPC_RESULT_APP_ERROR;
1310 goto done;
1311 }
1312 nap->command_service = (struct NaClCommandService *) NaClRefCountRef(
1313 (struct NaClRefCount *) command_server);
1314 out_args[0]->u.hval = NaClDescRef(command_server->base.bound_and_cap[1]);
1315 rpc->result = NACL_SRPC_RESULT_OK;
1286 1316
1287 struct NaClSecureReverseClient { 1317 done:
1288 struct NaClSimpleRevClient base; 1318 NaClXMutexUnlock(&nap->mu);
1289 struct NaClApp *nap; 1319 (*done->Run)(done);
1290 1320 NaClLog(4, "Leaving NaClCommandServiceSetup\n");
1291 struct NaClMutex mu;
1292
1293 struct NaClConnectionHandler *queue_head;
1294 struct NaClConnectionHandler **queue_insert;
1295 };
1296
1297 struct NaClSimpleRevClientVtbl const kNaClSecureReverseClientVtbl;
1298
1299
1300 int NaClSecureServiceCtor(struct NaClSecureService *self,
1301 struct NaClSrpcHandlerDesc const *srpc_handlers,
1302 struct NaClApp *nap) {
1303 NaClLog(4,
1304 "Entered NaClSecureServiceCtor: self 0x%"NACL_PRIxPTR"\n",
1305 (uintptr_t) self);
1306 if (NACL_FI_ERROR_COND(
1307 "NaClSecureServiceCtor__NaClSimpleServiceWithSocketCtor",
1308 !NaClSimpleServiceWithSocketCtor(
1309 &self->base,
1310 srpc_handlers,
1311 NaClThreadInterfaceThreadFactory,
1312 (void *) NULL,
1313 nap->service_port,
1314 nap->service_address))) {
1315 goto failure_simple_ctor;
1316 }
1317 self->nap = nap;
1318
1319 NACL_VTBL(NaClRefCount, self) =
1320 (struct NaClRefCountVtbl *) &kNaClSecureServiceVtbl;
1321 return 1;
1322 failure_simple_ctor:
1323 return 0;
1324 }
1325
1326 void NaClSecureServiceDtor(struct NaClRefCount *vself) {
1327 struct NaClSecureService *self = (struct NaClSecureService *) vself;
1328
1329 NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl const *)
1330 &kNaClSimpleServiceVtbl;
1331 (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
1332 } 1321 }
1333 1322
1334 /* 1323 /*
1335 * The first connection is performed by this callback handler. This 1324 * The first connection is performed by this callback handler. This
1336 * spawns a client thread that will bootstrap the other connections by 1325 * spawns a client thread that will bootstrap the other connections by
1337 * stashing the connection represented by |conn| to make reverse RPCs 1326 * stashing the connection represented by |conn| to make reverse RPCs
1338 * to ask the peer to connect to us. No thread is spawned; we just 1327 * to ask the peer to connect to us. No thread is spawned; we just
1339 * wrap access to the connection with a lock. 1328 * wrap access to the connection with a lock.
1340 * 1329 *
1341 * Subsequent connection callbacks will pass the connection to the 1330 * Subsequent connection callbacks will pass the connection to the
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1383 NaClLog(LOG_FATAL, "Reverse quota interface Ctor failed\n"); 1372 NaClLog(LOG_FATAL, "Reverse quota interface Ctor failed\n");
1384 } 1373 }
1385 nap->reverse_channel_initialization_state = NACL_REVERSE_CHANNEL_INITIALIZED; 1374 nap->reverse_channel_initialization_state = NACL_REVERSE_CHANNEL_INITIALIZED;
1386 1375
1387 NaClXCondVarBroadcast(&nap->cv); 1376 NaClXCondVarBroadcast(&nap->cv);
1388 NaClXMutexUnlock(&nap->mu); 1377 NaClXMutexUnlock(&nap->mu);
1389 1378
1390 NaClLog(4, "Leaving NaClSecureReverseClientCallback\n"); 1379 NaClLog(4, "Leaving NaClSecureReverseClientCallback\n");
1391 } 1380 }
1392 1381
1393 /* fwd */
1394 int NaClSecureReverseClientCtor(
1395 struct NaClSecureReverseClient *self,
1396 void (*client_callback)(
1397 void *, struct NaClThreadInterface *, struct NaClDesc *),
1398 void *state,
1399 struct NaClApp *nap);
1400
1401 static void NaClSecureReverseClientSetup(struct NaClSrpcRpc *rpc, 1382 static void NaClSecureReverseClientSetup(struct NaClSrpcRpc *rpc,
1402 struct NaClSrpcArg **in_args, 1383 struct NaClSrpcArg **in_args,
1403 struct NaClSrpcArg **out_args, 1384 struct NaClSrpcArg **out_args,
1404 struct NaClSrpcClosure *done) { 1385 struct NaClSrpcClosure *done) {
1405 struct NaClApp *nap = 1386 struct NaClApp *nap =
1406 (struct NaClApp *) rpc->channel->server_instance_data; 1387 (struct NaClApp *) rpc->channel->server_instance_data;
1407 struct NaClSecureReverseClient *rev; 1388 struct NaClSecureReverseClient *rev;
1408 1389
1409 UNREFERENCED_PARAMETER(in_args); 1390 UNREFERENCED_PARAMETER(in_args);
1410 NaClLog(4, "Entered NaClSecureReverseClientSetup\n"); 1391 NaClLog(4, "Entered NaClSecureReverseClientSetup\n");
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1459 if (!NaClSimpleRevClientStartServiceThread(&rev->base)) { 1440 if (!NaClSimpleRevClientStartServiceThread(&rev->base)) {
1460 NaClLog(LOG_FATAL, "Could not start reverse service thread\n"); 1441 NaClLog(LOG_FATAL, "Could not start reverse service thread\n");
1461 } 1442 }
1462 1443
1463 done: 1444 done:
1464 NaClXMutexUnlock(&nap->mu); 1445 NaClXMutexUnlock(&nap->mu);
1465 (*done->Run)(done); 1446 (*done->Run)(done);
1466 NaClLog(4, "Leaving NaClSecureReverseClientSetup\n"); 1447 NaClLog(4, "Leaving NaClSecureReverseClientSetup\n");
1467 } 1448 }
1468 1449
1469 /*
1470 * Only called at startup and thereafter by the reverse secure
1471 * channel, with |self| locked.
1472 */
1473 static
1474 int NaClSecureReverseClientInsertHandler_mu(
1475 struct NaClSecureReverseClient *self,
1476 void (*h)(void *,
1477 struct NaClThreadInterface *,
1478 struct NaClDesc *),
1479 void *d) {
1480 struct NaClConnectionHandler *entry;
1481
1482 NaClLog(4,
1483 ("NaClSecureReverseClientInsertHandler_mu: h 0x%"NACL_PRIxPTR","
1484 " d 0x%"NACL_PRIxPTR"\n"),
1485 (uintptr_t) h,
1486 (uintptr_t) d);
1487 entry = (struct NaClConnectionHandler *) malloc(sizeof *entry);
1488 if (NULL == entry) {
1489 return 0;
1490 }
1491 entry->handler = h;
1492 entry->state = d;
1493 entry->next = (struct NaClConnectionHandler *) NULL;
1494 *self->queue_insert = entry;
1495 self->queue_insert = &entry->next;
1496
1497 return 1;
1498 }
1499
1500 /*
1501 * Caller must set up handler before issuing connection request RPC on
1502 * nap->reverse_channel, since otherwise the connection handler queue
1503 * may be empty and the connect code would abort. Because the connect
1504 * doesn't wait for a handler, we don't need a condvar.
1505 *
1506 * We do not need to serialize on the handlers, since the
1507 * RPC-server/IMC-client implementation should not distinguish one
1508 * connection from another: it is okay for two handlers to be
1509 * inserted, and two connection request RPCs to be preformed
1510 * (sequentially, since they are over a single channel), and have the
1511 * server side spawn threads that asynchronously connect twice, in the
1512 * "incorrect" order, etc.
1513 */
1514 int NaClSecureReverseClientInsertHandler(
1515 struct NaClSecureReverseClient *self,
1516 void (*handler)(
1517 void *handlr_state,
1518 struct NaClThreadInterface *thread_if,
1519 struct NaClDesc *new_conn),
1520 void *handler_state) {
1521 int retval;
1522
1523 NaClXMutexLock(&self->mu);
1524 retval = NaClSecureReverseClientInsertHandler_mu(self,
1525 handler, handler_state);
1526 NaClXMutexUnlock(&self->mu);
1527 return retval;
1528 }
1529
1530 static
1531 struct NaClConnectionHandler *NaClSecureReverseClientPopHandler(
1532 struct NaClSecureReverseClient *self) {
1533 struct NaClConnectionHandler *head;
1534
1535 NaClLog(4, "Entered NaClSecureReverseClientPopHandler, acquiring lock\n");
1536 NaClXMutexLock(&self->mu);
1537 NaClLog(4, "NaClSecureReverseClientPopHandler, got lock\n");
1538 head = self->queue_head;
1539 if (NULL == head) {
1540 NaClLog(LOG_FATAL,
1541 "NaClSecureReverseClientPopHandler: empty handler queue\n");
1542 }
1543 if (NULL == (self->queue_head = head->next)) {
1544 NaClLog(4, "NaClSecureReverseClientPopHandler, last elt patch up\n");
1545 self->queue_insert = &self->queue_head;
1546 }
1547 NaClLog(4, "NaClSecureReverseClientPopHandler, unlocking\n");
1548 NaClXMutexUnlock(&self->mu);
1549
1550 head->next = NULL;
1551 NaClLog(4,
1552 ("Leaving NaClSecureReverseClientPopHandler:"
1553 " returning %"NACL_PRIxPTR"\n"),
1554 (uintptr_t) head);
1555 return head;
1556 }
1557
1558 static
1559 void NaClSecureReverseClientInternalCallback(
1560 void *state,
1561 struct NaClThreadInterface *tif,
1562 struct NaClDesc *conn) {
1563 struct NaClSecureReverseClient *self =
1564 (struct NaClSecureReverseClient *) state;
1565 struct NaClConnectionHandler *hand_ptr;
1566
1567 UNREFERENCED_PARAMETER(tif);
1568 NaClLog(4, "Entered NaClSecureReverseClientInternalCallback\n");
1569 hand_ptr = NaClSecureReverseClientPopHandler(self);
1570 NaClLog(4, " got callback object %"NACL_PRIxPTR"\n", (uintptr_t) hand_ptr);
1571 NaClLog(4,
1572 " callback:0x%"NACL_PRIxPTR"(0x%"NACL_PRIxPTR",0x%"NACL_PRIxPTR")\n",
1573 (uintptr_t) hand_ptr->handler,
1574 (uintptr_t) hand_ptr->state,
1575 (uintptr_t) conn);
1576 (*hand_ptr->handler)(hand_ptr->state, tif, conn);
1577 NaClLog(4, "NaClSecureReverseClientInternalCallback: freeing memory\n");
1578 free(hand_ptr);
1579 NaClLog(4, "Leaving NaClSecureReverseClientInternalCallback\n");
1580 }
1581
1582 /*
1583 * Require an initial connection handler in the Ctor, so that it's
1584 * obvious that a reverse client needs to accept an IMC connection
1585 * from the server to get things bootstrapped.
1586 */
1587 int NaClSecureReverseClientCtor(
1588 struct NaClSecureReverseClient *self,
1589 void (*client_callback)(
1590 void *, struct NaClThreadInterface*, struct NaClDesc *),
1591 void *state,
1592 struct NaClApp *nap) {
1593 NaClLog(4,
1594 ("Entered NaClSecureReverseClientCtor, self 0x%"NACL_PRIxPTR","
1595 " nap 0x%"NACL_PRIxPTR"\n"),
1596 (uintptr_t) self,
1597 (uintptr_t) nap);
1598 if (!NaClSimpleRevClientCtor(&self->base,
1599 NaClSecureReverseClientInternalCallback,
1600 (void *) self,
1601 NaClThreadInterfaceThreadFactory,
1602 (void *) NULL)) {
1603 goto failure_simple_ctor;
1604 }
1605 NaClLog(4, "NaClSecureReverseClientCtor: Mutex\n");
1606 if (!NaClMutexCtor(&self->mu)) {
1607 goto failure_mutex_ctor;
1608 }
1609 self->nap = nap;
1610 self->queue_head = (struct NaClConnectionHandler *) NULL;
1611 self->queue_insert = &self->queue_head;
1612
1613 NACL_VTBL(NaClRefCount, self) =
1614 (struct NaClRefCountVtbl *) &kNaClSecureReverseClientVtbl;
1615
1616 NaClLog(4, "NaClSecureReverseClientCtor: InsertHandler\n");
1617 if (!NaClSecureReverseClientInsertHandler(self,
1618 client_callback,
1619 state)) {
1620 goto failure_handler_insert;
1621 }
1622
1623 NaClLog(4, "Leaving NaClSecureReverseClientCtor\n");
1624 return 1;
1625
1626 failure_handler_insert:
1627 NaClLog(4, "NaClSecureReverseClientCtor: InsertHandler failed\n");
1628 NACL_VTBL(NaClRefCount, self) =
1629 (struct NaClRefCountVtbl *) &kNaClSimpleRevClientVtbl;
1630
1631 self->nap = NULL;
1632 self->queue_insert = (struct NaClConnectionHandler **) NULL;
1633 NaClMutexDtor(&self->mu);
1634
1635 failure_mutex_ctor:
1636 NaClLog(4, "NaClSecureReverseClientCtor: Mutex failed\n");
1637 (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
1638 failure_simple_ctor:
1639 NaClLog(4, "Leaving NaClSecureReverseClientCtor\n");
1640 return 0;
1641 }
1642
1643 void NaClSecureReverseClientDtor(struct NaClRefCount *vself) {
1644 struct NaClSecureReverseClient *self =
1645 (struct NaClSecureReverseClient *) vself;
1646
1647 struct NaClConnectionHandler *entry;
1648 struct NaClConnectionHandler *next;
1649
1650 for (entry = self->queue_head; NULL != entry; entry = next) {
1651 next = entry->next;
1652 free(entry);
1653 }
1654 NaClMutexDtor(&self->mu);
1655
1656 NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl const *)
1657 &kNaClSimpleRevClientVtbl;
1658 (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
1659 }
1660
1661 int NaClSecureServiceConnectionFactory(
1662 struct NaClSimpleService *vself,
1663 struct NaClDesc *conn,
1664 struct NaClSimpleServiceConnection **out) {
1665 struct NaClSecureService *self =
1666 (struct NaClSecureService *) vself;
1667
1668 /* our instance_data is not connection specific */
1669 return NaClSimpleServiceConnectionFactoryWithInstanceData(
1670 vself, conn, (void *) self->nap, out);
1671 }
1672
1673 int NaClSecureServiceAcceptAndSpawnHandler(struct NaClSimpleService *vself) {
1674 int rv;
1675
1676 NaClLog(4,
1677 "NaClSecureServiceAcceptAndSpawnHandler: invoking base class vfn\n");
1678 rv = (*kNaClSimpleServiceVtbl.AcceptAndSpawnHandler)(vself);
1679 if (0 != rv) {
1680 NaClLog(LOG_FATAL,
1681 "Secure channel AcceptAndSpawnHandler returned %d\n",
1682 rv);
1683 }
1684 NaClThreadExit(0);
1685 /*
1686 * NOTREACHED The port is now to be used by untrusted code: all
1687 * subsequent connections are handled there.
1688 */
1689 return rv;
1690 }
1691
1692 void NaClSecureServiceRpcHandler(struct NaClSimpleService *vself,
1693 struct NaClSimpleServiceConnection *vconn) {
1694
1695 NaClLog(4, "NaClSecureChannelThread started\n");
1696 (*kNaClSimpleServiceVtbl.RpcHandler)(vself, vconn);
1697 NaClLog(4, "NaClSecureChannelThread: channel closed, exiting.\n");
1698 NaClExit(0);
1699 }
1700
1701 struct NaClSimpleServiceVtbl const kNaClSecureServiceVtbl = {
1702 {
1703 NaClSecureServiceDtor,
1704 },
1705 NaClSecureServiceConnectionFactory,
1706 NaClSimpleServiceAcceptConnection,
1707 NaClSecureServiceAcceptAndSpawnHandler,
1708 NaClSecureServiceRpcHandler,
1709 };
1710
1711 struct NaClSimpleRevClientVtbl const kNaClSecureReverseClientVtbl = {
1712 {
1713 NaClSecureReverseClientDtor,
1714 },
1715 };
1716
1717
1718 void NaClSecureCommandChannel(struct NaClApp *nap) { 1450 void NaClSecureCommandChannel(struct NaClApp *nap) {
1719 struct NaClSecureService *secure_command_server; 1451 struct NaClSecureService *secure_command_server;
1720 1452
1721 static struct NaClSrpcHandlerDesc const secure_handlers[] = { 1453 static struct NaClSrpcHandlerDesc const secure_handlers[] = {
1722 { "hard_shutdown::", NaClSecureChannelShutdownRpc, }, 1454 { "hard_shutdown::", NaClSecureChannelShutdownRpc, },
1723 { "start_module::i", NaClSecureChannelStartModuleRpc, }, 1455 { "start_module::i", NaClSecureChannelStartModuleRpc, },
1724 { "log:is:", NaClSecureChannelLog, }, 1456 { "log:is:", NaClSecureChannelLog, },
1725 { "load_module:hs:", NaClLoadModuleRpc, }, 1457 { "load_module:hs:", NaClLoadModuleRpc, },
1726 { "load_irt:h:", NaClLoadIrtRpc, }, 1458 { "load_irt:h:", NaClLoadIrtRpc, },
1459 { "command_setup::h", NaClCommandServiceSetupRpc, },
1727 { "reverse_setup::h", NaClSecureReverseClientSetup, }, 1460 { "reverse_setup::h", NaClSecureReverseClientSetup, },
1728 /* add additional calls here. upcall set up? start module signal? */ 1461 /* add additional calls here. upcall set up? start module signal? */
1729 { (char const *) NULL, (NaClSrpcMethod) NULL, }, 1462 { (char const *) NULL, (NaClSrpcMethod) NULL, },
1730 }; 1463 };
1731 1464
1732 NaClLog(4, "Entered NaClSecureCommandChannel\n"); 1465 NaClLog(4, "Entered NaClSecureCommandChannel\n");
1733 1466
1734 secure_command_server = (struct NaClSecureService *) malloc( 1467 secure_command_server = (struct NaClSecureService *) malloc(
1735 sizeof *secure_command_server); 1468 sizeof *secure_command_server);
1736 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc", 1469 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc",
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
1829 nacl_global_xlate_base = mem_start; 1562 nacl_global_xlate_base = mem_start;
1830 1563
1831 NaClSandboxMemoryStartForValgrind(mem_start); 1564 NaClSandboxMemoryStartForValgrind(mem_start);
1832 1565
1833 _ovly_debug_event(); 1566 _ovly_debug_event();
1834 } 1567 }
1835 1568
1836 void NaClGdbHook(struct NaClApp const *nap) { 1569 void NaClGdbHook(struct NaClApp const *nap) {
1837 StopForDebuggerInit(nap->mem_start); 1570 StopForDebuggerInit(nap->mem_start);
1838 } 1571 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698