Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Support for new Palacios image file format (Version 1)
Kyle Hale [Sat, 28 Jul 2012 22:40:26 +0000 (17:40 -0500)]
The VMM configuration side and the utilities side have been updated to now support
two file formats:

Version 0 : The previous version "legacy"
Version 1 : The new version "file integrity checking"

build_vm now has an option [-v] to select versions, version 1 is the default
v3_create now creates version 1 images when dynamic construction of an image file is done

Version 1 has these changes:

add integrity checking for files included in guest configs

This patch adds a hash field to the file headers built from guest
configurations. Both methods of guest creation (in-memory with XML and
file building with build_vm) have been modified to support this. The hash
is passed along with the file when it's added to Palacios, so integrity checks
can theoretically happen at any point, but currently
this is only being done at configuration time.

linux_usr/v3_create.c
linux_usr/v3_ctrl.c
linux_usr/v3_ctrl.h
palacios/include/palacios/vmm_config.h
palacios/src/palacios/vmm_config.c
utils/guest_creator/Makefile
utils/guest_creator/main.c

index 8131df3..4a0b9ff 100644 (file)
@@ -247,6 +247,7 @@ int build_image(char * vm_name, char * filename, struct cfg_value * cfg_vals, in
        int i = 0;
        int offset = 0;
        unsigned long long file_offset = 0;
+        struct mem_file_hdr * hdrs = NULL;
 
        /* Image size is: 
           8 byte header + 
@@ -254,7 +255,7 @@ int build_image(char * vm_name, char * filename, struct cfg_value * cfg_vals, in
           xml strlen + 
           8 bytes of zeros + 
           8 bytes (number of files) + 
-          num_files * 16 byte file header + 
+          num_files * (16+sizeof(unsigned long)) byte file header + 
           8 bytes of zeroes + 
           file data
        */
@@ -263,13 +264,16 @@ int build_image(char * vm_name, char * filename, struct cfg_value * cfg_vals, in
        }
 
        guest_img_size = 8 + 4 + strlen(new_xml_str) + 8 + 8 + 
-           (num_files * 16) + 8 + file_data_size;
+           (num_files * (16*sizeof(unsigned long))) + 8 + file_data_size;
            
 
        guest_img_data = malloc(guest_img_size);
        memset(guest_img_data, 0, guest_img_size);
 
-       memcpy(guest_img_data, "v3vee\0\0\0", 8);
+       //
+       // Dynamically built guests are version 1 by default now
+       //
+       memcpy(guest_img_data, "v3vee\0\0\1", 8);
        offset += 8;
 
        *(unsigned int *)(guest_img_data + offset) = strlen(new_xml_str);
@@ -284,20 +288,29 @@ int build_image(char * vm_name, char * filename, struct cfg_value * cfg_vals, in
        *(unsigned long long *)(guest_img_data + offset) = num_files;
        offset += 8;
 
+        hdrs = guest_img_data + offset;
        
        // The file offset starts at the end of the file list
-       file_offset = offset + (16 * num_files) + 8;
+       file_offset = offset + ((sizeof(unsigned long) + 16) * num_files) + 8;
 
        for (i = 0; i < num_files; i++) {
-           *(unsigned int *)(guest_img_data + offset) = i;
+            /*
+           unsigned int *)(guest_img_data + offset) = i;
            offset += 4;
            *(unsigned int *)(guest_img_data + offset) = files[i].size;
            offset += 4;
            *(unsigned long long *)(guest_img_data + offset) = file_offset;
            offset += 8;
-
+            *(unsigned long *)(guest_img_data + offset) = 0;
+            offset += sizeof(unsigned long);
+            */
+            hdrs[i].file_idx     = i;
+            hdrs[i].file_size    = files[i].size;
+            hdrs[i].file_offset  = file_offset;
+            hdrs[i].file_hash    = 0;
+
+            offset +=  16 + sizeof(unsigned long);
            file_offset += files[i].size;
-
        }
 
        memset(guest_img_data + offset, 0, 8);
@@ -306,13 +319,18 @@ int build_image(char * vm_name, char * filename, struct cfg_value * cfg_vals, in
 
        for (i = 0; i < num_files; i++) {
            int fd = open(files[i].filename, O_RDONLY);
+            unsigned char * faddr = (unsigned char *)(guest_img_data + offset);
 
            if (fd == -1) {
                printf("Error: Could not open aux file (%s)\n", files[i].filename);
                return -1;
            }
 
-           v3_read_file(fd, files[i].size, (unsigned char *)(guest_img_data + offset));
+           v3_read_file(fd, files[i].size, faddr);
+
+            /* store a hash of the file blob for integrity checking later */
+            hdrs[i].file_hash = v3_hash_buffer(faddr, files[i].size);
+            printf("File Hash: %llx\n", hdrs[i].file_hash);
 
            close(fd);
 
index 0183a95..54e8df7 100644 (file)
@@ -150,3 +150,24 @@ int stop_vm (const char * filename) {
 
     return 0;
 }
+
+
+/*
+ * generic ELF header buffer hash function. 
+ * Mirrors internal Palacios implementation
+ */
+unsigned long v3_hash_buffer (unsigned char * msg, unsigned int len) {
+    unsigned long hash = 0;
+    unsigned long temp = 0;
+    unsigned int i;
+
+    for (i = 0; i < len; i++) {
+        hash = (hash << 4) + *(msg + i) + i;
+        if ((temp = (hash & 0xF0000000))) {
+            hash ^= (temp >> 24);
+        }
+        hash &= ~temp;
+    }
+    return hash;
+}
+
index a210013..e81968c 100644 (file)
@@ -110,6 +110,7 @@ int v3_read_file (int fd, int size, unsigned char * buf);
 int launch_vm (const char * filename);
 int stop_vm   (const char * filename);
 
+unsigned long v3_hash_buffer (unsigned char * msg, unsigned int len);
 
 /* XML-related structs */
 struct cfg_value {
@@ -130,4 +131,12 @@ struct file_info {
     char id[256];
 };
 
+struct mem_file_hdr {
+    unsigned int file_idx;
+    unsigned int file_size;
+    unsigned long long file_offset;
+    unsigned long file_hash;
+};
+
+
 #endif
index a6e2b73..78a16c2 100644 (file)
@@ -42,6 +42,7 @@ int v3_free_config(struct v3_vm_info * vm);
 struct v3_cfg_file {
     void * data;
     uint64_t size;
+    ulong_t  hash;   // used only in version 1+
 
     char tag[V3_MAX_TAG_LEN];
 
index 9125d2e..f02ab25 100644 (file)
 
 #include "vmm_config_class.h"
 
+
+/* The Palacios cookie encodes "v3vee" followed by a 
+   3 byte version code.   There are currently two versions:
+
+    \0\0\0 => original (no checksum)
+    \0\0\1 => checksum
+*/
+#define COOKIE_LEN 8
+#define COOKIE_V0 "v3vee\0\0\0"
+#define COOKIE_V1 "v3vee\0\0\1"
+
+
+
+
 // This is used to access the configuration file index table
-struct file_hdr {
+struct file_hdr_v0 {
     uint32_t index;
     uint32_t size;
     uint64_t offset;
 };
 
-struct file_idx_table {
+struct file_hdr_v1 {
+    uint32_t index;
+    uint32_t size;
+    uint64_t offset;
+    ulong_t  hash;
+};
+
+
+struct file_idx_table_v0 {
     uint64_t num_files;
-    struct file_hdr hdrs[0];
+    struct file_hdr_v0 hdrs[0];
+};
+
+struct file_idx_table_v1 {
+    uint64_t num_files;
+    struct file_hdr_v1 hdrs[0];
 };
 
 
@@ -118,17 +145,25 @@ static struct v3_config * parse_config(void * cfg_blob) {
     struct v3_config * cfg = NULL;
     int offset = 0;
     uint_t xml_len = 0; 
-    struct file_idx_table * files = NULL;
+    struct file_idx_table_v0 * files_v0 = NULL;
+    struct file_idx_table_v1 * files_v1 = NULL;
     v3_cfg_tree_t * file_tree = NULL;
+    int version=-1;
 
     V3_Print("cfg data at %p\n", cfg_blob);
 
-    if (memcmp(cfg_blob, "v3vee\0\0\0", 8) != 0) {
-       PrintError("Invalid Configuration Header\n");
+    if (memcmp(cfg_blob, COOKIE_V0, COOKIE_LEN) == 0) {
+        version = 0;
+    } else if (memcmp(cfg_blob, COOKIE_V1, COOKIE_LEN) == 0) { 
+        version = 1;
+    } else {
+       PrintError("Invalid Configuration Header Or Unknown Version\n");
        return NULL;
-    }
+    } 
 
-    offset += 8;
+    V3_Print("Handling Palacios Image Format, Version 0x%x\n",version);
+
+    offset += COOKIE_LEN;
 
     cfg = (struct v3_config *)V3_Malloc(sizeof(struct v3_config));
 
@@ -157,9 +192,15 @@ static struct v3_config * parse_config(void * cfg_blob) {
    
     offset += 8;
 
-    files = (struct file_idx_table *)(cfg_blob + offset);
+    // This is hideous, but the file formats are still very close
+    if (version==0) { 
+       files_v0 = (struct file_idx_table_v0 *)(cfg_blob + offset);
+       V3_Print("Number of files in cfg: %d\n", (uint32_t)(files_v0->num_files));
+    } else {
+       files_v1 = (struct file_idx_table_v1 *)(cfg_blob + offset);
+       V3_Print("Number of files in cfg: %d\n", (uint32_t)(files_v1->num_files));
+    }
 
-    V3_Print("Number of files in cfg: %d\n", (uint32_t)(files->num_files));
 
     file_tree = v3_cfg_subtree(v3_cfg_subtree(cfg->cfg, "files"), "file");
 
@@ -167,7 +208,6 @@ static struct v3_config * parse_config(void * cfg_blob) {
        char * id = v3_cfg_val(file_tree, "id");
        char * index = v3_cfg_val(file_tree, "index");
        int idx = atoi(index);
-       struct file_hdr * hdr = &(files->hdrs[idx]);
        struct v3_cfg_file * file = NULL;
 
        file = (struct v3_cfg_file *)V3_Malloc(sizeof(struct v3_cfg_file));
@@ -182,11 +222,38 @@ static struct v3_config * parse_config(void * cfg_blob) {
        V3_Print("File index=%d id=%s\n", idx, id);
 
        strncpy(file->tag, id, V3_MAX_TAG_LEN);
-       file->size = hdr->size;
-       file->data = cfg_blob + hdr->offset;
 
-       V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
-       V3_Print("file data at %p\n", file->data);
+       if (version==0) { 
+           struct file_hdr_v0 * hdr = &(files_v0->hdrs[idx]);
+
+           file->size = hdr->size;
+           file->data = cfg_blob + hdr->offset;
+           file->hash = 0;
+           
+           V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
+           V3_Print("file data at %p\n", file->data);
+
+       } else if (version==1) { 
+           struct file_hdr_v1 * hdr = &(files_v1->hdrs[idx]);
+           unsigned long hash;
+
+           file->size = hdr->size;
+           file->data = cfg_blob + hdr->offset;
+           file->hash = hdr->hash;
+
+           V3_Print("Storing file data offset = %d, size=%d\n", (uint32_t)hdr->offset, hdr->size);
+           V3_Print("file data at %p\n", file->data);
+           V3_Print("Checking file data integrity...\n");
+           if ((hash = v3_hash_buffer(file->data, file->size)) != file->hash) {
+               PrintError("File data corrupted! (orig hash=0x%lx, new=0x%lx\n",
+                          file->hash, hash);
+               return NULL;
+           }
+           V3_Print("File data OK\n");
+           
+       }
+           
+           
        list_add( &(file->file_node), &(cfg->file_list));
 
        V3_Print("Keying file to name\n");
index 0bc5172..ec26ac6 100644 (file)
@@ -1,16 +1,17 @@
 
 CC = gcc
-CFLAGS = -Wall -g 
+INC = -I../../linux_usr
+CFLAGS = -Wall -g  $(INC)
 LDFLAGS = 
 
 
-OBJS = main.c ezxml.c
+OBJS = main.c ezxml.c ../../linux_usr/libv3_ctrl.a
 
 all: builder
 
 
 builder: $(OBJS)
-       $(CC) $(CFLAGS) $(OBJS) -o build_vm
+       $(CC) $(CFLAGS) $(OBJS) -lv3_ctrl -L../../linux_usr -o build_vm
 
 clean:         
-       rm -f *.o build_vm
\ No newline at end of file
+       rm -f *.o build_vm
index 15b85ce..c98637d 100644 (file)
@@ -4,18 +4,42 @@
 #include <getopt.h>
 #include <unistd.h>
 #include <string.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <errno.h>
 
+#include <v3_ctrl.h>
 
 #define MAX_FILES 256
 
+/*
 struct file_info {
     int size;
     char filename[2048];
     char id[256];
 };
+*/
+
+/*
+
+   The Palacios cookie encodes "v3vee" followed by a 
+   3 byte version code.   There are currently two versions:
+
+    \0\0\0 => original (no checksum)
+    \0\0\1 => checksum
+*/
+
+#define COOKIE "v3vee\0\0\0"
+#define COOKIE_LEN            8
+#define COOKIE_VERSION_OFFSET 5
+#define COOKIE_VERSION_LEN    3
+
+int version = 1; // default version is now 1
+
 
 int num_files = 0;
 struct file_info files[MAX_FILES];
@@ -28,7 +52,7 @@ int write_output(char * filename, ezxml_t cfg_output);
 int copy_file(int file_index, FILE * data_file);
 
 void usage() {
-    printf("Usage: build_vm <infile> [-o outfile]\n");
+    printf("Usage: build_vm <infile> [-v version] [-o outfile]\n");
 }
 
 int main(int argc, char ** argv) {
@@ -36,16 +60,18 @@ int main(int argc, char ** argv) {
     char * outfile = NULL;
     char * infile = NULL;
 
-
     memset((char *)files, 0, sizeof(files));
 
     opterr = 0;
 
-    while ((c = getopt(argc, argv, "ho:")) != -1) {
+    while ((c = getopt(argc, argv, "ho:v:")) != -1) {
        switch (c) {
            case 'o':
                outfile = optarg;
                break;
+           case 'v':
+                version = atoi(optarg);
+                break;
            case 'h':
                usage();
                return 1;
@@ -59,6 +85,11 @@ int main(int argc, char ** argv) {
        return 1;
     }
 
+    if (version != 0 && version != 1) { 
+       printf("Only versions 0 and 1 are supported\n");
+       return 1;
+    }
+
     infile = argv[optind];
 
 
@@ -163,6 +194,77 @@ int parse_config_input(ezxml_t cfg_input) {
 }
 
 
+static int generate_file_hashes (char * filename,
+                                 unsigned long long hdr_offset,
+                                 int num_files) {
+    unsigned char * file_data;
+    unsigned char * out_data;
+    struct mem_file_hdr * hdrs = NULL;
+    int i, fd, out_fd;
+    struct stat st;
+
+    out_fd = open(filename, O_RDWR);
+    if (!out_fd) {
+        fprintf(stderr, "Couldn't open output file %s\n", filename);
+        return -1;
+    }
+    fstat(out_fd, &st);
+
+    /* mmap the out file, easy access to file headers */
+    if ((out_data = mmap(0,
+                         st.st_size,
+                         PROT_READ|PROT_WRITE,
+                         MAP_SHARED,
+                         out_fd,
+                         0)) == MAP_FAILED) {
+        fprintf(stderr, "Error mapping output file (%d)\n", errno);
+        return -1;
+    }
+
+    hdrs = (struct mem_file_hdr *)(out_data + hdr_offset);
+
+    /* mmap each file, then update it's hash */
+    for (i = 0; i < num_files; i++) {
+
+        fd = open(files[i].filename, O_RDONLY);
+        if (!fd) {
+            fprintf(stderr, "Error opening file %s\n",
+                    files[i].filename);
+            return -1;
+        }
+
+        if ((file_data = mmap(0, 
+                              hdrs[i].file_size, 
+                              PROT_READ,
+                              MAP_PRIVATE,
+                              fd,
+                              0)) == MAP_FAILED) {
+            fprintf(stderr, "Could not mmap file for hashing\n");
+            return -1;
+         }
+
+         /* generate the hash and save it */
+        hdrs[i].file_hash = v3_hash_buffer(file_data, hdrs[i].file_size);
+        printf("Generating hash for file %s (hash=0x%lx)\n", 
+                files[i].filename, hdrs[i].file_hash);
+
+        munmap(file_data, hdrs[i].file_size);
+        close(fd);
+    }
+
+    munmap(out_data, st.st_size);
+    return 0;
+}
+
+void gen_cookie(char *dest)
+{
+    memcpy(dest,COOKIE,COOKIE_LEN);
+    dest[COOKIE_VERSION_OFFSET]   = (((unsigned)version) >> 16) & 0xff;
+    dest[COOKIE_VERSION_OFFSET+1] = (((unsigned)version) >>  8) & 0xff;
+    dest[COOKIE_VERSION_OFFSET+2] = (((unsigned)version) >>  0) & 0xff;
+}
+
+
 int write_output(char * filename, ezxml_t cfg_output) {
     FILE * data_file = fopen(filename, "w+");
     char * new_cfg_str = ezxml_toxml(cfg_output);
@@ -171,9 +273,13 @@ int write_output(char * filename, ezxml_t cfg_output) {
     int i = 0;
     unsigned long long offset = 0;
     unsigned long long file_cnt = num_files;
+    unsigned long long hdr_offset = 0;
+    char cookie[COOKIE_LEN];
 
-    fwrite("v3vee\0\0\0", 8, 1, data_file);
-    offset += 8;
+    gen_cookie(cookie);
+
+    fwrite(cookie, COOKIE_LEN, 1, data_file);
+    offset += COOKIE_LEN;
 
     //  printf("New config: \n%s\n", new_cfg_str);
     
@@ -191,14 +297,30 @@ int write_output(char * filename, ezxml_t cfg_output) {
     fwrite(&file_cnt, 8, 1, data_file);
     offset += 8;
 
-    // each index entry is 16 bytes long plus end padding
-    offset += (16 * num_files) + 8;
 
+    if (version==0) { 
+       // for version 0, we simply have the file num, offset, size list
+       // each index entry is 16 bytes long plus end padding
+       offset += (16 * num_files) + 8;
+    } else if (version==1) { 
+       // For a version 1, we have the file num, offset, size, and hash list
+       // We need to remember where this begins in the file, though...
+       hdr_offset = offset;
+
+       // each index entry is (16+sizeof(unsigned long)) bytes long plus end padding
+       offset += ((16 + sizeof(unsigned long)) * num_files) + 8;
+    }
+    
     for (i = 0; i < num_files; i++) {
        fwrite(&i, 4, 1, data_file);
        fwrite(&(files[i].size), 4, 1, data_file);
        fwrite(&offset, 8, 1, data_file);
 
+       if (version==1) { 
+           /* we can't generate the hash yet, zero for now */
+           fwrite(&zero, sizeof(unsigned long), 1, data_file);
+       }
+
        offset += files[i].size;
     }
 
@@ -210,9 +332,18 @@ int write_output(char * filename, ezxml_t cfg_output) {
        
     }
     
+    fclose(data_file);
 
+    if (version==1) { 
+       // We now will go back and place the hashes
+       if (generate_file_hashes(filename,
+                                hdr_offset,
+                                num_files) < 0) {
+           fprintf(stderr, "Error generating file hashes\n");
+           return -1;
+       }
+    }
 
-    fclose(data_file);
 
     return 0;
 }