/// <summary>
	/// Unprotects a block of code so that it can be written to.
	/// </summary>
	/// <param name="code">Start of the region of code to unprotect.</param>
	/// <param name="size">Size of the region of code to unprotect.</param>
	/// <param name="oldProtection">Variable to receive the old protection state. The meaning of this value is platform-dependant.</param>
	/// <returns><c>true</c> if successful.</returns>
	bool unprotectCode(void *code, size_t size, int *oldProtection)
	{
		void *alignedCode;
		size_t alignedSize;
		pageAlign(code, size, &alignedCode, &alignedSize);
		
		const int newProtection = RWXProtection;
		if (mprotect(alignedCode, alignedSize, newProtection) != 0)
		{
			perror("Unprotection failed");
			return false;
		}
		
		// Look up old protection state in the protection map
		if (!protection)
		{
			protection = new std::unordered_map<void*, int>();
			*oldProtection = DefaultProtection;
		}
		else
		{
			std::unordered_map<void*, int>::const_iterator it = protection->find(alignedCode);
			if (it != protection->end())
				*oldProtection = it->second;
			else
				*oldProtection = DefaultProtection; // No easy way of querying this, so just assume it's default
		}
			
		(*protection)[alignedCode] = newProtection;
		return true;
	}
Exemple #2
0
void
ControlFile::ensureMapping()
{
    // If the file is not mmaped yet, first do a huge anonymous mmap
    // so that we never have to change the address, then mmap the
    // start of the file.
    if (!_mapBase) {
        int prot = PROT_READ;
        int flags = MAP_PRIVATE | MAP_ANON;
        int fd = -1;
        size_t length = pageAlign(_maxMapSize + 1);

        void *addr = mmap(NULL, length, prot, flags, fd, 0);
        if (!addr) {
            throwInvalid("Failed to get anonymous memory for control file: %s",
                         strerror(errno));
        }
        _mapBase = static_cast<char *>(addr);
        extendMapping();

        char *s = strstr(_mapBase, "Prefix: ");
        if (!s) {
            throwInvalid("Bad format of mapped file. bleh.");
        }
        _prefix = s + strlen("Prefix: ");
        _firstComponent = _mapBase + _maxPrefix + 25;
        _firstComponent = strchr(_firstComponent, '\n') + 1;
    }
}
Exemple #3
0
void
ControlFile::setPrefix(const char *prefix)
{
    if (prefix && !hasPrefix() && _prefix) {
        char buf[_maxPrefix + 1];
        sprintf(buf, "%.*s\n", _maxPrefix - 1, prefix);
        memcpy(_prefix, buf, strlen(buf));
        msync(_mapBase, pageAlign(1), MS_ASYNC | MS_INVALIDATE);
    }
}
Exemple #4
0
void
ControlFile::freeMapping()
{
    // If the file is mmapped, release all resource used
    if (_mapBase && (munmap(_mapBase, pageAlign(_maxMapSize + 1)) < 0)) {
        LOG(warning, "munmapping of loglevel settings failed: %s",
            strerror(errno));
    }
    _mapBase = NULL;
}
	/// <summary>
	/// Protects a block of code that was previously unprotected with <see cref="unprotectCode"/>.
	/// </summary>
	/// <param name="code">Start of the region of code to protect.</param>
	/// <param name="size">Size of the region of code to protect.</param>
	/// <param name="protection">The oldProtection value received from <see cref="unprotectCode"/>.
	/// <returns><c>true</c> if successful.</returns>
	bool protectCode(void *code, size_t size, int oldProtection)
	{
		void *alignedCode;
		size_t alignedSize;
		pageAlign(code, size, &alignedCode, &alignedSize);
		if (mprotect(alignedCode, alignedSize, oldProtection) != 0)
			return false;
			
		// Update protection state in the protection map
		if (!protection)
			protection = new std::unordered_map<void*, int>();
		if (oldProtection != DefaultProtection)
			(*protection)[alignedCode] = oldProtection;
		else
			protection->erase(alignedCode);
		return true;
	}
Exemple #6
0
bool
ControlFile::extendMapping()
{
    int fileLen = _fileBacking.size();

    if (fileLen == -1) {
        _fileBacking.unlock();
        LOG(error, "Cannot get file size of '%s': %s", _fileName,
            strerror(errno));
        return false;
    }

    if (fileLen >= _maxMapSize) {
        _fileBacking.unlock();
        LOG(error, "Log control file is too big at %d bytes (max "
            "size is %d). Ignoring it for further log components.",
            fileLen, _maxMapSize - 1);
        return false;
    }

    off_t size = pageAlign(fileLen);

    int prot = PROT_READ | (_mode == READONLY ? 0 : PROT_WRITE);
    int flags = MAP_FIXED | MAP_SHARED;
    int fd = _fileBacking.fd();
    if (mmap(_mapBase, size, prot, flags, fd, 0) != _mapBase) {
        _fileBacking.unlock();
        _mappedSize = -1;
        LOG(error, "failed to mmap lock file: %s", strerror(errno));
        return false;
    }
    _mappedSize = size;
    _fileSize = fileLen;

    return true;
}
Exemple #7
0
void MachOObject::loadSegments()
{
	for (Segment* seg : getSegments(*m_file))
	{
		uintptr_t mappingSize;
		int initprot, maxprot;
		void* mappingAddr;
		void* rv;
		int flags = MAP_PRIVATE;
		
		if (strcmp(seg->segname, SEG_PAGEZERO) == 0 || seg->vmsize == 0)
			continue;
		
		assert(seg->vmsize >= seg->filesize);
		
		if (!m_base)
		{
			mappingAddr = (void*) seg->vmaddr;
			
			if (mappingAddr < MachOMgr::instance()->maxAddress())
				mappingAddr = MachOMgr::instance()->maxAddress();
		}
		else
			mappingAddr = (void*) (seg->vmaddr + m_slide);
		
		mappingSize = pageAlign(seg->filesize);
		maxprot = machoProtectionFlagsToMmap(seg->maxprot);
		initprot = machoProtectionFlagsToMmap(seg->initprot);
	
		if (MachOMgr::instance()->printSegments())
			std::cerr << "dyld: Mapping segment " << seg->segname << " from " << m_file->filename() << " to " << mappingAddr << ", slide is 0x" << std::hex << m_slide << std::dec << std::endl;
		
#ifndef __arm__ // All executables on iOS are PIE
		// The first segment can be moved by mmap, but not the following ones
		auto filetype = m_file->header().filetype;
		if (m_base || (!(m_file->header().flags & MH_PIE) && filetype != MH_DYLIB && filetype != MH_BUNDLE))
			flags |= MAP_FIXED;
		else
#endif
		{
			// When letting the system decide where to place the mapping, we need to make sure that the spot chosen
			// is big enough for all segments
			uintptr_t size = getTotalMappingSize();
			rv = ::mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
			if (rv == MAP_FAILED)
			{
				std::stringstream ss;
				ss << "Failed to mmap temporary anonymous range: "  << strerror(errno);
				throw std::runtime_error(ss.str());
			}
			
			flags |= MAP_FIXED;
			mappingAddr = rv;
		}

		rv = ::mmap(mappingAddr, mappingSize, maxprot, flags, m_file->fd(), m_file->offset() + seg->fileoff);
		if (rv == MAP_FAILED)
		{
			std::stringstream ss;
			
			if (errno == EPERM && uintptr_t(mappingAddr) < getMinMappingAddr())
			{
				ss << "This executable is not position independent and your vm.mmap_min_addr is too low to load it. ";
				ss << "As low as " << uintptr_t(mappingAddr) << " is needed.";
			}
			else
				ss << "Failed to mmap '" << m_file->filename() << "': " << strerror(errno);
			throw std::runtime_error(ss.str());
		}
		if (!m_base)
		{
			m_slide = (intptr_t(rv) - intptr_t(seg->vmaddr));
			m_base = rv;
			mappingAddr = rv;
		}
		
		m_mappings.push_back(Mapping { mappingAddr, pageAlign(seg->vmsize), initprot, maxprot });

		if (seg->vmsize > mappingSize)
		{
			// Map empty pages to cover the vmsize range
			mappingAddr = (void*) (seg->vmaddr + m_slide + mappingSize);
			mappingSize = seg->vmsize - mappingSize;
			
			rv = ::mmap(mappingAddr, mappingSize, maxprot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
			//int err = ::mprotect(mappingAddr, mappingSize, maxprot);
			
			if (rv == MAP_FAILED)
			{
				std::stringstream ss;
				ss << "Failed to mmap anonymous pages for '" << m_file->filename() << "': " << strerror(errno);
				throw std::runtime_error(ss.str());
			}
		}
	}
}