diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/CMakeLists.txt b/CMakeLists.txt index 50aa33a..ab33341 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,10 @@ if(ENABLE_BUILD_GUEST) include_dependency(BOXY_SOURCE_DEPENDS_DIR linux) endif() +if(ENABLE_BUILD_GUEST AND ENABLE_BUILD_EXAMPLES) + include_dependency(BOXY_SOURCE_DEPENDS_DIR buildroot) +endif() + # ------------------------------------------------------------------------------ # VMM # ------------------------------------------------------------------------------ @@ -86,3 +90,22 @@ if(NOT WIN32 AND NOT CYGWIN) DEPENDS bfintrinsics ) endif() + +# ------------------------------------------------------------------------------ +# Examples +# ------------------------------------------------------------------------------ + +if(ENABLE_BUILD_EXAMPLES AND NOT WIN32 AND NOT CYGWIN) + add_subproject( + vmilinux userspace + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/examples/vmilinux + DEPENDS bflinux + ) +endif() + +# ------------------------------------------------------------------------------ +# Validate Build +# ------------------------------------------------------------------------------ + +include(${CMAKE_CURRENT_LIST_DIR}/scripts/cmake/validate.cmake) +validate_build() \ No newline at end of file diff --git a/bfbuilder/src/platform/linux/intrinsics.S b/bfbuilder/src/platform/linux/intrinsics.S index b13f4c0..b30b171 100644 --- a/bfbuilder/src/platform/linux/intrinsics.S +++ b/bfbuilder/src/platform/linux/intrinsics.S @@ -74,7 +74,7 @@ _mv_handle_op_close_handle: mov r10, rdi - mov rax, 0x764D000000010000 + mov rax, 0x764D000000010001 vmcall ret @@ -104,6 +104,139 @@ _mv_vm_properties_op_set_e820: ret .size _mv_vm_properties_op_set_e820, .-_mv_vm_properties_op_set_e820 +/* -------------------------------------------------------------------------- */ +/* _mv_vm_state_op_gva_to_gpa */ +/* -------------------------------------------------------------------------- */ + + .globl _mv_vm_state_op_gva_to_gpa + .type _mv_vm_state_op_gva_to_gpa, @function +_mv_vm_state_op_gva_to_gpa: + + push r12 + push r13 + + mov r10, rdi + mov r11, rsi + mov r12, rdx + mov r13, rcx + + mov rax, 0x764D000000030008 + vmcall + + mov [r8], r10 + mov [r9], r11 + + pop r13 + pop r12 + ret + .size _mv_vm_state_op_gva_to_gpa, .-_mv_vm_state_op_gva_to_gpa + +/* -------------------------------------------------------------------------- */ +/* _mv_vm_state_op_map_range */ +/* -------------------------------------------------------------------------- */ + + .globl _mv_vm_state_op_map_range + .type _mv_vm_state_op_map_range, @function +_mv_vm_state_op_map_range: + + push r12 + push r13 + push r14 + push r15 + + mov r10, rdi + mov r11, rsi + mov r12, rdx + mov r13, rcx + mov r14, r8 + mov r15, r9 + + mov rax, 0x764D000000030009 + vmcall + + pop r15 + pop r14 + pop r13 + pop r12 + ret + .size _mv_vm_state_op_map_range, .-_mv_vm_state_op_map_range + +/* -------------------------------------------------------------------------- */ +/* _mv_vm_state_op_unmap_range */ +/* -------------------------------------------------------------------------- */ + + .globl _mv_vm_state_op_unmap_range + .type _mv_vm_state_op_unmap_range, @function +_mv_vm_state_op_unmap_range: + + push r12 + push r13 + push r14 + push r15 + + mov r10, rdi + mov r11, rsi + mov r12, rdx + mov r13, rcx + mov r14, r8 + mov r15, r9 + + mov rax, 0x764D00000003000A + vmcall + + pop r15 + pop r14 + pop r13 + pop r12 + ret + .size _mv_vm_state_op_unmap_range, .-_mv_vm_state_op_unmap_range + +/* -------------------------------------------------------------------------- */ +/* _mv_vp_state_op_reg_val */ +/* -------------------------------------------------------------------------- */ + + .globl _mv_vp_state_op_reg_val + .type _mv_vp_state_op_reg_val, @function +_mv_vp_state_op_reg_val: + + push r12 + + mov r10, rdi + mov r11, rsi + mov r12, rdx + + mov rax, 0x764D000000070000 + vmcall + + mov [rcx], r10 + + pop r12 + ret + .size _mv_vp_state_op_reg_val, .-_mv_vp_state_op_reg_val + +/* -------------------------------------------------------------------------- */ +/* _mv_vp_state_op_msr_val */ +/* -------------------------------------------------------------------------- */ + + .globl _mv_vp_state_op_msr_val + .type _mv_vp_state_op_msr_val, @function +_mv_vp_state_op_msr_val: + + push r12 + + mov r10, rdi + mov r11, rsi + mov r12, rdx + + mov rax, 0x764D000000070004 + vmcall + + mov [rcx], r10 + + pop r12 + ret + .size _mv_vp_state_op_msr_val, .-_mv_vp_state_op_msr_val + /* -------------------------------------------------------------------------- */ /* !!! WARNING DEPRECATED !!! */ /* -------------------------------------------------------------------------- */ diff --git a/bfbuilder/src/platform/windows/intrinsics.asm b/bfbuilder/src/platform/windows/intrinsics.asm index 4b2b735..c21907a 100644 --- a/bfbuilder/src/platform/windows/intrinsics.asm +++ b/bfbuilder/src/platform/windows/intrinsics.asm @@ -1,53 +1,266 @@ -; -; Copyright (C) 2019 Assured Information Security, Inc. -; -; Permission is hereby granted, free of charge, to any person obtaining a copy -; of this software and associated documentation files (the "Software"), to deal -; in the Software without restriction, including without limitation the rights -; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -; copies of the Software, and to permit persons to whom the Software is -; furnished to do so, subject to the following conditions: -; -; The above copyright notice and this permission notice shall be included in all -; copies or substantial portions of the Software. -; -; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -; SOFTWARE. - -.code - -_cpuid_eax PROC - - push rbx - - mov eax, ecx - mov ecx, 0 - cpuid - - pop rbx - ret - -_cpuid_eax ENDP - -_vmcall PROC - - push rbx - - mov rax, rcx - mov rbx, rdx - mov rcx, r8 - mov rdx, r9 - - vmcall - - pop rbx - ret - -_vmcall ENDP - -end +; +; Copyright (C) 2019 Assured Information Security, Inc. +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + +.code + +;------------------------------------------------------------------------------- +; _mv_cpuid +;------------------------------------------------------------------------------- + +_mv_cpuid PROC + + push rbx + + mov r10, rcx + mov r11, rdx + + mov eax, [rcx] + cpuid + + mov [r10], eax + mov [r11], ebx + mov [r8], ecx + mov [r9], edx + + pop rbx + ret + +_mv_cpuid ENDP + +;------------------------------------------------------------------------------- +; _mv_handle_op_open_handle +;------------------------------------------------------------------------------- + +_mv_handle_op_open_handle PROC + + mov r11, rcx + + mov rax, 764D000000010000h + vmcall + + mov [rdx], r10 + + ret +_mv_handle_op_open_handle ENDP + +;------------------------------------------------------------------------------- +; _mv_handle_op_close_handle +;------------------------------------------------------------------------------- + +_mv_handle_op_close_handle PROC + + mov r10, rcx + + mov rax, 764D000000010001h + vmcall + + ret + +_mv_handle_op_close_handle ENDP + +;------------------------------------------------------------------------------- +; _mv_vm_properties_op_set_e820 +;------------------------------------------------------------------------------- + +_mv_vm_properties_op_set_e820 PROC + + push r12 + push r13 + + mov r10, rcx + mov r11, rdx + mov r12, r8 + mov r13, r9 + + mov rax, 764D000000020006h + vmcall + + pop r13 + pop r12 + ret + +_mv_vm_properties_op_set_e820 ENDP + +;------------------------------------------------------------------------------- +; _mv_vm_state_op_gva_to_gpa +;------------------------------------------------------------------------------- + +_mv_vm_state_op_gva_to_gpa PROC + + push r12 + push r13 + + mov r10, rcx + mov r11, rdx + mov r12, r8 + mov r13, r9 + + mov rax, 764D000000030008h + vmcall + + mov r8, [rsp+28h+8*2] + mov r9, [rsp+30h+8*2] + + mov [r8], r10 + mov [r9], r11 + + pop r13 + pop r12 + ret + +_mv_vm_state_op_gva_to_gpa ENDP + +;------------------------------------------------------------------------------- +; _mv_vm_state_op_map_range +;------------------------------------------------------------------------------- + +_mv_vm_state_op_map_range PROC + + push r12 + push r13 + push r14 + push r15 + + mov r10, rcx + mov r11, rdx + mov r12, r8 + mov r13, r9 + mov r14, [rsp+28h+8*4] + mov r15, [rsp+30h+8*4] + + mov rax, 764D000000030009h + vmcall + + pop r15 + pop r14 + pop r13 + pop r12 + ret + +_mv_vm_state_op_map_range ENDP + +;------------------------------------------------------------------------------- +; _mv_vm_state_op_unmap_range +;------------------------------------------------------------------------------- + +_mv_vm_state_op_unmap_range PROC + + push r12 + push r13 + push r14 + push r15 + + mov r10, rcx + mov r11, rdx + mov r12, r8 + mov r13, r9 + mov r14, [rsp+28h+8*4] + mov r15, [rsp+30h+8*4] + + mov rax, 764D00000003000Ah + vmcall + + pop r15 + pop r14 + pop r13 + pop r12 + ret + +_mv_vm_state_op_unmap_range ENDP + +;------------------------------------------------------------------------------- +; _mv_vp_state_op_reg_val +;------------------------------------------------------------------------------- + +_mv_vp_state_op_reg_val PROC + + push r12 + + mov r10, rcx + mov r11, rdx + mov r12, r8 + + mov rax, 764D000000070000h + vmcall + + mov [r9], r10 + + pop r12 + ret + +_mv_vp_state_op_reg_val ENDP + +;------------------------------------------------------------------------------- +; _mv_vp_state_op_msr_val +;------------------------------------------------------------------------------- + +_mv_vp_state_op_msr_val PROC + + push r12 + + mov r10, rcx + mov r11, rdx + mov r12, r8 + + mov rax, 764D000000070004h + vmcall + + mov [r9], r10 + + pop r12 + ret + +_mv_vp_state_op_msr_val ENDP + +;------------------------------------------------------------------------------- +; !!! WARNING DEPRECATED !!! +;------------------------------------------------------------------------------- + +_cpuid_eax PROC + + push rbx + + mov eax, ecx + mov ecx, 0 + cpuid + + pop rbx + ret + +_cpuid_eax ENDP + +_vmcall PROC + + push rbx + + mov rax, rcx + mov rbx, rdx + mov rcx, r8 + mov rdx, r9 + + vmcall + + pop rbx + ret + +_vmcall ENDP + +end diff --git a/bfsdk/include/bfhypercall.h b/bfsdk/include/bfhypercall.h index 182fd0a..609b5b2 100644 --- a/bfsdk/include/bfhypercall.h +++ b/bfsdk/include/bfhypercall.h @@ -1059,11 +1059,11 @@ mv_vm_state_op_gva_to_gpa( } if (MV_NULL == gpa) { - return MV_STATUS_INVALID_PARAMS3; + return MV_STATUS_INVALID_PARAMS4; } if (MV_NULL == flags) { - return MV_STATUS_INVALID_PARAMS3; + return MV_STATUS_INVALID_PARAMS5; } return _mv_vm_state_op_gva_to_gpa( @@ -1368,7 +1368,7 @@ mv_vm_management_op_resume_vm( // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- -// VMID +// VPID // ----------------------------------------------------------------------------- #define MV_VPID_SELF ((mv_uint64_t)0xFFFFFFFFFFFFFFF0) @@ -1930,7 +1930,9 @@ hypercall_uart_ndec_op(uint16_t port, uint64_t val) #define hypercall_enum_domain_op__ldtr_access_rights 0xBF02000000020730 #define hypercall_enum_domain_op__set_ldtr_access_rights 0xBF02000000020731 +#ifndef UART_MAX_BUFFER #define UART_MAX_BUFFER 0x4000 +#endif static inline domainid_t hypercall_domain_op__create_domain(void) diff --git a/bfvmm/include/hve/arch/intel_x64/domain.h b/bfvmm/include/hve/arch/intel_x64/domain.h index e5e851b..3af121f 100644 --- a/bfvmm/include/hve/arch/intel_x64/domain.h +++ b/bfvmm/include/hve/arch/intel_x64/domain.h @@ -205,6 +205,52 @@ class domain : public boxy::domain /// void release(uintptr_t gpa); + /// Share Range + /// + /// Share a range of 4k guest physical addresses from foreign mmap using EPT + /// effectivily remapping our guest physical addresses to their host + /// physical addresses. + /// + /// The caller must invalidate the translations derived from EPT with + /// invept. + /// + /// @expects + /// @ensures + /// + /// @param gpa the guest physical address to remap + /// @param foreign_gpa the foreign guest physical address to remap from + /// @param foreign_mmap the foreign mmap to remap from + /// @param size the number of GPA to remap + /// @param attr the map permissions apply to our GPAs being remapped + /// @param cache the memory type for our remapped GPAs + /// + void share_range( + uintptr_t gpa, + uintptr_t foreign_gpa, bfvmm::intel_x64::ept::mmap &foreign_mmap, + uint32_t size, + bfvmm::intel_x64::ept::mmap::attr_type attr, + bfvmm::intel_x64::ept::mmap::memory_type cache); + + /// Unshare Range + /// + /// Unshare a range of 4k guest physical addresses previously assigned with + /// share_range. + /// + /// The caller must invalidate the translations derived from EPT with + /// invept. + /// + /// @expects + /// @ensures + /// + /// @param gpa the guest physical address to restore + /// @param size the number of GPA to restore + /// @param attr the map permissions apply to our GPAs being remapped + /// @param cache the memory type for our remapped GPAs + void unshare_range( + uintptr_t gpa, uint32_t size, + bfvmm::intel_x64::ept::mmap::attr_type attr, + bfvmm::intel_x64::ept::mmap::memory_type cache); + public: /// Set UART @@ -432,6 +478,9 @@ class domain : public boxy::domain mv_mdl_t m_e820_map{}; bfvmm::intel_x64::vcpu_global_state_t m_vcpu_global_state{}; + std::unordered_map m_range_sizes; + std::mutex m_mutex; + uart::port_type m_uart_port{}; uart::port_type m_pt_uart_port{}; uart m_uart_3F8{0x3F8}; diff --git a/bfvmm/include/hve/arch/intel_x64/vcpu.h b/bfvmm/include/hve/arch/intel_x64/vcpu.h index b76b9fa..8c6f007 100644 --- a/bfvmm/include/hve/arch/intel_x64/vcpu.h +++ b/bfvmm/include/hve/arch/intel_x64/vcpu.h @@ -388,6 +388,27 @@ class vcpu : public bfvmm::intel_x64::vcpu /// void halt(const std::string &str = {}) override; +public: + + //-------------------------------------------------------------------------- + // Model-specific registers + //-------------------------------------------------------------------------- + + /// Get MSR Register Value + /// + /// @param msr the msr to get + /// + VIRTUAL uint64_t msr(uint32_t msr) const; + + /// Set MSR Register Value + /// + /// @param msr the msr to set + /// @param val the value to set the msr with + /// + VIRTUAL void set_msr(uint32_t msr, uint64_t val); + + /// @cond + private: void write_dom0_guest_state(domain *domain); diff --git a/bfvmm/include/hve/arch/intel_x64/vmcall/vm_state_op.h b/bfvmm/include/hve/arch/intel_x64/vmcall/vm_state_op.h index 77b46bd..26a9ec2 100644 --- a/bfvmm/include/hve/arch/intel_x64/vmcall/vm_state_op.h +++ b/bfvmm/include/hve/arch/intel_x64/vmcall/vm_state_op.h @@ -54,6 +54,14 @@ class vm_state_op_handler private: + void gva_to_gpa(vcpu *vcpu); + + std::tuple map_range_init(vcpu *vp); + void map_range(vcpu *vcpu); + void unmap_range(vcpu *vcpu); + bool dispatch(vcpu *vcpu); private: diff --git a/bfvmm/include/hve/arch/intel_x64/vmcall/vp_state_op.h b/bfvmm/include/hve/arch/intel_x64/vmcall/vp_state_op.h index f0b499c..b2e3913 100644 --- a/bfvmm/include/hve/arch/intel_x64/vmcall/vp_state_op.h +++ b/bfvmm/include/hve/arch/intel_x64/vmcall/vp_state_op.h @@ -54,6 +54,10 @@ class vp_state_op_handler private: + vcpu *init_target(vcpu *vp); + void reg_val(vcpu *vp); + void msr_val(vcpu *vp); + bool dispatch(vcpu *vcpu); private: diff --git a/bfvmm/include/hve/arch/intel_x64/vmexit/msr.h b/bfvmm/include/hve/arch/intel_x64/vmexit/msr.h index 01aac7b..530c09a 100644 --- a/bfvmm/include/hve/arch/intel_x64/vmexit/msr.h +++ b/bfvmm/include/hve/arch/intel_x64/vmexit/msr.h @@ -94,6 +94,15 @@ class msr_handler /// @endcond +public: + + /// @cond + + uint64_t get_msr(uint32_t msr) const; + void set_msr(uint32_t msr, uint64_t val); + + /// @endcond + private: vcpu *m_vcpu; diff --git a/bfvmm/src/hve/arch/intel_x64/domain.cpp b/bfvmm/src/hve/arch/intel_x64/domain.cpp index fb2b596..c8d548a 100644 --- a/bfvmm/src/hve/arch/intel_x64/domain.cpp +++ b/bfvmm/src/hve/arch/intel_x64/domain.cpp @@ -120,6 +120,55 @@ void domain::release(uintptr_t gpa) { m_ept_map.release(gpa); } +void +domain::share_range( + uintptr_t gpa, + uintptr_t foreign_gpa, bfvmm::intel_x64::ept::mmap &foreign_mmap, + uint32_t size, + bfvmm::intel_x64::ept::mmap::attr_type attr, + bfvmm::intel_x64::ept::mmap::memory_type cache) +{ + std::lock_guard lock(m_mutex); + using namespace ::intel_x64::ept; + + auto &range_size = m_range_sizes[gpa]; + if (range_size != 0) { + throw std::runtime_error("share_range: map range already exists"); + } + range_size = size; + + for (auto _foreign_gpa = foreign_gpa, _gpa = gpa; + _foreign_gpa < (foreign_gpa + (size << pt::from)); + _foreign_gpa += (0x1ULL << pt::from), _gpa += (0x1ULL << pt::from)) { + + m_ept_map.share_4k(_gpa, _foreign_gpa, foreign_mmap, attr, cache); + } +} + +void +domain::unshare_range( + uintptr_t gpa, uint32_t size, + bfvmm::intel_x64::ept::mmap::attr_type attr, + bfvmm::intel_x64::ept::mmap::memory_type cache) + +{ + std::lock_guard lock(m_mutex); + using namespace ::intel_x64::ept; + + if (m_range_sizes[gpa] != size) { + throw std::runtime_error("unshare_range: size is different from original one"); + } + + for (auto _gpa = gpa; + _gpa < (gpa + (size << pt::from)); + _gpa += (0x1ULL << pt::from)) { + + m_ept_map.unshare_4k(_gpa, attr, cache); + } + + m_range_sizes.erase(gpa); +} + void domain::set_uart(uart::port_type uart) noexcept { m_uart_port = uart; } diff --git a/bfvmm/src/hve/arch/intel_x64/vcpu.cpp b/bfvmm/src/hve/arch/intel_x64/vcpu.cpp index bae35b8..0d29e04 100644 --- a/bfvmm/src/hve/arch/intel_x64/vcpu.cpp +++ b/bfvmm/src/hve/arch/intel_x64/vcpu.cpp @@ -305,6 +305,22 @@ vcpu::halt(const std::string &str) } } +//------------------------------------------------------------------------------ +// Model-specific registers +//------------------------------------------------------------------------------ + +uint64_t +vcpu::msr(uint32_t msr) const +{ + return m_msr_handler.get_msr(msr); +} + +void +vcpu::set_msr(uint32_t msr, uint64_t val) +{ + m_msr_handler.set_msr(msr, val); +} + //------------------------------------------------------------------------------ // Setup Functions //------------------------------------------------------------------------------ diff --git a/bfvmm/src/hve/arch/intel_x64/vmcall/handle_op.cpp b/bfvmm/src/hve/arch/intel_x64/vmcall/handle_op.cpp index 33ac7bb..78d8071 100644 --- a/bfvmm/src/hve/arch/intel_x64/vmcall/handle_op.cpp +++ b/bfvmm/src/hve/arch/intel_x64/vmcall/handle_op.cpp @@ -30,10 +30,6 @@ handle_op_handler::handle_op_handler( ) : m_vcpu{vcpu} { - if (vcpu->is_domU()) { - return; - } - vcpu->add_vmcall_handler({&handle_op_handler::dispatch, this}); } diff --git a/bfvmm/src/hve/arch/intel_x64/vmcall/vm_state_op.cpp b/bfvmm/src/hve/arch/intel_x64/vmcall/vm_state_op.cpp index db0c638..c397162 100644 --- a/bfvmm/src/hve/arch/intel_x64/vmcall/vm_state_op.cpp +++ b/bfvmm/src/hve/arch/intel_x64/vmcall/vm_state_op.cpp @@ -31,11 +31,183 @@ vm_state_op_handler::vm_state_op_handler( ) : m_vcpu{vcpu} { - if (vcpu->is_domU()) { + vcpu->add_vmcall_handler({&vm_state_op_handler::dispatch, this}); +} + + +void +vm_state_op_handler::gva_to_gpa(vcpu *vcpu) +{ + auto vmid{vcpu->r11()}; + auto ptt_gpa{vcpu->r12()}; + auto gva{vcpu->r13()}; + uint64_t gpa = 0; + uint64_t flags = 0; + + bool is_self = vmid == MV_VMID_SELF || vmid == vcpu->domid(); + + if (is_self) { + gpa = vcpu->gva_to_gpa(gva).first; + } + else { + // TODO: translate gva given ptt_gpa for root and guests + throw std::runtime_error("gva_to_gpa: non-self is not yet implemented"); + } + + // TODO handle flags; + + if (!is_self) { + vcpu->load(); + } + + vcpu->set_r10(gpa); + vcpu->set_r11(flags); + + vcpu->set_rax(MV_STATUS_SUCCESS); +} + +inline std::tuple + vm_state_op_handler::map_range_init(vcpu *vp) +{ + auto src_vmid{vp->r11()}; + auto src_gpa{vp->r12()}; + auto dst_vmid{vp->r13()}; + auto dst_gpa{vp->r14()}; + auto flags{vp->r15()}; + auto size{(flags & 0x00000000FFFFFFFF) != 0 ? : 1}; + + using namespace bfvmm::intel_x64::ept; + + mmap::attr_type attr = mmap::attr_type::read_only; + mmap::memory_type cache = mmap::memory_type::write_back; + + domain *src_vm; + domain *dst_vm; + + switch (src_vmid) { + case MV_VMID_ROOT: + src_vm = get_domain(0); + break; + default: + throw std::runtime_error( + "map_range: non-root source is not yet implemented"); + } + + switch (dst_vmid) { + case MV_VMID_SELF: + dst_vm = get_domain(vp->domid()); + break; + default: + throw std::runtime_error( + "map_range: non-self destination is not yet implemented"); + } + + using namespace ::intel_x64::ept; + + // src REVZ must be zero + + if (bfn::lower(src_gpa, pt::from)) { + vp->set_rax(MV_STATUS_INVALID_PARAMS2); + return {}; + } + + // dst REVZ must be zero + + if (bfn::lower(dst_gpa, pt::from)) { + vp->set_rax(MV_STATUS_INVALID_PARAMS4); + return {}; + } + + // TODO donate and zombie flags + + if (flags & MV_GPA_FLAG_DONATE) { + // Only the root VM is allowed to donate + if (vp->is_domU()) { + vp->set_rax(MV_STATUS_INVALID_PARAMS5); + return {}; + } + + vp->set_rax(MV_STATUS_INVALID_PARAMS5); + bfdebug_info(0, "map_range: page donation is not yet implemented"); + return {}; + } + + // Memory access type + + switch ((flags >> 32) & 0x3LLU) { + case 0: break; + case 1: attr = mmap::attr_type::read_only; break; + case 2: attr = mmap::attr_type::write_only; break; + case 3: attr = mmap::attr_type::read_write; break; + case 4: attr = mmap::attr_type::execute_only; break; + case 5: attr = mmap::attr_type::read_execute; break; + case 6: attr = mmap::attr_type::read_write_execute; break; + default: + vp->set_rax(MV_STATUS_INVALID_PARAMS5); + return {}; + } + + // Cacheability + + switch ((flags >> 35) & 0x7LLU) { + case 0x00: break; + case 0x01: cache = mmap::memory_type::uncacheable; break; + // TODO: case 0x02 uncacheable_minus + case 0x04: cache = mmap::memory_type::write_combining; break; + // TODO: case 0x08 write_combining_plus + case 0x10: cache = mmap::memory_type::write_through; break; + case 0x20: cache = mmap::memory_type::write_back; break; + case 0x40: cache = mmap::memory_type::write_protected; break; + default: + vp->set_rax(MV_STATUS_INVALID_PARAMS5); + return {}; + } + + return {src_vm, src_gpa, dst_vm, dst_gpa, size, attr, cache}; +} + +void +vm_state_op_handler::map_range(vcpu *vp) +{ + auto [src_vm, src_gpa, dst_vm, dst_gpa, size, attr, cache] = + map_range_init(vp); + + if ((vp->rax() >> 48) == 0xDEAD) { return; } - vcpu->add_vmcall_handler({&vm_state_op_handler::dispatch, this}); + try { + dst_vm->share_range(dst_gpa, src_gpa, src_vm->ept(), size, attr, cache); + vp->invept(); + } + catchall({ + throw std::runtime_error("map_range failed"); + }) + + vp->set_rax(MV_STATUS_SUCCESS); +} + +void +vm_state_op_handler::unmap_range(vcpu *vp) +{ + auto [src_vm, src_gpa, dst_vm, dst_gpa, size, attr, cache] = + map_range_init(vp); + + if ((vp->rax() >> 48) == 0xDEAD) { + return; + } + + try { + dst_vm->unshare_range(dst_gpa, size, attr, cache); + vp->invept(); + } + catchall({ + throw std::runtime_error("map_range failed"); + }) + + vp->set_rax(MV_STATUS_SUCCESS); } bool @@ -48,6 +220,15 @@ vm_state_op_handler::dispatch(vcpu *vcpu) // TODO: Validate the handle switch (mv_hypercall_index(vcpu->rax())) { + case MV_VM_STATE_OP_GVA_TO_GPA_IDX_VAL: + this->gva_to_gpa(vcpu); + return true; + case MV_VM_STATE_OP_MAP_RANGE_IDX_VAL: + this->map_range(vcpu); + return true; + case MV_VM_STATE_OP_UNMAP_RANGE_IDX_VAL: + this->unmap_range(vcpu); + return true; default: break; }; diff --git a/bfvmm/src/hve/arch/intel_x64/vmcall/vp_state_op.cpp b/bfvmm/src/hve/arch/intel_x64/vmcall/vp_state_op.cpp index 4d361cd..0c9c851 100644 --- a/bfvmm/src/hve/arch/intel_x64/vmcall/vp_state_op.cpp +++ b/bfvmm/src/hve/arch/intel_x64/vmcall/vp_state_op.cpp @@ -31,28 +31,231 @@ vp_state_op_handler::vp_state_op_handler( ) : m_vcpu{vcpu} { - if (vcpu->is_domU()) { + vcpu->add_vmcall_handler({&vp_state_op_handler::dispatch, this}); +} + +#define case_reg(name) \ + case mv_reg_t_ ## name: \ + reg_val = target->name(); \ + break + +#define case_reg2(name0, name1) \ + case mv_reg_t_ ## name0: \ + reg_val = target->name1(); \ + break + +#define case_reg_vmcs(name) \ + case mv_reg_t_ ## name: \ + target->load(); \ + reg_val = target->name(); \ + vp->load(); \ + break + +#define case_reg_vmcs2(name0, name1) \ + case mv_reg_t_ ## name0: \ + target->load(); \ + reg_val = target->name1(); \ + vp->load(); \ + break + +void +vp_state_op_handler::reg_val(vcpu *vp) +{ + mv_reg_t reg{static_cast(vp->r12())}; + uint64_t reg_val{}; + vcpu *target{init_target(vp)}; + + if (target == nullptr) { return; } - vcpu->add_vmcall_handler({&vp_state_op_handler::dispatch, this}); + switch (reg) { + case_reg(rax); + case_reg(rbx); + case_reg(rcx); + case_reg(rdx); + case_reg(rdi); + case_reg(rsi); + case_reg2(r8, r08); + case_reg2(r9, r09); + case_reg(r10); + case_reg(r11); + case_reg(r12); + case_reg(r13); + case_reg(r14); + case_reg(r15); + case_reg(rbp); + case_reg(rsp); + case_reg(rip); + case_reg_vmcs(cr0); + case_reg(cr2); + case_reg_vmcs(cr3); + case_reg_vmcs(cr4); + case_reg(cr8); + case_reg(dr0); + case_reg(dr1); + case_reg(dr2); + case_reg(dr3); + // FIXME mv_reg_t_dr4 + // FIXME mv_reg_t_dr5 + case_reg(dr6); + case_reg_vmcs(dr7); + case_reg_vmcs(rflags); + case_reg_vmcs2(es, es_selector); + case_reg_vmcs2(es_base_addr, es_base); + case_reg_vmcs(es_limit); + case_reg_vmcs2(es_attributes, es_access_rights); + case_reg_vmcs2(cs, cs_selector); + case_reg_vmcs2(cs_base_addr, cs_base); + case_reg_vmcs(cs_limit); + case_reg_vmcs2(cs_attributes, cs_access_rights); + case_reg_vmcs2(ss, ss_selector); + case_reg_vmcs2(ss_base_addr, ss_base); + case_reg_vmcs(ss_limit); + case_reg_vmcs2(ss_attributes, ss_access_rights); + case_reg_vmcs2(ds, ds_selector); + case_reg_vmcs2(ds_base_addr, ds_base); + case_reg_vmcs(ds_limit); + case_reg_vmcs2(ds_attributes, ds_access_rights); + case_reg_vmcs2(fs, fs_selector); + case_reg_vmcs2(fs_base_addr, fs_base); + case_reg_vmcs(fs_limit); + case_reg_vmcs2(fs_attributes, fs_access_rights); + case_reg_vmcs2(gs, gs_selector); + case_reg_vmcs2(gs_base_addr, gs_base); + case_reg_vmcs(gs_limit); + case_reg_vmcs2(gs_attributes, gs_access_rights); + case_reg_vmcs2(ldtr, ldtr_selector); + case_reg_vmcs2(ldtr_base_addr, ldtr_base); + case_reg_vmcs(ldtr_limit); + case_reg_vmcs2(ldtr_attributes, ldtr_access_rights); + case_reg_vmcs2(tr, tr_selector); + case_reg_vmcs2(tr_base_addr, tr_base); + case_reg_vmcs(tr_limit); + case_reg_vmcs2(tr_attributes, tr_access_rights); + // FIXME: mv_reg_t_gdtr + case_reg_vmcs2(gdtr_base_addr, gdt_base); + case_reg_vmcs2(gdtr_limit, gdt_limit); + // FIXME: mv_reg_t_gdtr_attributes + // FIXME: mv_reg_t_idtr + case_reg_vmcs2(idtr_base_addr, idt_base); + case_reg_vmcs2(idtr_limit, idt_limit); + // FIXME: mv_reg_t_idtr_attributes + + default: + vp->set_rax(MV_STATUS_INVALID_PARAMS2); + return; + } + + vp->set_r10(reg_val); + vp->set_rax(MV_STATUS_SUCCESS); +} + +#define case_msr_vmcs(msr, name) \ + case msr: \ + target->load(); \ + msr_val = vmcs_n::guest_## name ::get(); \ + vp->load(); \ + break + +void +vp_state_op_handler::msr_val(vcpu *vp) +{ + uint32_t msr{gsl::narrow_cast(vp->r12())}; + uint64_t msr_val{}; + vcpu *target{init_target(vp)}; + + if (target == nullptr) { + return; + } + + switch (msr) { + case_msr_vmcs(::x64::msrs::ia32_pat::addr, ia32_pat); + case_msr_vmcs(::intel_x64::msrs::ia32_efer::addr, ia32_efer); + case_msr_vmcs(::intel_x64::msrs::ia32_fs_base::addr, fs_base); + case_msr_vmcs(::intel_x64::msrs::ia32_gs_base::addr, gs_base); + case_msr_vmcs(::intel_x64::msrs::ia32_sysenter_cs::addr, ia32_sysenter_cs); + case_msr_vmcs(::intel_x64::msrs::ia32_sysenter_eip::addr, ia32_sysenter_eip); + case_msr_vmcs(::intel_x64::msrs::ia32_sysenter_esp::addr, ia32_sysenter_esp); + + default: + try { + msr_val = target->msr(msr); + } + catchall({ + bferror_nhex(0, "vp_state_op unhandled msr:", msr); + vp->set_rax(MV_STATUS_INVALID_PARAMS2); + return; + }) + } + + vp->set_r10(msr_val); + vp->set_rax(MV_STATUS_SUCCESS); +} + +vcpu * +vp_state_op_handler::init_target(vcpu *vp) +{ + vcpu *target{nullptr}; + + // For now we only allow a domU to target its parent + // either via MV_VPID_PARENT or with its parent vp id + switch (vp->r11()) { + case MV_VPID_SELF: + vp->set_rax(MV_STATUS_INVALID_VPID_UNSUPPORTED_SELF); + break; + case MV_VPID_PARENT: + if (vp->is_dom0()) { + vp->set_rax(MV_STATUS_INVALID_VPID_UNSUPPORTED_PARENT); + break; + } + target = vp->parent_vcpu(); + break; + case MV_VPID_ANY: + vp->set_rax(MV_STATUS_INVALID_VPID_UNSUPPORTED_ANY); + break; + default: + if (vp->is_dom0()) { + // TODO check if is child of current vp + } + else if (vp->parent_vcpu()->id() != vp->r11()) { + vp->set_rax(MV_STATUS_FAILURE_UNSUPPORTED_HYPERCALL); + break; + } + + try { + target = get_vcpu(vp->r11()); + } + catchall({ + vp->set_rax(MV_STATUS_INVALID_VPID_UNKNOWN); + break; + }) + } + + return target; } bool -vp_state_op_handler::dispatch(vcpu *vcpu) +vp_state_op_handler::dispatch(vcpu *vp) { - if (mv_hypercall_opcode(vcpu->rax()) != MV_VP_STATE_OP_VAL) { + if (mv_hypercall_opcode(vp->rax()) != MV_VP_STATE_OP_VAL) { return false; } // TODO: Validate the handle - switch (mv_hypercall_index(vcpu->rax())) { + switch (mv_hypercall_index(vp->rax())) { + case MV_VP_STATE_OP_REG_VAL_IDX_VAL: + this->reg_val(vp); + return true; + case MV_VP_STATE_OP_MSR_VAL_IDX_VAL: + this->msr_val(vp); + return true; default: break; }; - vcpu->set_rax(MV_STATUS_FAILURE_UNKNOWN_HYPERCALL); + vp->set_rax(MV_STATUS_FAILURE_UNKNOWN_HYPERCALL); return true; } diff --git a/bfvmm/src/hve/arch/intel_x64/vmexit/msr.cpp b/bfvmm/src/hve/arch/intel_x64/vmexit/msr.cpp index 3cf8961..edc502b 100644 --- a/bfvmm/src/hve/arch/intel_x64/vmexit/msr.cpp +++ b/bfvmm/src/hve/arch/intel_x64/vmexit/msr.cpp @@ -285,4 +285,20 @@ msr_handler::handle_wrmsr_0x0000064E( return false; } +// ----------------------------------------------------------------------------- +// Accessor / Mutator +// ----------------------------------------------------------------------------- + +uint64_t +msr_handler::get_msr(uint32_t msr) const +{ + return m_msrs.at(msr); +} + +void +msr_handler::set_msr(uint32_t msr, uint64_t val) +{ + m_msrs[msr] = val; +} + } diff --git a/bfvmm/src/main/arch/intel_x64/vcpu_factory.cpp b/bfvmm/src/main/arch/intel_x64/vcpu_factory.cpp index 278758c..3def1a0 100644 --- a/bfvmm/src/main/arch/intel_x64/vcpu_factory.cpp +++ b/bfvmm/src/main/arch/intel_x64/vcpu_factory.cpp @@ -21,6 +21,7 @@ #include #include +#include namespace bfvmm { @@ -29,12 +30,16 @@ std::unique_ptr vcpu_factory::make(vcpuid::type vcpuid, void *data) { using namespace boxy::intel_x64; - static domain dom0{0}; + static bfn::once_flag flag; if (vcpuid::is_host_vcpu(vcpuid)) { + bfn::call_once(flag, [&] { + g_dm->create(0, nullptr); + }); + return std::make_unique( - vcpuid, &dom0 + vcpuid, get_domain(0) ); } else { diff --git a/config.cmake b/config.cmake index 6760500..74c97d2 100644 --- a/config.cmake +++ b/config.cmake @@ -19,7 +19,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -set(CACHE_DIR ${CMAKE_CURRENT_LIST_DIR}/cache) +if(NOT DEFINED CACHE_DIR) + set(CACHE_DIR ${CMAKE_CURRENT_LIST_DIR}/cache) +endif() + file(MAKE_DIRECTORY ${CACHE_DIR}) set(CMAKE_BUILD_TYPE Release) diff --git a/examples/buildroot/Config.in b/examples/buildroot/Config.in new file mode 100644 index 0000000..6843a99 --- /dev/null +++ b/examples/buildroot/Config.in @@ -0,0 +1,2 @@ +source "$BR2_EXTERNAL_vmilinux_PATH/package/libvmi/Config.in" +source "$BR2_EXTERNAL_vmilinux_PATH/package/vmilinux/Config.in" diff --git a/examples/buildroot/common/post-build.sh b/examples/buildroot/common/post-build.sh new file mode 100755 index 0000000..e65f93a --- /dev/null +++ b/examples/buildroot/common/post-build.sh @@ -0,0 +1,69 @@ +#!/bin/bash -e +# +# Copyright (C) 2020 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# env REKALL_PROFILE_PATH or VOLATILITY_PROFILE_PATH pointing to a json profile + +PROFILE_FILES=(${REKALL_PROFILE_PATH} ${VOLATILITY_PROFILE_PATH}) + +source "${BR2_EXTERNAL_vmilinux_PATH}/../../scripts/util/colors.sh" + +if [[ -z "${REKALL_PROFILE_PATH}" && -z "${VOLATILITY_PROFILE_PATH}" ]]; then + echo -e "${BF_COLOR_RED}Error: a profile environment variable is required.${BF_COLOR_RST}" + echo "Please define REKALL_PROFILE_PATH or VOLATILITY_PROFILE_PATH to a json profile" + exit 1; +fi + +LIBVMI_CONF="dom0 {" + +for JSON_PROFILE in ${PROFILE_FILES}; do + if [ ! -f "${JSON_PROFILE}" ]; then + echo -e "${BF_COLOR_RED}Missing profile file ${JSON_PROFILE}${BF_COLOR_RST}" + echo "" + exit 1; + fi + + [[ $JSON_PROFILE = $REKALL_PROFILE_PATH ]] && JSON_FILE="rekall.json" || JSON_FILE="volatility.json" + + if [ -f "${TARGET_DIR}/root/${JSON_FILE}" ]; then + echo "removing \${TARGET_DIR}/root/${JSON_FILE})" + rm ${TARGET_DIR}/root/${JSON_FILE} + fi + + echo -e "${BF_COLOR_BLU}Copying host profile for libvmi:${BF_COLOR_RST}" + echo "cp \"${JSON_PROFILE}\" \"${TARGET_DIR}/root/${JSON_FILE}\"" + cp "${JSON_PROFILE}" "${TARGET_DIR}/root/${JSON_FILE}" + + case "${JSON_FILE}" in + rekall.json) + LIBVMI_CONF="${LIBVMI_CONF}\n\trekall_profile = \"/root/rekall.json\";" + ;; + volatility.json) + LIBVMI_CONF="${LIBVMI_CONF}\n\tvolatility_ist = \"/root/volatility.json\";" + ;; + *) + ;; + esac +done + +LIBVMI_CONF="${LIBVMI_CONF}\n}" +printf "${LIBVMI_CONF} > \${TARGET_DIR}/etc/libvmi.conf\n" +printf "${LIBVMI_CONF}" > ${TARGET_DIR}/etc/libvmi.conf \ No newline at end of file diff --git a/examples/buildroot/configs/vmilinux_defconfig b/examples/buildroot/configs/vmilinux_defconfig new file mode 100644 index 0000000..cfd4a94 --- /dev/null +++ b/examples/buildroot/configs/vmilinux_defconfig @@ -0,0 +1,21 @@ +BR2_x86_64=y +BR2_x86_core2=y +BR2_TOOLCHAIN_BUILDROOT_GLIBC=y +BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_20=y +BR2_PACKAGE_GLIBC_UTILS=y +BR2_TOOLCHAIN_BUILDROOT_CXX=y +BR2_INIT_NONE=y +# BR2_TARGET_ENABLE_ROOT_LOGIN is not set +# BR2_TARGET_GENERIC_GETTY is not set +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_CUSTOM_TARBALL=y +BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="https://github.com/Bareflank/linux/archive/boxy_1.01.tar.gz" +BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_vmilinux_PATH}/../../bflinux/config" +# BR2_PACKAGE_BUSYBOX is not set +# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set +BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_vmilinux_PATH}/common/post-build.sh" +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_CPIO_GZIP=y +# BR2_TARGET_ROOTFS_TAR is not set +BR2_PACKAGE_VMILINUX=y diff --git a/examples/buildroot/external.desc b/examples/buildroot/external.desc new file mode 100644 index 0000000..c43d4c4 --- /dev/null +++ b/examples/buildroot/external.desc @@ -0,0 +1,2 @@ +name: vmilinux +desc: LibVMI examples with Bareflank Boxy diff --git a/examples/buildroot/external.mk b/examples/buildroot/external.mk new file mode 100644 index 0000000..cfc7635 --- /dev/null +++ b/examples/buildroot/external.mk @@ -0,0 +1 @@ +include $(sort $(wildcard $(BR2_EXTERNAL_vmilinux_PATH)/package/*/*.mk)) diff --git a/examples/buildroot/package/cpio/cpio.mk b/examples/buildroot/package/cpio/cpio.mk new file mode 100644 index 0000000..bb05ceb --- /dev/null +++ b/examples/buildroot/package/cpio/cpio.mk @@ -0,0 +1,10 @@ +################################################################################ +# +# cpio to archive target filesystem +# +################################################################################ + +# Overrides rootfs cpio config from fs/cpio/cpio.mk +# to prevent it from placing /init + +ROOTFS_CPIO_PRE_GEN_HOOKS = diff --git a/examples/buildroot/package/libvmi/Config.in b/examples/buildroot/package/libvmi/Config.in new file mode 100644 index 0000000..9f0a693 --- /dev/null +++ b/examples/buildroot/package/libvmi/Config.in @@ -0,0 +1,16 @@ +config BR2_PACKAGE_LIBVMI + bool "libvmi" + depends on BR2_TOOLCHAIN_USES_GLIBC + depends on BR2_USE_WCHAR # glib2 + depends on BR2_TOOLCHAIN_HAS_THREADS # glib2 + depends on BR2_USE_MMU # glib2 + select BR2_PACKAGE_LIBGLIB2 + select BR2_PACKAGE_JSON_C + # BR2_STATIC_LIBS + help + LibVMI is a C library with Python bindings that makes it easy to monitor the + low-level details of a running virtual machine by viewing its memory, trapping + on hardware events, and accessing the vCPU registers. This is called virtual + machine introspection. + + https://github.com/libvmi/libvmi \ No newline at end of file diff --git a/examples/buildroot/package/libvmi/libvmi.mk b/examples/buildroot/package/libvmi/libvmi.mk new file mode 100644 index 0000000..2d6ab45 --- /dev/null +++ b/examples/buildroot/package/libvmi/libvmi.mk @@ -0,0 +1,40 @@ +################################################################################ +# +# LibVMI +# +################################################################################ + +ifeq ($(BR2_LIBVMI_PATH),) + LIBVMI_VERSION = bebefc7c4564b48801baf97084ff21f26d24631c + LIBVMI_SITE = $(call github,chp-io,libvmi,$(LIBVMI_VERSION)) + LIBVMI_REPO = https://github.com/chp-io/libvmi +else + LIBVMI_SITE = ${BR2_LIBVMI_PATH} + LIBVMI_SITE_METHOD = local + LIBVMI_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS = --exclude '/deps' +endif + +LIBVMI_LICENSE = LGPLv3 +LIBVMI_LICENSE_FILES = COPYING + +LIBVMI_DEPENDENCIES = json-c libglib2 +HOST_LIBVMI_DEPENDENCIES = host-pkgconf host-bison host-flex host-libglib2 +LIBVMI_CONF_OPTS = \ + -DENABLE_XENSTORE=OFF \ + -DENABLE_XEN=OFF \ + -DENABLE_FILE=OFF \ + -DENABLE_VMIFS=OFF \ + -DENABLE_KVM=OFF \ + -DBUILD_EXAMPLES=ON \ + -DENABLE_FREEBSD=OFF \ + -DENABLE_STATIC=OFF \ + -DENABLE_PAGE_CACHE=OFF + +ifeq ($(BR2_LIBVMI_DEBUG),y) + LIBVMI_CONF_OPTS += -DCMAKE_BUILD_TYPE=Debug \ + -DVMI_DEBUG=__VMI_DEBUG_ALL +else + LIBVMI_CONF_OPTS += -DCMAKE_BUILD_TYPE=Release +endif + +$(eval $(cmake-package)) diff --git a/examples/buildroot/package/vmilinux/Config.in b/examples/buildroot/package/vmilinux/Config.in new file mode 100644 index 0000000..9ea9f81 --- /dev/null +++ b/examples/buildroot/package/vmilinux/Config.in @@ -0,0 +1,7 @@ +config BR2_PACKAGE_VMILINUX + bool "vmilinux" + depends on BR2_INSTALL_LIBSTDCPP + select BR2_PACKAGE_LIBVMI + help + vmilinux starts a vmi app with populated cmdline parsed from the kernel's + cmdline. \ No newline at end of file diff --git a/examples/buildroot/package/vmilinux/vmilinux.mk b/examples/buildroot/package/vmilinux/vmilinux.mk new file mode 100644 index 0000000..dab1173 --- /dev/null +++ b/examples/buildroot/package/vmilinux/vmilinux.mk @@ -0,0 +1,36 @@ +################################################################################ +# +# vmilinux +# +################################################################################ + +VMILINUX_SITE = ${BR2_EXTERNAL_vmilinux_PATH}/../.. # ${BOXY_SOURCE_ROOT_DIR} +VMILINUX_SITE_METHOD = local +VMILINUX_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS = --exclude build --exclude 'build_*' + +VMILINUX_LICENSE = MIT + +# VMILINUX_SUBDIR = hypervisor +VMILINUX_SUPPORTS_IN_SOURCE_BUILD = NO +VMILINUX_CONF_OPTS = -DBUILD_SHARED_LIBS=NO +VMILINUX_MAKE_OPTS = vmilinux_x86_64-userspace-elf + +define VMILINUX_CONFIGURE_CMDS + (cd $(@D); \ + [[ -d buildroot-build ]] || mkdir buildroot-build; \ + cd buildroot-build; \ + $(TARGET_MAKE_ENV) cmake ../hypervisor \ + -DENABLE_BUILD_EXAMPLES=ON \ + -DREKALL_PROFILE_PATH=${REKALL_PROFILE_PATH} \ + -DVOLATILITY_PROFILE_PATH=${VOLATILITY_PROFILE_PATH} \ + -DCACHE_DIR=${CACHE_DIR} \ + ) +endef + +define VMILINUX_INSTALL_TARGET_CMDS + $(INSTALL) -m 0755 \ + -D $(@D)/buildroot-build/prefixes/initrd/sbin/init-vmi \ + $(TARGET_DIR)/sbin/init +endef + +$(eval $(cmake-package)) \ No newline at end of file diff --git a/examples/buildroot/patch/0001-package-json-c-bump-version-to-0.14.patch b/examples/buildroot/patch/0001-package-json-c-bump-version-to-0.14.patch new file mode 100644 index 0000000..944372b --- /dev/null +++ b/examples/buildroot/patch/0001-package-json-c-bump-version-to-0.14.patch @@ -0,0 +1,57 @@ +From e621c74f96c7f4093829d7a4b91f91c589bb3949 Mon Sep 17 00:00:00 2001 +From: Christopher Pelloux +Date: Thu, 4 Jun 2020 21:11:26 -0400 +Subject: [PATCH 1/1] package/json-c: bump version to 0.14 + +Notes: + +- json-c now uses cmake instead of autoconf +- This version also brings support to the much welcomed feature for + parsing uint64_t types + +Signed-off-by: Christopher Pelloux +--- + package/json-c/json-c.hash | 2 +- + package/json-c/json-c.mk | 14 +++----------- + 2 files changed, 4 insertions(+), 12 deletions(-) + +diff --git a/package/json-c/json-c.hash b/package/json-c/json-c.hash +index 0e03007476..93eaff67c3 100644 +--- a/package/json-c/json-c.hash ++++ b/package/json-c/json-c.hash +@@ -1,4 +1,4 @@ + # From https://github.com/json-c/json-c/wiki +-sha256 b87e608d4d3f7bfdd36ef78d56d53c74e66ab278d318b71e6002a369d36f4873 json-c-0.13.1.tar.gz ++sha256 b377de08c9b23ca3b37d9a9828107dff1de5ce208ff4ebb35005a794f30c6870 json-c-0.14.tar.gz + # Locally calculated + sha256 74c1e6ca5eba76b54d0ad00d4815c8315c1b3bc45ff99de61d103dc92486284c COPYING +diff --git a/package/json-c/json-c.mk b/package/json-c/json-c.mk +index 2788fe563b..3e17effdad 100644 +--- a/package/json-c/json-c.mk ++++ b/package/json-c/json-c.mk +@@ -4,19 +4,11 @@ + # + ################################################################################ + +-JSON_C_VERSION = 0.13.1 ++JSON_C_VERSION = 0.14 + JSON_C_SITE = https://s3.amazonaws.com/json-c_releases/releases + JSON_C_INSTALL_STAGING = YES + JSON_C_LICENSE = MIT + JSON_C_LICENSE_FILES = COPYING + +-# update config.h.in timestamp to avoid autoheader run +-define JSON_C_UPDATE_CONFIG_TIMESTAMP +- touch $(@D)/config.h.in +-endef +- +-JSON_C_POST_EXTRACT_HOOKS += JSON_C_UPDATE_CONFIG_TIMESTAMP +-HOST_JSON_C_POST_EXTRACT_HOOKS += JSON_C_UPDATE_CONFIG_TIMESTAMP +- +-$(eval $(autotools-package)) +-$(eval $(host-autotools-package)) ++$(eval $(cmake-package)) ++$(eval $(host-cmake-package)) +-- +2.17.1 + diff --git a/examples/vmilinux/CMakeLists.txt b/examples/vmilinux/CMakeLists.txt new file mode 100644 index 0000000..f4213ac --- /dev/null +++ b/examples/vmilinux/CMakeLists.txt @@ -0,0 +1,63 @@ +# +# Copyright (C) 2019 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +cmake_minimum_required(VERSION 3.13) +project(vmilinux C CXX) + +init_project(vmilinux INTERFACE) + +target_link_libraries(vmilinux INTERFACE userspace::bflinux) + +if (${SVMI_STATIC_INIT}) + add_executable(init-vmi + ${CMAKE_CURRENT_LIST_DIR}/tests/test-init.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/init-vmi.cpp + ) + target_compile_definitions(init-vmi PUBLIC + SVMI_STATIC_INIT + SVMI_INIT_NO_PROC_MOUNT + SVMI_INIT_NO_PRINTK + SVMI_CMDLINE_PATH="${CMAKE_CURRENT_LIST_DIR}/tests/cmdline.txt" + ) + set(INIT_VMI_BIN init-vmi) +else() + add_executable(init-vmi ${CMAKE_CURRENT_LIST_DIR}/src/init-vmi.cpp) + set(INIT_VMI_BIN init-vmi) +endif() +target_link_options(init-vmi PRIVATE -static) +set_target_properties(init-vmi PROPERTIES CXX_STANDARD 20) +target_include_directories(init-vmi PRIVATE + $ + $ +) +target_link_libraries(${INIT_VMI_BIN} PUBLIC vmilinux) + +add_custom_target( + package ALL + COMMAND ${CMAKE_COMMAND} -E copy ${INIT_VMI_BIN} ${PREFIXES_DIR}/initrd/sbin/ + COMMAND ${CMAKE_COMMAND} -E chdir ${PREFIXES_DIR}/initrd/ bash ${BOXY_SOURCE_ROOT_DIR}/bflinux/build.sh + COMMAND ${CMAKE_COMMAND} -E echo initrd built for vmilinux + VERBATIM +) + +add_dependencies(package init-vmi) + +fini_project() diff --git a/examples/vmilinux/include/cmdl.h b/examples/vmilinux/include/cmdl.h new file mode 100644 index 0000000..4010281 --- /dev/null +++ b/examples/vmilinux/include/cmdl.h @@ -0,0 +1,131 @@ +// +// Copyright (C) 2020 Assured Information Security, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef VMI_CMDL_H +#define VMI_CMDL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace svmi +{ + +class cmdl +{ + +public: + // + cmdl(const std::string &str, const char delim = ',', const std::string &key = "vmi=") + : m_cmdline{str}, m_args{} + { + if (str == "") { + m_argv.push_back(nullptr); + return; + } + + if (int pos = str.find(key); pos != std::string::npos) { + pos += key.size(); + char *tmp; + std::string tmp_str(str); + char *arg = strtok_r(const_cast(tmp_str.data() + pos), &delim, &tmp); + while (arg) { + if (arg[0] == ' ') { + break; + } + m_args.push_back(arg); + arg = strtok_r(NULL, &delim, &tmp); + } + } + else { + return; + } + + m_argv.resize(m_args.size() + 1); + std::transform(m_args.begin(), m_args.end(), m_argv.begin(), [](const std::string & arg) { + return const_cast(arg.data()); + }); + m_argv.back() = nullptr; + } + + char * + file() const noexcept + { + return m_argv[0]; + } + + int + argc() const noexcept + { + return m_args.size(); + } + + char ** + argv() const noexcept + { + return const_cast(m_argv.data()); + } + + std::unique_ptr + to_string() const noexcept + { + auto str = std::make_unique(""); + std::for_each(m_args.begin(), m_args.end(), [&](const std::string & arg) { + *str += (arg + " "); + }); + str->pop_back(); + return str; + } + + const std::string + kernel_cmdline() const noexcept + { + return m_cmdline; + } + + void + add_arg0(const std::string &arg0) + { + m_args.insert(m_args.begin(), arg0); + + // Pointers might now be invalid. Need to recompute argv. + m_argv.resize(m_args.size() + 1); + std::transform(m_args.begin(), m_args.end(), m_argv.begin(), [](const std::string & arg) { + return const_cast(arg.data()); + }); + m_argv.back() = nullptr; + } + +private: + const std::string &m_cmdline; + std::vector m_args; + + std::vector m_argv; +}; + +} + +#endif diff --git a/examples/vmilinux/src/init-vmi.cpp b/examples/vmilinux/src/init-vmi.cpp new file mode 100644 index 0000000..c123eab --- /dev/null +++ b/examples/vmilinux/src/init-vmi.cpp @@ -0,0 +1,160 @@ +// +// Copyright (C) 2020 Assured Information Security, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma GCC diagnostic ignored "-Wunused-result" + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +// Notes: +// +// init.cpp parses the kernel cmdline in /proc/cmdline to create argc, argv and passes it to an +// application's main function. Arguements are given by prefixing them with "vmi=" and seperated +// by a comma. e.g. "vmi=arg0,arg1 ..." +// +// init.cpp can be compiled in two ways. With SVMI_STATIC_INIT defined, init.cpp will call a +// statically linked main and a single application will be running on the guest. +// e.g. "vmi=dom0" will call main with argv[0]="init" argv[1]="dom0" +// +// With SVMI_STATIC_INIT not defined, init.cpp will provide a main function that will execute an +// external application. Here, the first agument of "vmi=" needs to be the path of the executable. +// e.g. "vmi=/bin/vmi-module-list,dom0" will call main with argv[0]="/bin/vmi-module-list" and +// argv[1]="dom0". + +// Macros: +// +// SVMI_STATIC_INIT : if defined, call a linked main otherwise provide main and execute an +// external program. + +// Macros (mainly for testing): +// +// SVMI_INIT_NO_PROC_MOUNT : don't mount proc. +// SVMI_INIT_NO_PRINTK : don't redirect output to the kernel ring buffer. +// SVMI_CMDLINE_PATH : define a file path instead of /proc/cmdline for testing. + +#ifndef SVMI_CMDLINE_PATH +#define SVMI_CMDLINE_PATH "/proc/cmdline" +#endif + +int main(int argc, char **argv); + +namespace svmi +{ + +class pre_main +{ +public: + pre_main() + { + +#ifndef SVMI_INIT_NO_PROC_MOUNT + mount("proc", "/proc", "proc", 0, ""); +#endif + +#ifndef SVMI_INIT_NO_PRINTK + freopen("/dev/ttyprintk", "w", stdout); + freopen("/dev/ttyprintk", "w", stderr); +#endif + + printf("Init: reached\n"); + + auto rawtime = time(0); + auto loctime = localtime(&rawtime); + int ret = 0; + + bfn::file f(SVMI_CMDLINE_PATH); + std::string s(f.data(), f.size()); + + // remove line feed + s.pop_back(); + + cmdl cmdl(s); + +#ifdef SVMI_STATIC_INIT + // TODO: Retrieve arg 0 of this process + cmdl.add_arg0("static-init"); +#else + if (cmdl.argc() == 0) { + printf("Init: Error: No vmi args found in kernel cmdline.\n"); + printf("Init: cmdline: %s\n", cmdl.kernel_cmdline().data()); + printf("Init: Please use --cmdline='vmi=,'\n"); + printf("Init: e.g. --cmdline='vmi=/bin/vmi-module-list,dom0'\n"); + goto done; + } +#endif + printf("Init: Starting %s at %s\n", cmdl.to_string()->data(), asctime(loctime)); + ret = main(cmdl.argc(), cmdl.argv()); + +done: + printf("\nInit: return code is %d. Nothing left to do.\n", ret); + // We don't need to sync since we don't have persistent storage yet + reboot(RB_HALT_SYSTEM); + } +}; + +pre_main do_pre_main; + +} + +#ifndef SVMI_STATIC_INIT + +int +main(int argc, char **argv) +{ + pid_t pid; + int status; + int wait_status; + + if ((pid = fork()) == 0) { + if (execve(argv[0], argv, NULL) == -1) { + perror("Init: Error: child process execve failed"); + return -1; + } + } + + wait_status = waitpid(pid, &status, 0); + + if (!WIFEXITED(status)) { + printf( + "Init: %s WEXITSTATUS %d WIFEXITED %d [status %d]\n", + argv[0], + WEXITSTATUS(status), + WIFEXITED(status), + status); + perror("Init: waitpid failed"); + return -1; + } + + return WEXITSTATUS(status); +} + +#endif diff --git a/examples/vmilinux/tests/cmdline.txt b/examples/vmilinux/tests/cmdline.txt new file mode 100644 index 0000000..6736827 --- /dev/null +++ b/examples/vmilinux/tests/cmdline.txt @@ -0,0 +1 @@ +console=uart,io,0x3f8,115200n8 vmi=/usr/bin/vmi-module-list,dom0 diff --git a/examples/vmilinux/tests/test-init.cpp b/examples/vmilinux/tests/test-init.cpp new file mode 100644 index 0000000..e9a78aa --- /dev/null +++ b/examples/vmilinux/tests/test-init.cpp @@ -0,0 +1,32 @@ +// +// Copyright (C) 2020 Assured Information Security, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +int +main(int argc, char **argv) +{ + printf("Test init args: "); + for (int i = 0; i < argc; i++) { + printf("%s ", argv[i]); + } + return argc; +} diff --git a/hypervisor b/hypervisor index 7c1dce3..9358b54 160000 --- a/hypervisor +++ b/hypervisor @@ -1 +1 @@ -Subproject commit 7c1dce35e9e54601de1c4655565fde803ab446f0 +Subproject commit 9358b546244a71512d92e7983638048733f8abbb diff --git a/scripts/cmake/config/default.cmake b/scripts/cmake/config/default.cmake index 8fe4a6e..8d93484 100644 --- a/scripts/cmake/config/default.cmake +++ b/scripts/cmake/config/default.cmake @@ -73,6 +73,11 @@ set(BOXY_SOURCE_BFVMM_DIR ${BOXY_SOURCE_ROOT_DIR}/bfvmm "BOXY bfvmm source dir" ) +set(BOXY_SOURCE_EXAMPLES_DIR ${BOXY_SOURCE_ROOT_DIR}/examples + CACHE INTERNAL + "BOXY example source dir" +) + # ------------------------------------------------------------------------------ # Links # ------------------------------------------------------------------------------ @@ -87,6 +92,20 @@ set(LINUX_URL_MD5 "bbe9d03b76f874444ff2839f74c982e6" "Linux URL MD5 hash" ) +if(NOT DEFINED BUILDROOT_VERSION) + set(BUILDROOT_VERSION "2020.02.2") +endif() + +set(BUILDROOT_URL "https://buildroot.org/downloads/buildroot-${BUILDROOT_VERSION}.tar.gz" + CACHE INTERNAL FORCE + "Buildroot URL" +) + +set(BUILDROOT_URL_MD5 "f288c13b4b51a50e2e06cea4b3869ca0" + CACHE INTERNAL FORCE + "Buildroot URL MD5 hash" +) + # ------------------------------------------------------------------------------ # Boxy guest # ------------------------------------------------------------------------------ @@ -97,3 +116,10 @@ add_config( DEFAULT_VAL ON DESCRIPTION "Build a minimal Linux guest along with the VMM" ) + +add_config( + CONFIG_NAME ENABLE_BUILD_EXAMPLES + CONFIG_TYPE BOOL + DEFAULT_VAL OFF + DESCRIPTION "Build guest examples showcasing Boxy with LibVMI" +) diff --git a/scripts/cmake/depends/buildroot.cmake b/scripts/cmake/depends/buildroot.cmake new file mode 100755 index 0000000..edf82a2 --- /dev/null +++ b/scripts/cmake/depends/buildroot.cmake @@ -0,0 +1,76 @@ +# +# Copyright (C) 2020 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +if(ENABLE_BUILD_EXAMPLES AND ENABLE_BUILD_USERSPACE AND NOT WIN32 AND NOT CYGWIN) + message(STATUS "Including dependency: buildroot") + + set(BUILDROOT_BUILD_DIR ${DEPENDS_DIR}/buildroot/${USERSPACE_PREFIX}/build) + set(BUILDROOT_ENV REKALL_PROFILE_PATH=${REKALL_PROFILE_PATH} VOLATILITY_PROFILE_PATH=${VOLATILITY_PROFILE_PATH} CACHE_DIR=${CACHE_DIR}) + + download_dependency( + buildroot-source + URL ${BUILDROOT_URL} + URL_MD5 ${BUILDROOT_URL_MD5} + PATCH_COMMAND ${CMAKE_COMMAND} -E chdir "${CACHE_DIR}/buildroot-source" git apply -p1 ${BOXY_SOURCE_EXAMPLES_DIR}/buildroot/patch/0001-package-json-c-bump-version-to-0.14.patch + ) + + add_dependency( + buildroot-source userspace + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + BUILD_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + ) + + add_dependency_step( + buildroot-source userspace + COMMAND ${CMAKE_COMMAND} -E make_directory ${BUILDROOT_BUILD_DIR} + COMMAND ${CMAKE_COMMAND} -DSRC=${CACHE_DIR}/buildroot-source/ -DDST=${BUILDROOT_BUILD_DIR} + -P ${BOXY_SOURCE_CMAKE_DIR}/utils/copy_no_follow.cmake + COMMAND ${CMAKE_COMMAND} -E chdir ${BUILDROOT_BUILD_DIR} + env ${BUILDROOT_ENV} + make BR2_EXTERNAL=${BOXY_SOURCE_EXAMPLES_DIR}/buildroot vmilinux_defconfig + COMMAND ${CMAKE_COMMAND} -E make_directory ${PREFIXES_DIR}/vms/buildroot + ) + + add_dependency( + buildroot userspace + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + BUILD_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E echo "-- skip" + UPDATE_COMMAND ${CMAKE_COMMAND} -E echo "-- checking for updates" + DEPENDS buildroot-source_${USERSPACE_PREFIX} + ) + + add_dependency_step( + buildroot userspace + COMMAND ${CMAKE_COMMAND} -E chdir ${BUILDROOT_BUILD_DIR} + env ${BUILDROOT_ENV} + make -j${BUILD_TARGET_CORES} + COMMAND ${CMAKE_COMMAND} -E copy + ${BUILDROOT_BUILD_DIR}/output/images/bzImage + ${BUILDROOT_BUILD_DIR}/output/images/rootfs.cpio.gz + ${PREFIXES_DIR}/vms/buildroot + ) + + add_dependencies(vms buildroot_${USERSPACE_PREFIX}) +endif() diff --git a/scripts/cmake/utils/copy_no_follow.cmake b/scripts/cmake/utils/copy_no_follow.cmake new file mode 100644 index 0000000..98d95f0 --- /dev/null +++ b/scripts/cmake/utils/copy_no_follow.cmake @@ -0,0 +1,26 @@ +# +# Copyright (C) 2020 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Helper script used instead of cmake -E copy_directory as the latter doesn't +# support symbolic link no follow +# e.g. ExternalProject_Add + +file(COPY "${SRC}/" DESTINATION "${DST}") \ No newline at end of file diff --git a/scripts/cmake/validate.cmake b/scripts/cmake/validate.cmake new file mode 100644 index 0000000..c9a6ffa --- /dev/null +++ b/scripts/cmake/validate.cmake @@ -0,0 +1,56 @@ +# +# Copyright (C) 2020 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# ------------------------------------------------------------------------------ +# Buildroot +# ------------------------------------------------------------------------------ + +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_HOST_SYSTEM_NAME STREQUAL "CYGWIN") + if(ENABLE_BUILD_EXAMPLES) + invalid_config("ENABLE_BUILD_EXAMPLES is not supported on Windows. Please use Vagrant.") + endif() +endif() + +if(ENABLE_BUILD_EXAMPLES AND NOT DEFINED REKALL_PROFILE_PATH AND NOT DEFINED VOLATILITY_PROFILE_PATH) + invalid_config("ENABLE_BUILD_EXAMPLES requires REKALL_PROFILE_PATH or VOLATILITY_PROFILE_PATH") +endif() + +if((${REKALL_PROFILE_PATH}) AND NOT EXISTS ${REKALL_PROFILE_PATH}) + message(REKALL_PROFILE_PATH=${REKALL_PROFILE_PATH}) + invalid_config("REKALL_PROFILE_PATH must point to a valid json file") +endif() + +if((${VOLATILITY_PROFILE_PATH}) AND NOT EXISTS ${VOLATILITY_PROFILE_PATH}) + message(REKALL_PROFILE_PATH=${REKALL_PROFILE_PATH}) + invalid_config("VOLATILITY_PROFILE_PATH must point to a valid json file") +endif() + +# add_config( +# CONFIG_NAME REKALL_PROFILE_PATH +# CONFIG_TYPE PATH +# DESCRIPTION "Rekall profile file path for libvmi" +# ) + +# add_config( +# CONFIG_NAME VOLATILITY_PROFILE_PATH +# CONFIG_TYPE PATH +# DESCRIPTION "Volatility profile file path for libvmi" +# ) \ No newline at end of file diff --git a/scripts/util/colors.sh b/scripts/util/colors.sh new file mode 100644 index 0000000..6bdcd4b --- /dev/null +++ b/scripts/util/colors.sh @@ -0,0 +1,30 @@ +# +# Copyright (C) 2020 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +BF_Esc='\e' +BF_COLOR_RST="${BF_Esc}[m" +BF_COLOR_RED="${BF_Esc}[91m" +BF_COLOR_GRN="${BF_Esc}[92m" +BF_COLOR_YLW="${BF_Esc}[93m" +BF_COLOR_BLU="${BF_Esc}[94m" +BF_COLOR_MAG="${BF_Esc}[95m" +BF_COLOR_CYN="${BF_Esc}[96m" +BF_COLOR_WHT="${BF_Esc}[97m"