/* * mount given channel (must be constructed) with a given mode/attributes * return 0 - when everything is ok, otherwise - negative error */ int MountChannel(struct NaClApp *nap, enum ChannelType ch) { struct PreOpenedFileDesc *channel = &nap->manifest->user_setup->channels[ch]; if(channel) { switch(channel->mounted) { int code; case MAPPED: code = PremapChannel(nap, channel); COND_ABORT(code, "cannot premap channel\n"); break; case LOADED: code = PreloadChannel(nap, channel); COND_ABORT(code, "cannot preload channel\n"); break; case NETWORK: code = PrefetchChannel(nap, channel); COND_ABORT(code, "cannot allocate network channel\n"); break; default: COND_ABORT(1, "mounting method not supported\n"); break; } } return 0; }
/* * construct SetupList (policy) part of manifest structure (w/o channels) * note: malloc(). must be called only once */ void SetupUserPolicy(struct NaClApp *nap) { /* allocate space for policy */ struct SetupList *policy = malloc(sizeof(*policy)); COND_ABORT(!policy, "cannot allocate memory for user policy\n"); policy->self_size = sizeof(*policy); /* set self size */ /* setup limits */ TRANSET(policy->max_cpu, "CPUMax"); TRANSET(policy->max_mem, "MemMax"); TRANSET(policy->max_setup_calls, "SetupCallsMax"); TRANSET(policy->max_syscalls, "SyscallsMax"); /* setup counters */ policy->cnt_cpu = 0; policy->cnt_cpu_last = 0; policy->cnt_mem = 0; policy->cnt_setup_calls = 0; policy->cnt_syscalls = 0; policy->heap_ptr = 0; /* set user heap to NULL until it allocated */ /* clear syscallback */ policy->syscallback = 0; /* setup custom attributes */ #define STRNCPY_NULL(a, b, n) if ((a) && (b)) strncpy(a, b, n); STRNCPY_NULL(policy->content_type, get_value_by_key(nap, "ContentType"), CONTENT_TYPE_LEN); STRNCPY_NULL(policy->timestamp, get_value_by_key(nap, "TimeStamp"), TIMESTAMP_LEN); STRNCPY_NULL(policy->x_object_meta_tag, get_value_by_key(nap, "XObjectMetaTag"), X_OBJECT_META_TAG_LEN); STRNCPY_NULL(policy->user_etag, get_value_by_key(nap, "UserETag"), USER_TAG_LEN); #undef STRNCPY_NULL nap->manifest->user_setup = policy; }
/* * preallocate channel. for output files only. since we cannot say how much user * program will use we only can allocate max size provided for current channel * note: must be called from PremapChannel() after file opened and measured * note: user_log file will be trimmed to asciiz string size it contain */ static void PreallocateChannel(struct PreOpenedFileDesc* channel) { if(channel->fsize != channel->max_size && (channel->type == OutputChannel || channel->type == LogChannel)) { int ret_code = ftruncate(channel->handle, channel->max_size); COND_ABORT(ret_code < 0, "cannot set the channel size\n"); channel->fsize = channel->max_size; } }
/* * preload given file (channel). return 0 if success, otherwise negative errcode */ int PreloadChannel(struct NaClApp *nap, struct PreOpenedFileDesc* channel) { /* debug checks */ if(!channel->name) return -1; /* channel is not constructed. skip it */ COND_ABORT(channel->mounted != LOADED, "channel is not supposed to be loaded\n"); /* open file */ channel->handle = open((char*)channel->name, GetChannelOpenFlags(channel), S_IRWXU); COND_ABORT(channel->handle < 0, "channel open error\n"); /* check if given file in bounds of manifest limits */ channel->fsize = GetFileSize((char*)channel->name); PreallocateChannel(channel); COND_ABORT(channel->max_size < channel->fsize, "channel legnth exceeded policy limit\n"); /* mounting finalization */ channel->bsize = -1; /* will be provided by user */ return 0; }
/* * construct SystemList (zerovm settings) part of manifest structure * note: malloc(). must be called only once */ void SetupSystemPolicy(struct NaClApp *nap) { /* allocate space for policy */ struct SystemList *policy = malloc(sizeof(*policy)); COND_ABORT(!policy, "cannot allocate memory for system policy\n"); /* get zerovm settings */ policy->version = get_value_by_key(nap, "Version"); policy->zerovm = get_value_by_key(nap, "ZeroVM"); policy->log = get_value_by_key(nap, "Log"); policy->report = get_value_by_key(nap, "Report"); COND_ABORT(policy->nexe, "nexe file name is already specified in the command line\n"); policy->nexe = get_value_by_key(nap, "Nexe"); policy->blob = get_value_by_key(nap, "Blob"); policy->nexe_etag = get_value_by_key(nap, "NexeEtag"); TRANSET(policy->nexe_max, "NexeMax"); TRANSET(policy->timeout, "Timeout"); TRANSET(policy->kill_timeout, "KillTimeout"); nap->manifest->system_setup = policy; }
/* * construct Report (zerovm report to proxy) part of manifest structure * note: malloc(). must be called only once */ void SetupReportSettings(struct NaClApp *nap) { /* allocate space for report */ struct Report *report = malloc(sizeof(*report)); // ### memory must be allocated before nexe start COND_ABORT(!report, "cannot allocate memory for report\n"); /* set results */ report->etag = MakeEtag(nap); report->content_type = "application/octet-stream"; // where to get it? report->x_object_meta_tag = "Format:Pickle"; // where to get it? /* ### ret codes must be set from main() */ nap->manifest->report = report; }
/* * construct Report (zerovm report to proxy) part of manifest structure * note: malloc(). must be called only once */ void SetupReportSettings(struct NaClApp *nap) { /* * allocate space for report * todo: memory must be allocated before nexe start */ struct Report *report = malloc(sizeof(*report)); COND_ABORT(!report, "cannot allocate memory for report\n"); /* set results. note: etag is temporary disabled */ report->etag = MakeEtag(nap); /* get custom attributes from the manifest */ report->content_type = get_value_by_key(nap, "ContentType"); report->x_object_meta_tag = get_value_by_key(nap, "XObjectMetaTag"); nap->manifest->report = report; }
/* * preallocate memory area of given size. abort if fail */ void PreallocateUserMemory(struct NaClApp *nap) { struct SetupList *policy = nap->manifest->user_setup; uintptr_t i = nap->data_end; uint32_t stump = nap->manifest->user_setup->max_mem - nap->stack_size - nap->data_end; uint32_t dead_space; struct NaClVmmapEntry *user_space; /* check if max_mem is specified in manifest and proceed if so */ if(!policy->max_mem) return; /* user memory chunk must be allocated next to the data end */ i = (i + NACL_MAP_PAGESIZE - 1) & ~(NACL_MAP_PAGESIZE - 1); policy->heap_ptr = NaClCommonSysMmapIntern(nap, (void*)i, stump, 3, 0x22, -1, 0); assert(policy->heap_ptr == i); /* * free "whole chunk" block without real memory deallocation * the map entry we need is the last in raw */ user_space = nap->mem_map.vmentry[nap->mem_map.nvalid - 1]; assert(policy->heap_ptr / NACL_PAGESIZE == user_space->page_num); assert(nap->mem_map.is_sorted != 1); /* protect dead space */ dead_space = NaClVmmapFindMaxFreeSpace(&nap->mem_map, 1) * NACL_PAGESIZE; i = (user_space->page_num + user_space->npages) * NACL_PAGESIZE; dead_space = NaClCommonSysMmapIntern(nap, (void*)i, dead_space, 0, 0x22, -1, 0); assert(dead_space == i); /* sort and remove deleted blocks */ user_space->removed = 1; nap->mem_map.is_sorted = 0; /* force sort because we need to get rid of removed blocks */ NaClVmmapMakeSorted(&nap->mem_map); /* why 0xfffff000? 1. 0x1000 reserved for error codes 2. it is still larger then 4gb - stack */ COND_ABORT(policy->heap_ptr > 0xfffff000, "cannot preallocate memory for user\n"); }
/* * construct SystemList (zerovm settings) part of manifest structure * note: malloc(). must be called only once */ void SetupSystemPolicy(struct NaClApp *nap) { /* allocate space for policy */ struct SystemList *policy = malloc(sizeof(*policy)); COND_ABORT(!policy, "cannot allocate memory for system policy\n"); /* get zerovm settings */ policy->version = GetValueByKey(nap, "Version"); policy->zerovm = GetValueByKey(nap, "ZeroVM"); policy->log = GetValueByKey(nap, "Log"); policy->report = GetValueByKey(nap, "Report"); policy->nexe = GetValueByKey(nap, "Nexe"); policy->cmd_line = GetValueByKey(nap, "CommandLine"); policy->blob = GetValueByKey(nap, "Blob"); policy->nexe_etag = GetValueByKey(nap, "NexeEtag"); TRANSET(policy->nexe_max, "NexeMax"); TRANSET(policy->timeout, "Timeout"); TRANSET(policy->kill_timeout, "KillTimeout"); nap->manifest->system_setup = policy; }
/* * premap given file (channel). return 0 if success, otherwise negative errcode * note: malloc() */ int PremapChannel(struct NaClApp *nap, struct PreOpenedFileDesc* channel) { int desc; struct NaClHostDesc *hd = malloc(sizeof(*hd)); /* debug checks */ COND_ABORT(!hd, "cannot allocate memory to hold channel descriptor\n"); COND_ABORT(!channel, "channel is not constructed\n"); COND_ABORT(channel->mounted != MAPPED, "channel is not supposed to be mapped\n"); COND_ABORT(!channel->name, "cannot resolve channel name\n"); /* open file */ channel->handle = open((char*)channel->name, GetChannelOpenFlags(channel), S_IRWXU); COND_ABORT(channel->handle < 0, "channel open error\n"); /* check if given file in bounds of manifest limits */ channel->fsize = GetFileSize((char*)channel->name); PreallocateChannel(channel); COND_ABORT(channel->max_size < channel->fsize, "channel legnth exceeded policy limit\n"); /* construct nacl descriptor */ hd->d = channel->handle; desc = NaClSetAvail(nap, ((struct NaClDesc *) NaClDescIoDescMake(hd))); /* map whole file into the memory. address cannot be higher than stack */ channel->buffer = NaClCommonSysMmapIntern(nap, NULL, channel->fsize, GetChannelMapProt(channel), GetChannelMapFlags(channel), desc, 0); COND_ABORT((uint32_t)channel->buffer > 0xFF000000, "channel map error\n"); /* mounting finalization */ close(channel->handle); channel->bsize = channel->fsize; /* yes. mapped file always put to memory whole */ channel->handle = -1; /* there is no opened file for mapped channel */ return 0; }
/* * infere file open flags by channel prefix */ static int GetChannelOpenFlags(struct PreOpenedFileDesc* channel) { int flags[] = CHANNEL_OPEN_FLAGS; COND_ABORT(channel->type >= sizeof(flags)/sizeof(*flags), "unknown channel type\n"); return flags[channel->type]; }
/* * set "prefix" (channel name) by "ch" (channel id) * note: prefix must have enough space to hold it */ static void GetChannelPrefixById(enum ChannelType ch, char *prefix) { char *prefixes[] = CHANNEL_PREFIXES; COND_ABORT(ch >= sizeof(prefixes)/sizeof(*prefixes), "unknown channel id\n"); strcpy(prefix, prefixes[ch]); }