/* * read specified amount of bytes from given desc/offset to buffer * return amount of read bytes or negative error code if call failed */ static int32_t ZVMReadHandle(struct NaClApp *nap, int ch, char *buffer, int32_t size, int64_t offset) { struct ChannelDesc *channel; int64_t tail; char *sys_buffer; assert(nap != NULL); assert(nap->manifest != NULL); assert(nap->manifest->channels != NULL); /* check the channel number */ if(ch < 0 || ch >= nap->manifest->channels->len) { ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld", ch, buffer, size, offset); return -EINVAL; } channel = CH_CH(nap->manifest, ch); ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld", channel->alias, buffer, size, offset); /* check buffer and convert address */ if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_WRITE) == -1) return -EINVAL; sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t)buffer); /* ignore user offset for sequential access read */ if(CH_SEQ_READABLE(channel)) offset = channel->getpos; else /* prevent reading beyond the end of the random access channels */ size = MIN(channel->size - offset, size); /* check arguments sanity */ if(size == 0) return 0; /* success. user has read 0 bytes */ if(size < 0) return -EFAULT; if(offset < 0) return -EINVAL; /* check for eof */ if(channel->eof) return 0; /* check limits */ if(channel->counters[GetsLimit] >= channel->limits[GetsLimit]) return -EDQUOT; if(CH_RND_READABLE(channel)) if(offset >= channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit] + channel->size) return -EINVAL; /* calculate i/o leftovers */ tail = channel->limits[GetSizeLimit] - channel->counters[GetSizeLimit]; if(size > tail) size = tail; if(size < 1) return -EDQUOT; /* read data */ return ChannelRead(channel, sys_buffer, (size_t)size, (off_t)offset); }
/* * write specified amount of bytes from buffer to given desc/offset * return amount of read bytes or negative error code if call failed */ static int32_t ZVMWriteHandle(struct NaClApp *nap, int ch, const char *buffer, int32_t size, int64_t offset) { struct ChannelDesc *channel; int64_t tail; const char *sys_buffer; assert(nap != NULL); assert(nap->manifest != NULL); assert(nap->manifest->channels != NULL); /* check the channel number */ if(ch < 0 || ch >= nap->manifest->channels->len) { ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld", ch, buffer, size, offset); return -EINVAL; } channel = CH_CH(nap->manifest, ch); ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld", channel->alias, buffer, size, offset); /* check buffer and convert address */ if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL; sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer); /* ignore user offset for sequential access write */ if(CH_SEQ_WRITEABLE(channel)) offset = channel->putpos; /* check arguments sanity */ if(size == 0) return 0; /* success. user has read 0 bytes */ if(size < 0) return -EFAULT; if(offset < 0) return -EINVAL; /* check limits */ if(channel->counters[PutsLimit] >= channel->limits[PutsLimit]) return -EDQUOT; tail = channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit]; if(offset >= channel->limits[PutSizeLimit] && !((CH_RW_TYPE(channel) & 1) == 1)) return -EINVAL; if(offset >= channel->size + tail) return -EINVAL; if(size > tail) size = tail; if(size < 1) return -EDQUOT; /* write data */ return ChannelWrite(channel, sys_buffer, (size_t)size, (off_t)offset); }
/* * write specified amount of bytes from buffer to given desc/offset * return amount of read bytes or negative error code if call failed */ static int32_t ZVMWriteHandle(struct NaClApp *nap, int ch, const char *buffer, int32_t size, int64_t offset) { struct ChannelDesc *channel; int64_t tail; const char *sys_buffer; int32_t retcode = -1; assert(nap != NULL); assert(nap->system_manifest != NULL); assert(nap->system_manifest->channels != NULL); /* check the channel number */ if(ch < 0 || ch >= nap->system_manifest->channels_count) { ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=0x%lx, size=%d, offset=%ld", ch, (intptr_t)buffer, size, offset); return -EINVAL; } channel = &nap->system_manifest->channels[ch]; ZLOGS(LOG_DEBUG, "channel %s, buffer=0x%lx, size=%d, offset=%ld", channel->alias, (intptr_t)buffer, size, offset); /* check buffer and convert address */ if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL; sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer); /* ignore user offset for sequential access write */ if(CHANNEL_SEQ_WRITEABLE(channel)) offset = channel->putpos; /* check arguments sanity */ if(size == 0) return 0; /* success. user has read 0 bytes */ if(size < 0) return -EFAULT; if(offset < 0) return -EINVAL; /* check limits */ if(channel->counters[PutsLimit] >= channel->limits[PutsLimit]) return -EDQUOT; tail = channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit]; if(offset >= channel->limits[PutSizeLimit] && !CHANNEL_READABLE(channel)) return -EINVAL; if(offset >= channel->size + tail) return -EINVAL; if(size > tail) size = tail; if(size < 1) return -EDQUOT; /* write data and update position */ switch(channel->source) { case ChannelRegular: retcode = pwrite(channel->handle, sys_buffer, (size_t)size, (off_t)offset); if(retcode == -1) retcode = -errno; break; case ChannelCharacter: case ChannelFIFO: retcode = fwrite(sys_buffer, 1, (size_t)size, (FILE*)channel->socket); if(retcode == -1) retcode = -errno; break; case ChannelTCP: retcode = SendMessage(channel, sys_buffer, size); if(retcode == -1) retcode = -EIO; break; default: /* design error */ ZLOGFAIL(1, EFAULT, "invalid channel source"); break; } /* update the channel counter, size, position and tag */ ++channel->counters[PutsLimit]; if(retcode > 0) { channel->counters[PutSizeLimit] += retcode; UpdateChannelTag(channel, (const char*)sys_buffer, retcode); channel->putpos = offset + retcode; channel->size = (channel->type == SGetRPut) || (channel->type == RGetRPut) ? MAX(channel->size, channel->putpos) : channel->putpos; channel->getpos = channel->putpos; } return retcode; }
/* * read specified amount of bytes from given desc/offset to buffer * return amount of read bytes or negative error code if call failed */ static int32_t ZVMReadHandle(struct NaClApp *nap, int ch, char *buffer, int32_t size, int64_t offset) { struct ChannelDesc *channel; int64_t tail; char *sys_buffer; int32_t retcode = -1; assert(nap != NULL); assert(nap->system_manifest != NULL); assert(nap->system_manifest->channels != NULL); /* check the channel number */ if(ch < 0 || ch >= nap->system_manifest->channels_count) { ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=0x%lx, size=%d, offset=%ld", ch, (intptr_t)buffer, size, offset); return -EINVAL; } channel = &nap->system_manifest->channels[ch]; ZLOGS(LOG_DEBUG, "channel %s, buffer=0x%lx, size=%d, offset=%ld", channel->alias, (intptr_t)buffer, size, offset); /* check buffer and convert address */ if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL; sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer); /* ignore user offset for sequential access read */ if(CHANNEL_SEQ_READABLE(channel)) offset = channel->getpos; else /* prevent reading beyond the end of the random access channels */ size = MIN(channel->size - offset, size); /* check arguments sanity */ if(size == 0) return 0; /* success. user has read 0 bytes */ if(size < 0) return -EFAULT; if(offset < 0) return -EINVAL; /* check for eof */ if(channel->eof) return 0; /* check limits */ if(channel->counters[GetsLimit] >= channel->limits[GetsLimit]) return -EDQUOT; if(CHANNEL_RND_READABLE(channel)) if(offset >= channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit] + channel->size) return -EINVAL; /* calculate i/o leftovers */ tail = channel->limits[GetSizeLimit] - channel->counters[GetSizeLimit]; if(size > tail) size = tail; if(size < 1) return -EDQUOT; /* read data and update position */ switch(channel->source) { case ChannelRegular: retcode = pread(channel->handle, sys_buffer, (size_t)size, (off_t)offset); if(retcode == -1) retcode = -errno; break; case ChannelCharacter: case ChannelFIFO: retcode = fread(sys_buffer, 1, (size_t)size, (FILE*)channel->socket); if(retcode == -1) retcode = -errno; break; case ChannelTCP: retcode = FetchMessage(channel, sys_buffer, size); if(retcode == -1) retcode = -EIO; break; default: /* design error */ ZLOGFAIL(1, EFAULT, "invalid channel source"); break; } /* update the channel counter, size, position and tag */ ++channel->counters[GetsLimit]; if(retcode > 0) { channel->counters[GetSizeLimit] += retcode; UpdateChannelTag(channel, (const char*)sys_buffer, retcode); /* * current get cursor. must be updated if channel have seq get * but there is nothing wrong to update it even it have random get */ channel->getpos = offset + retcode; /* if channel have random put update put cursor. not allowed for cdr */ if(CHANNEL_RND_WRITEABLE(channel)) channel->putpos = offset + retcode; } /* * set eof if 0 bytes has been read. it is safe because * 1. if user asked for a 0 bytes control will not reach this code * 2. if user asked more then 0 bytes and got 0 that means end of data * 3. if quota exceeded user will get an error before an actual read */ if(retcode == 0) channel->eof = 1; return retcode; }