From f3f50c9a315f0969ab68fb77c8b057a5039973a6 Mon Sep 17 00:00:00 2001
From: Dario Pinto <dario.pinto@cea.fr>
Date: Tue, 1 Sep 2020 10:44:38 +0200
Subject: [PATCH] add GreatView

---
 cgc-challenges/GreatView/.frama-c/GNUmakefile |  51 ++
 .../.frama-c/GreatView.parse/metrics.log      |   0
 .../.frama-c/GreatView.parse/warnings.log     |   1 +
 cgc-challenges/GreatView/.frama-c/path.mk     |   1 +
 cgc-challenges/GreatView/README.md            |  47 ++
 cgc-challenges/GreatView/include/cgc_stdint.h |  38 ++
 cgc-challenges/GreatView/lib/cgc_libc.h       | 500 ++++++++++++++
 cgc-challenges/GreatView/lib/libc.c           | 514 ++++++++++++++
 cgc-challenges/GreatView/src/cgc_viewscript.h |  34 +
 cgc-challenges/GreatView/src/service.c        |  35 +
 cgc-challenges/GreatView/src/viewscript.c     | 640 ++++++++++++++++++
 cgc-challenges/lib/common.c                   | 146 ++++
 cgc-challenges/lib/common.h                   |  14 +
 cgc-challenges/lib/fc_stubs.h                 |  18 +
 cgc-challenges/lib/libcgc.c                   |  36 +
 cgc-challenges/lib/libcgc.h                   |   2 +
 16 files changed, 2077 insertions(+)
 create mode 100644 cgc-challenges/GreatView/.frama-c/GNUmakefile
 create mode 100644 cgc-challenges/GreatView/.frama-c/GreatView.parse/metrics.log
 create mode 100644 cgc-challenges/GreatView/.frama-c/GreatView.parse/warnings.log
 create mode 120000 cgc-challenges/GreatView/.frama-c/path.mk
 create mode 100644 cgc-challenges/GreatView/README.md
 create mode 100644 cgc-challenges/GreatView/include/cgc_stdint.h
 create mode 100644 cgc-challenges/GreatView/lib/cgc_libc.h
 create mode 100644 cgc-challenges/GreatView/lib/libc.c
 create mode 100644 cgc-challenges/GreatView/src/cgc_viewscript.h
 create mode 100644 cgc-challenges/GreatView/src/service.c
 create mode 100644 cgc-challenges/GreatView/src/viewscript.c

diff --git a/cgc-challenges/GreatView/.frama-c/GNUmakefile b/cgc-challenges/GreatView/.frama-c/GNUmakefile
new file mode 100644
index 000000000..2ad6c92ea
--- /dev/null
+++ b/cgc-challenges/GreatView/.frama-c/GNUmakefile
@@ -0,0 +1,51 @@
+# Makefile template for Frama-C/Eva case studies.
+# For details and usage information, see the Frama-C User Manual.
+
+### Prologue. Do not modify this block. #######################################
+-include path.mk
+FRAMAC ?= frama-c
+include $(shell $(FRAMAC)-config -scripts)/prologue.mk
+###############################################################################
+
+# Edit below as needed. MACHDEP is mandatory. Suggested flags are optional.
+
+MACHDEP = x86_32
+
+## Preprocessing flags (for -cpp-extra-args)
+CPPFLAGS    += \
+  -DPATCHED \
+  -I../../lib \
+  -I../lib \
+  -I../include \
+
+## General flags
+FCFLAGS     += \
+  -add-symbolic-path=..:. \
+  -kernel-warn-key annot:missing-spec=abort \
+  -kernel-warn-key typing:implicit-function-declaration=abort \
+  -absolute-valid-range 0x4347C000-0x4347FFFF \
+  -c11
+
+## Eva-specific flags
+EVAFLAGS    += \
+  -eva-precision 2 \
+  -eva-warn-key builtins:missing-spec=abort \
+  -eva-warn-key garbled-mix=inactive \
+  -eva-use-spec cgc_find_path \
+
+## GUI-only flags
+FCGUIFLAGS += \
+
+## Analysis targets (suffixed with .eva)
+TARGETS = GreatView.eva
+
+### Each target <t>.eva needs a rule <t>.parse with source files as prerequisites
+GreatView.parse: \
+  ../src/service.c \
+  ../src/viewscript.c \
+  ../lib/libc.c \
+
+
+### Epilogue. Do not modify this block. #######################################
+include $(shell $(FRAMAC)-config -scripts)/epilogue.mk
+###############################################################################
diff --git a/cgc-challenges/GreatView/.frama-c/GreatView.parse/metrics.log b/cgc-challenges/GreatView/.frama-c/GreatView.parse/metrics.log
new file mode 100644
index 000000000..e69de29bb
diff --git a/cgc-challenges/GreatView/.frama-c/GreatView.parse/warnings.log b/cgc-challenges/GreatView/.frama-c/GreatView.parse/warnings.log
new file mode 100644
index 000000000..54ceec602
--- /dev/null
+++ b/cgc-challenges/GreatView/.frama-c/GreatView.parse/warnings.log
@@ -0,0 +1 @@
+[kernel] warning: attempting to save on non-zero exit code: modifying filename into `/home/dario/git/open-source-case-studies/cgc-challenges/GreatView/.frama-c/GreatView.parse/framac.sav.error'.
diff --git a/cgc-challenges/GreatView/.frama-c/path.mk b/cgc-challenges/GreatView/.frama-c/path.mk
new file mode 120000
index 000000000..222d0e049
--- /dev/null
+++ b/cgc-challenges/GreatView/.frama-c/path.mk
@@ -0,0 +1 @@
+../../frama-c-cgc-path.mk
\ No newline at end of file
diff --git a/cgc-challenges/GreatView/README.md b/cgc-challenges/GreatView/README.md
new file mode 100644
index 000000000..75f70b757
--- /dev/null
+++ b/cgc-challenges/GreatView/README.md
@@ -0,0 +1,47 @@
+# CGC Challenge Binary Template
+
+## Author Information
+
+"Ben Schmidt" <info@narfindustries.com>
+
+### DARPA performer group
+
+Narf Industries (NRFIN)
+
+## Description
+
+SafeTechs is proud to announce the latest in our ever-expanding line of cloud offerings: GreatView, a memory-as-a-service (MaaS) technology that allows you to easily expand the amount of memory to a local application.
+As an added benefit, you can retrieve this stored data in any number of supported views, abstracting away all the hassle of converting endianess and data types.
+
+
+### Feature List
+
+Using our patent-pending array management language, you can quickly and easily store and retrieve arbitrary values in any way that you so choose.
+Because all the data is stored in memory, and our servers are located in some of the fastest data centers in the world, you can be certain that you can access this data as fast as possible.
+
+
+## Vulnerability
+
+The main vulnerability in this CB is based closely off of CVE-2014-1705, a vulnerability in V8's handling of ArrayViews that lead to an arbitrary read-write of memory.
+In this CVE, by defining a getter for the byteLength attribute of an Array object, it was possible to fool the ArrayView constructor into creating a view with arbitrary bounds.
+Similarly, this CB allows users to override the byteSize attribute of a view with a summation of declared variables, which will then be trusted by get and set functions.
+This leads to an arbitrary read-write to the entire process space.
+
+There is an additional vulnerability that causes a tokenization function to write outside the bounds of the lines array.
+Due to improper bounds checking, it is possible to cause run\_viewscript to add more lines to the lines array than it has allocated, leading to a crash.
+
+### Generic class of vulnerability
+
+Improper bounds checking
+
+### CWE classification
+
+CWE-131: Incorrect Calculation of Buffer Size
+CWE-787: Out-of-bounds Write
+
+## Challenges
+Discovery of this vulnerability requires the CRS to utilize the ability to set the byteSize attribute of a view to access outside the bounds of the array.
+As no example of this is provided in pollers, competitors' must independently discover that this is possible, and properly create and reference variables with large enough values to access outside the bounds of the view.
+
+Patching will also prove difficult, as a CRS must properly enforce bounds checking of the array to prevent all crashes.
+Multiple PoVs exercising the vulnerability in different ways have been provided for reference.
diff --git a/cgc-challenges/GreatView/include/cgc_stdint.h b/cgc-challenges/GreatView/include/cgc_stdint.h
new file mode 100644
index 000000000..4f1671a31
--- /dev/null
+++ b/cgc-challenges/GreatView/include/cgc_stdint.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Narf Industries <info@narfindustries.com>
+ *
+ * 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 STDINT_H
+#define STDINT_H
+
+#define FALSE 0
+#define true 1
+#define false 0
+#define uint64_t unsigned long long
+#define uint32_t unsigned int
+#define uint16_t unsigned short
+#define uint8_t unsigned char
+#define bool uint8_t
+#define int32_t int
+#define int16_t short
+#define int8_t char
+
+#endif
diff --git a/cgc-challenges/GreatView/lib/cgc_libc.h b/cgc-challenges/GreatView/lib/cgc_libc.h
new file mode 100644
index 000000000..c854065e5
--- /dev/null
+++ b/cgc-challenges/GreatView/lib/cgc_libc.h
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) Narf Industries <info@narfindustries.com>
+ *
+ * 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 LIBC_H
+#define LIBC_H
+
+#include "libcgc.h"
+
+
+#define MAGICWORD "You didn't say the magic word."
+#define MEMERR "Clever girl."
+#define RNDERR "The essence of chaos."
+#define COOKIEFAIL "Friend is someone to share the last cookie with."
+
+/**
+ * Gets size of struct member
+ *
+ * @param t Struct type
+ * @param m Member to check
+ * @return Size of structure
+ */
+#define MEMBERSIZE(t,m) sizeof(((t*)0)->m)
+
+/**
+ * Sends a buffer and terminates on failure.
+ *
+ * @param s Size of the buffer
+ * @param b Buffer
+ * @return Number of bytes sent
+ */
+#define SSEND(s,b) if(cgc_sendall(STDOUT,b,s)<0)  cgc__terminate(3);
+
+/**
+ * Sends a buffer+newline and terminates on failure.
+ *
+ * @param s Size of the buffer
+ * @param b Buffer
+ * @return Number of bytes sent
+ */
+#define SSENDL(s,b) if(cgc_sendline(STDOUT,b,s)<0) cgc__terminate(6);
+
+/**
+ * Sends a buffer+newline and terminates on failure.
+ *
+ * @param b Buffer
+ * @return Number of bytes sent
+ */
+
+/**
+ * Sends an error message and terminates.
+ *
+ * @param b Buffer
+ * @param c Error code
+ */
+#define TERM(b,c)  LOG(b); cgc__terminate(c);
+
+/**
+ * Receives a newline terminated string into buffer, and replaces newline with NULL
+ * Terminates on error
+ *
+ * @param s Size of the buffer
+ * @param b Buffer
+ * @return Data in buffer
+ */
+#define SRECV(s,b) if(cgc_recvline(STDIN,b,s)<0){SSENDL(sizeof(MAGICWORD)-1,MAGICWORD); cgc__terminate(2);}
+
+/**
+ * Receives bytes into buffer
+ * Terminates on error
+ *
+ * @param s Number of bytes to cgc_read into the buffer
+ * @param b Buffer
+ * @return Data in buffer
+ */
+#define RECV(s,b) if(recv(STDIN,b,s)<0){SSENDL(sizeof(MAGICWORD)-1,MAGICWORD); cgc__terminate(4);}
+
+/**
+ * Thin wrapper to allocate
+ * Terminates on error
+ *
+ * @param x Is executable
+ * @param a Location to store address 
+ * @param s Size of allocation
+ * @return Address in a
+ */
+#define ALLOC(x,a,s) if(cgc_allocate(s,x,a)!=0){ SSENDL(sizeof(MEMERR)-1,MEMERR); cgc__terminate(9);}
+
+/**
+ * Thin wrapper to deallocate
+ * Terminates on error
+ *
+ * @param a Address to deallocate
+ * @param s Size of allocation
+ */
+#define DEALLOC(a,s) if(deallocate(a,s)!=0){ SSENDL(sizeof(MEMERR)-1,MEMERR); cgc__terminate(18);}
+
+/**
+ * Thin wrapper to random
+ * Terminates on error
+ *
+ * @param b Buffer to store random data
+ * @param s Count of random bytes to cgc_read
+ * @param r Location to store number of bytes cgc_read
+ * @return Random data in b
+ */
+#define RAND(b,s,r) if (cgc_random(b,s,r)){ SSENDL(sizeof(RNDERR)-1,RNDERR); cgc__terminate(19);}
+
+#define STACKPROTECTINIT extern uint32_t cgc___cookie;
+#define STACKPROTECTADD  uint32_t __wat = cgc___cookie;
+#define STACKPROTECTCHK  if ( (__wat = __wat ^ cgc___cookie) != 0 ) __stack_cookie_fail();
+
+typedef enum {
+    YOLO,
+    SHEAP,
+    SSHEAP
+} heaptype;
+
+extern uint32_t cgc___hcookie[3];
+
+#define PAGE_SIZE 4096
+typedef struct heap_chunk heap_chunk_t;
+
+struct heap_chunk {
+    uint32_t cookie;
+    heap_chunk_t *prev;
+    heap_chunk_t *next;
+    uint32_t size;
+};
+
+/**
+ * Simple prompt handler
+ *
+ * @param buf Buffer to store response
+ * @param s Size of response buffer
+ * @param prompt Prompt to send 
+ * @return Response data in buf
+ */
+void cgc_promptc(char *buf, uint16_t  size, char *prompt);
+
+/**
+ * Convert unsigned integer to string
+ *
+ * @param str_buf Destination buffere
+ * @param buf_size Destination buffer size
+ * @param i Integer to convert
+ * @return Ascii-representation of i in str_buf
+ */
+int cgc_uint2str(char* str_buf, int buf_size, uint32_t i);
+
+/**
+ * Convert signed integer to string
+ *
+ * @param str_buf Destination buffere
+ * @param buf_size Destination buffer size
+ * @param i Integer to convert
+ * @return Ascii-representation of i in str_buf
+ */
+int cgc_int2str(char* str_buf, int buf_size, int i);
+
+/**
+ * Convert string to unsigned integer
+ *
+ * @param str_buf Source buffer
+ * @return integer
+ */
+uint32_t cgc_str2uint(const char* str_buf);
+
+/**
+ * Convert string to signed integer
+ *
+ * @param str_buf Source buffer
+ * @return integer
+ */
+int cgc_str2int(const char* str_buf);
+
+/**
+ * Send bytes from buffer to file descriptor
+ *
+ * @param fd File descriptor to send on
+ * @param buf Source buffer
+ * @param size Number of bytes to send
+ * @return Number of bytes sent, -1 on error
+ */
+int cgc_sendall(int fd, const char *buf, size_t size);
+
+/**
+ * Send bytes from buffer to file descriptor with newline
+ *
+ * @param fd File descriptor to send on
+ * @param buf Source buffer
+ * @param size Number of bytes to send
+ * @return Number of bytes sent, -1 on error
+ */
+int cgc_sendline(int fd, const char *buf, size_t size);
+
+/**
+ * Receive line from file descriptor
+ *
+ * @param fd File descriptor to receive on
+ * @param buf Destination buffer
+ * @param size Size of destination buffer
+ * @return Number of bytes received, -1 on error
+ */
+int cgc_recvline(int fd, char *buf, size_t size);
+
+/**
+ * Receive buffer until term character is reached
+ *
+ * @param fd File descriptor to receive on
+ * @param buf Destination buffer
+ * @param size Size of destination buffer
+ * @param term Terminating character
+ * @return Number of bytes received, -1 on error
+ */
+int cgc_recvuntil(int fd, char *buf, size_t size, char term);
+
+/**
+ * Receive bytes from file descriptor
+ *
+ * @param fd File descriptor to receive on
+ * @param buf Destination buffer
+ * @param size Number of bytes to receive
+ * @return Number of bytes received, -1 on error
+ */
+int cgc_recv(int fd, char *buf, size_t size); 
+
+/**
+ * Copy a string
+ *
+ * @param s1 Destination buffer
+ * @param s2 Source buffer
+ * @return Number of bytes copied
+ */
+size_t strcpy(char *s1, char *s2);
+
+/**
+ * Copy a string with bounds checking
+ *
+ * @param s1 Destination buffer
+ * @param s2 Source buffer
+ * @param n Size of destination buffer
+ * @return Number of bytes copied
+ */
+size_t strncpy(char *s1, char *s2, size_t n);
+
+/**
+ * Concatenate two strings
+ *
+ * @param s1 Main string
+ * @param s2 String to be concatenated
+ * @return s1
+ */
+char * cgc_strcat(char *s1, char *s2);
+
+/**
+ * Find length of string
+ *
+ * @param s String
+ * @return length of s
+ */
+size_t strlen(char *s);
+
+/**
+ * Check if two strings are identical
+ *
+ * @param s1 String 1
+ * @param s2 String 2
+ * @return 1 if identical, 0 if different
+ */
+int cgc_streq(char *s1, char *s2);
+
+/**
+ * Compare two strings
+ *
+ * @param s1 String 1
+ * @param s2 String 2
+ * @return 0 if identical, 1 if different
+ */
+int cgc_strncmp(char *s1, char *s2, size_t n);
+
+/**
+ * Check if a string starts with another string
+ *
+ * @param s1 String to check
+ * @param s2 String that s1 might start with
+ * @return 1 if s1 starts with s2, 0 if not
+ */
+int cgc_startswith(char *s1, char *s2);
+
+/**
+ * Set a buffer to provided character
+ *
+ * @param dst Destination buffer
+ * @param c Character to repeat
+ * @param n Number of times to copy character
+ * @return dst
+ */
+void * memset(void *dst, char c, size_t n); 
+
+/**
+ * Copy bytes from one buffer to another
+ *
+ * @param dst Destination buffer
+ * @param src Source buffer
+ * @param n Number of bytes to copy
+ * @return dst
+ */
+void * memcpy(void *dst, void *src, size_t n); 
+
+/**
+ * Convert byte to hex character string
+ *
+ * @param b Byte to convert
+ * @param h Destination hex string
+ * @return h
+ */
+char * cgc_b2hex(uint8_t b, char *h);
+
+/**
+ * Locate character in string
+ *
+ * @param str String to search
+ * @param h Character to find
+ * @return Pointer to character in string, or NULL
+ */
+char * strchr(char *str, char c); 
+
+/**
+ * Tokenize string. Loosely based on strtok.
+ *
+ * @param s String to tokenize, or NULL to continue with previous one
+ * @param sep Character to sep on
+ * @return Pointer to next string, or NULL
+ */
+char * strtok(char *s, char sep); 
+
+/**
+ * Sleep process
+ *
+ * @param s Amount of time to sleep
+ */
+void cgc_sleep(int s);
+
+/**
+ * Compare two buffers
+ *
+ * @param a First buffer
+ * @param b Second buffer
+ * @param n Number of bytes to compare
+ * @return -1 if not equal, 0 if equal
+ */
+int memcmp(void *a, void *b, size_t n); 
+
+/**
+ * Allocate a buffer on simple heap
+ *
+ * @param size Size of buffer to allocate
+ * @return Pointer to newly allocated buffer 
+ */
+void *cgc_nmalloc(size_t size);
+
+/**
+ * Allocate a buffer on secure heap
+ *
+ * @param size Size of buffer to allocate
+ * @return Pointer to newly allocated buffer 
+ */
+void *cgc_smalloc(size_t size);
+
+/**
+ * Allocate a buffer on super secure heap
+ *
+ * @param size Size of buffer to allocate
+ * @return Pointer to newly allocated buffer 
+ */
+void *cgc_ssmalloc(size_t size);
+
+/**
+ * Free an allocated buffer on simple heap
+ *
+ * @param p Pointer to buffer
+ */
+void cgc_nfree(void *p);
+
+/**
+ * Free an allocated buffer on secure heap
+ *
+ * @param p Pointer to buffer
+ */
+void cgc_sfree(void *p);
+
+/**
+ * Free an allocated buffer on super secure heap
+ *
+ * @param p Pointer to buffer
+ */
+void cgc_ssfree(void *p);
+
+/**
+ * Free an allocated buffer
+ *
+ * @param p Pointer to buffer
+ */
+void free(void *p);
+
+/**
+ * Allocate a buffer on heap
+ *
+ * @param size Size of buffer to allocate
+ * @return Pointer to newly allocated buffer 
+ */
+void *malloc(size_t size);
+
+/**
+ * Allocate a zeroed buffer on heap
+ *
+ * @param size Size of buffer to allocate
+ * @return Pointer to newly allocated buffer 
+ */
+void *calloc(size_t size); 
+
+/**
+ * Configure the heap type to use
+ *
+ * @param type Type of heap
+ */
+void cgc_setheap(uint32_t type);
+
+/**
+ * Initialize stack cookie
+ *
+ */
+void cgc___stack_cookie_init(); 
+
+/**
+ * Check stack cookie
+ *
+ */
+void cgc___stack_cookie_fail(); 
+
+/**
+ * Check heap cookie
+ *
+ */
+void cgc___heap_cookie_fail(); 
+
+/**
+ * Check heap cookie if enabled, return next chunk.
+ * Terminates on error
+ *
+ * @param a current heap_chunk_t 
+ * @param type heap type
+ * @return a->next if safe, terminate if not
+ */
+inline heap_chunk_t* __attribute__((always_inline)) HNEXT(heap_chunk_t *a, 
+        heaptype type) {
+    if (type && a->cookie != cgc___hcookie[type])  cgc___heap_cookie_fail();
+    return a->next;
+}
+
+/**
+ * Check heap cookie if enabled, return next chunk.
+ * Terminates on error
+ *
+ * @param a current heap_chunk_t 
+ * @param type heap type
+ * @return a->next if safe, terminate if not
+ */
+inline heap_chunk_t* __attribute__((always_inline)) HPREV(heap_chunk_t *a, 
+        heaptype type) {
+    if (type && a->cookie != cgc___hcookie[type])  cgc___heap_cookie_fail();
+    return a->prev;
+}
+
+/**
+ * Validate that heap is walkable in all directions
+ * Terminates on error
+ * 
+ */ 
+void cgc_checkheap();
+#endif
+
diff --git a/cgc-challenges/GreatView/lib/libc.c b/cgc-challenges/GreatView/lib/libc.c
new file mode 100644
index 000000000..202ca0d4d
--- /dev/null
+++ b/cgc-challenges/GreatView/lib/libc.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) Narf Industries <info@narfindustries.com>
+ *
+ * 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 "libcgc.h"
+
+
+
+void (*freep)(void *);
+void *(*mallocp)(size_t);
+
+bool cgc_heapinit_done = false;
+
+heap_chunk_t freedc[3] = {0};
+
+heap_chunk_t cgc_allocatedc[3] = {0};
+
+heap_chunk_t *freed[3] = {0};
+
+heap_chunk_t *cgc_allocated[3] = {0};
+
+uint8_t *cgc_lastpage[3] = {0};
+uint32_t cgc_curleft[3] = {0};
+
+uint32_t cgc___cookie[3] = {0};
+uint32_t cgc___hcookie[3] = {0};
+heaptype cgc___htype = 0;
+
+static char *strtok_last = NULL;
+
+void cgc_promptc(char *buf, uint16_t  size, char *prompt) {
+
+    SSEND(strlen(prompt), prompt);
+
+    SRECV((uint32_t)size, buf);
+}
+
+
+int cgc_recv(int fd, char *buf, size_t size) {
+    size_t bytes_read = 0;
+    size_t total_read = 0;
+
+    if(!size)
+        return 0;
+
+    if (!buf)
+        return -1;
+
+    while (size) {
+        if (cgc_receive(fd, buf, size, &bytes_read))
+            return -1;
+        
+        total_read += bytes_read;
+        size -= bytes_read;
+        buf += bytes_read;
+    }
+
+    return total_read;
+
+}
+
+
+int cgc_recvline(int fd, char *buf, size_t size) {
+    return cgc_recvuntil(fd, buf, size, '\n');
+}
+
+int cgc_recvuntil(int fd, char *buf, size_t size, char term) {
+    size_t bytes_read = 0;
+    size_t total_read = 0;
+
+    if(!size)
+        return 0;
+
+    if (!buf)
+        return -1;
+
+    while (size) {
+        if (cgc_receive(fd, buf, 1, &bytes_read))
+            return -1;
+
+        total_read+=bytes_read;
+        size-=bytes_read;
+        
+        if(bytes_read && *buf == term)
+            break;
+        buf += bytes_read;
+    }
+
+    if (*(buf) != term)
+        return -2;
+    else
+        *(buf) = '\0';
+
+    return total_read;
+}
+
+//non-standard convention, returns num bytes copied instead of s1
+size_t strcpy(char *s1, char *s2) {
+    char *tmp = s1;
+    while (*s2) {
+        *tmp = *s2;
+        tmp++;
+        s2++;
+    }
+    *(tmp++)='\0';
+    return tmp-s1-1;
+}
+
+//non-standard convention, returns num bytes copied instead of s1
+size_t strncpy(char *s1, char *s2, size_t n) {
+    char *tmp = s1;
+    while ((tmp-s1 < n) && *s2) {
+        *tmp = *s2;
+        tmp++;
+        s2++;
+    }
+    *(tmp++)='\0';
+    return tmp-s1-1;
+}
+
+char * cgc_strcat(char *s1, char *s2) {
+    char *tmp = s1;
+    while (*tmp) tmp++;
+    strcpy(tmp,s2);
+    return s1;
+}
+
+size_t strlen(char *s) {
+    char *tmp = s;
+    while (*tmp) tmp++;
+    return (size_t)(tmp-s);
+}
+
+int cgc_streq(char *s1, char *s2) {
+    while (*s1 && *s2){
+        if (*s1 != *s2)
+            return 0;
+	    s1++;
+	    s2++;
+    }
+    return (*s1 == '\0') && (*s2 == '\0');
+}
+
+int cgc_strncmp(char *s1, char *s2, size_t n) {
+    while (*s1 && *s2 && n--){
+        if (*s1 != *s2)
+            return 1;
+	    s1++;
+	    s2++;
+    }
+    return !((*s1 == '\0') && (*s2 == '\0'));
+}
+
+int cgc_startswith(char *s1, char *s2) {
+    while (*s1 && *s2) {
+        if (*s1 != *s2)
+            return 0;
+	    s1++;
+	    s2++;
+    }
+    return *s2 == '\0';
+}
+
+
+
+void * memset(void *dst, char c, size_t n) {
+    size_t i;
+    for (i=0; i<n; i++) {
+        *((uint8_t*)dst+i) = c;
+    }
+    return dst;
+}
+
+void * memcpy(void *dst, void *src, size_t n) {
+    size_t i;
+    for (i=0; i<n; i++) {
+        *((uint8_t*)dst+i) = *((uint8_t*)src+i);
+    }
+    return dst;
+}
+
+char * cgc_b2hex(uint8_t b, char *h) {
+    if (b>>4 < 10)
+        h[0] = (b>>4)+0x30;
+    else
+        h[0] = (b>>4)+0x41-10;
+
+    if ((b&0xf) < 10)
+        h[1] = (b&0xf)+0x30;
+    else
+        h[1] = (b&0xf)+0x41-10;
+    h[2] = '\0';
+    return h;
+}
+
+char * strchr(char *str, char c) {
+    char *tmp = str;
+    while (*tmp) {
+        if (*tmp == c)
+            return tmp;
+        tmp++;
+    }
+    return 0;
+}
+
+char *strtok(char *s, char sep) {
+    char *c;
+    if (!s) {
+        if (!strtok_last)
+            return NULL;
+        s = strtok_last;
+        strtok_last = NULL;
+        //continue parsing
+    } 
+    
+    if (!(c = strchr(s,sep)))
+        return s;
+
+    *c = '\0';
+    c++;
+    strtok_last = c;
+    return s;
+}
+
+//modulus
+int cgc___umoddi3(int a, int b) {
+    return a-(a/b*b);
+}
+
+void cgc_sleep(int s) {
+    struct cgc_timeval tv;
+    tv.tv_sec = s;
+    tv.tv_usec = 0;
+    cgc_fdwait(0, NULL, NULL, &tv, NULL);
+}
+
+int memcmp(void *a, void *b, size_t n) {
+    size_t i;
+    for (i=0; i < n; i++)
+        if ( *(uint8_t*)(a+i) != *(uint8_t*)(b+i))
+            return -1;
+    return 0;
+}
+
+static void heapinit() {
+    int i;
+    RAND(&cgc___hcookie[SSHEAP], sizeof(cgc___hcookie[SSHEAP]), NULL);
+    cgc___hcookie[SHEAP] = 0x50C0FFEE;
+    for (i = 0; i < 3; i++) {
+        cgc_allocated[i] = &cgc_allocatedc[i];
+        freed[i] = &freedc[i];
+        cgc_allocated[i]->next = cgc_allocated[i];
+        cgc_allocated[i]->prev = cgc_allocated[i];
+        cgc_allocated[i]->cookie = cgc___hcookie[i];
+        freed[i]->cookie = cgc___hcookie[i];
+        freed[i]->next = freed[i];
+        freed[i]->prev = freed[i];
+        cgc_heapinit_done = true;
+    }
+}
+
+static void insert(heap_chunk_t *head, heap_chunk_t *node, heaptype type) {
+    node->cookie = cgc___hcookie[type];
+    node->next = head;
+    node->prev = head->prev;
+    node->prev->next = node;
+    head->prev = node;
+}
+
+static void remove(heap_chunk_t *node) {
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+    node->next = NULL;
+    node->prev = NULL;
+}
+
+static void *cgc___malloc(size_t size, heaptype type) {
+    /*
+     * A very stupid malloc implementation, meant to be simple.
+     * Keeps a list of allocated and freed chunks
+     * Alloc walks list of freed chunks to see if any are large enough
+     * If not, it allocates space large enough to store
+     * Oh, and we never actually free pages. It's quality software.
+     *
+     */
+    if (!cgc_heapinit_done) 
+        heapinit();
+
+    if (size == 0 || size > 0x7fffffff)
+        return NULL;
+
+    heap_chunk_t *chunk = freed[type];
+    heap_chunk_t *frag = NULL;
+    heap_chunk_t *prev = NULL;
+
+    //need space for inline metadata
+    size += sizeof(heap_chunk_t);
+
+    //walk freed list to see if we can find match
+    //while we're walking free list, might as well coalesce as we go
+    //this will only coalesce adjacent blocks in the freelist
+    while (chunk->size < size && HNEXT(chunk,type) != freed[type]) {
+
+        //ommitted type of HNEXT(chunk,type) != freed here because freed is only node in BSS
+        //should never be adjacent
+        while ((uint8_t*)HNEXT(chunk,type) == ((uint8_t*)chunk)+chunk->size) {
+            frag = HNEXT(chunk,type);
+            remove(frag);
+            chunk->size += frag->size;
+        }
+
+        //make sure HNEXT(chunk,type) isn't freed after coalesce, though
+        if (HNEXT(chunk,type) == freed[type])
+            break;
+
+        chunk = HNEXT(chunk,type);
+
+    }
+
+    if (type && cgc___hcookie[type] != chunk->cookie)
+        cgc___heap_cookie_fail();
+
+
+    if (chunk->size >= size) {
+        //found a match, remove from freed list, add to allocated list, and return
+        //SSSENDL("found free chunk");
+        
+        remove(chunk);
+
+        //first, break up chunk if we can create another valid chunk out of it
+        //this will fragment badly under some workloads, but meh
+        if (chunk->size > (size+sizeof(heap_chunk_t)+1)) {
+            frag = (heap_chunk_t*)(((uint8_t*)chunk)+size);
+            frag->size = chunk->size - size;
+            chunk->size = size;
+            insert(freed[type],frag,type);
+        }
+
+        insert(cgc_allocated[type],chunk,type);
+        return ((uint8_t*)chunk)+sizeof(heap_chunk_t);
+    }
+
+    //see if free space in last allocated page is enough
+    if (size <= cgc_curleft[type]) {
+        //SSSENDL("had enough left in current page");
+        chunk = (heap_chunk_t*)cgc_lastpage[type];
+        chunk->size = size;
+        cgc_lastpage[type] += size;
+        cgc_curleft[type] -= size;
+        insert(cgc_allocated[type],chunk,type);
+        return ((uint8_t*)chunk)+sizeof(heap_chunk_t);
+    }
+
+    //need to allocate new page
+
+    //SSSENDL("allocating new page");
+    //first add the remaining page to our freed list as a lazy hack
+    //if there's not enough left, we just let it leak
+    if (cgc_curleft[type] > sizeof(heap_chunk_t)) {
+        //SSSENDL("adding remainder to free list");
+        chunk = (heap_chunk_t*)cgc_lastpage[type];
+        chunk->size = cgc_curleft[type];
+        insert(freed[type],chunk,type);
+    }
+
+    if (cgc_allocate(size,0,(void**)&chunk) != 0)
+        return NULL;
+
+    chunk->size = size;
+    insert(cgc_allocated[type],chunk,type);
+
+    cgc_lastpage[type] = ((uint8_t*)chunk)+size;
+    //this is bad.
+    if ((size & 0xfff) != 0)
+        cgc_curleft[type] = PAGE_SIZE-(size&(PAGE_SIZE-1));
+    else
+        cgc_curleft[type] = 0;
+    return ((uint8_t*)chunk)+sizeof(heap_chunk_t);
+}
+
+void cgc___free(void *p, heaptype type) {
+    /*
+     * A very stupid free for a very stupid malloc
+     * Simply moves pointer from allocated to free list
+     * With no typeing of anything, obviously
+     *
+     */
+    if (!p)
+        return;
+
+    heap_chunk_t *chunk = (heap_chunk_t*)((uint8_t*)p - sizeof(heap_chunk_t));
+
+    if (type && cgc___hcookie[type] != chunk->cookie)
+        cgc___heap_cookie_fail();
+
+    //fix allocated list
+    remove(chunk);
+
+    //add chunk to the freed list
+    insert(freed[type],chunk,type);
+    return;
+}
+
+void *cgc_nmalloc(size_t size) {
+    return cgc___malloc(size, YOLO);
+}
+
+void *cgc_smalloc(size_t size) {
+    return cgc___malloc(size, SHEAP);
+}
+
+void *cgc_ssmalloc(size_t size) {
+    return cgc___malloc(size, SSHEAP);
+}
+
+void *malloc(size_t size) {
+    if (!mallocp)
+        cgc_setheap(0);
+    return mallocp(size);
+}
+
+void cgc_nfree(void *p) {
+    return cgc___free(p, YOLO);
+}
+
+void cgc_sfree(void *p) {
+    return cgc___free(p, SHEAP);
+}
+
+void cgc_ssfree(void *p) {
+    return cgc___free(p, SSHEAP);
+}
+
+void free(void *p) {
+    if (!freep)
+        cgc_setheap(0);
+    freep(p);
+}
+
+void *calloc(size_t size) {
+    void *ptr;
+
+    if (!(ptr = malloc(size)))
+        return NULL;
+
+    memset(ptr,'\0',size);
+    return ptr;
+}
+
+
+void cgc_setheap(uint32_t type) {
+    if (type == 0x10100110) {
+        cgc___htype = YOLO;
+        mallocp = cgc_nmalloc;
+        freep = cgc_nfree;
+    } else if (type == 0xF0C0FFEE) {
+        cgc___htype = SHEAP;
+        mallocp = cgc_smalloc;
+        freep = cgc_sfree;
+    } else {
+        cgc___htype = SSHEAP;
+        mallocp = cgc_ssmalloc;
+        freep = cgc_ssfree;
+    }
+}
+
+void cgc_checkheap() {
+    //validate free and allocated lists!
+    uint32_t type = cgc___htype;
+    heap_chunk_t *chunk = freed[type];
+
+    //forward and backwards
+
+    while((chunk=HNEXT(chunk,type)) != freed[type]);
+    while((chunk=HPREV(chunk,type)) != freed[type]);
+    chunk = cgc_allocated[type];
+    while((chunk=HNEXT(chunk,type)) != cgc_allocated[type]);
+    while((chunk=HPREV(chunk,type)) != cgc_allocated[type]);
+}
+
+void cgc___stack_cookie_init() {
+    RAND(&cgc___cookie, sizeof(cgc___cookie), NULL);
+}
+
+void cgc___cookie_fail() {
+    SSENDL(sizeof(COOKIEFAIL)-1,COOKIEFAIL);
+    cgc__terminate(66);
+}
+
+void cgc___stack_cookie_fail() {
+    cgc___cookie_fail();
+}
+
+void cgc___heap_cookie_fail() {
+    cgc___cookie_fail();
+}
diff --git a/cgc-challenges/GreatView/src/cgc_viewscript.h b/cgc-challenges/GreatView/src/cgc_viewscript.h
new file mode 100644
index 000000000..566c1beab
--- /dev/null
+++ b/cgc-challenges/GreatView/src/cgc_viewscript.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Narf Industries <info@narfindustries.com>
+ *
+ * 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 VIEWSCRIPT_H
+#define VIEWSCRIPT_H
+/**
+ * Run a viewscript.
+ *
+ * @param script Script to run.
+ * @return 0 on success, err number on error
+ */
+int cgc_run_viewscript(char *script);
+
+#endif
diff --git a/cgc-challenges/GreatView/src/service.c b/cgc-challenges/GreatView/src/service.c
new file mode 100644
index 000000000..d2cff0707
--- /dev/null
+++ b/cgc-challenges/GreatView/src/service.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Narf Industries <info@narfindustries.com>
+ *
+ * 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 "libcgc.h"
+#include "common.h"
+#include "cgc_viewscript.h"
+
+int main(int cgc_argc, char *cgc_argv[]) {
+    char buf[4096] = {0};
+
+    int res = cgc_recvuntil(STDIN, buf, sizeof(buf), '\0');
+    if (res < 0)
+        return res;
+
+    return cgc_run_viewscript(buf);
+}
diff --git a/cgc-challenges/GreatView/src/viewscript.c b/cgc-challenges/GreatView/src/viewscript.c
new file mode 100644
index 000000000..2d5f50512
--- /dev/null
+++ b/cgc-challenges/GreatView/src/viewscript.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) Narf Industries <info@narfindustries.com>
+ *
+ * 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 "libcgc.h"
+#include "common.h"
+#include "cgc_viewscript.h"
+
+/*
+ * View scripts are incredibly simple, so much so that we don't have any kind of a simple parser.
+ * There are four commands:
+ * new <type> <name> <type args>
+ * get <var> <arg>
+ * set <var> <descriptor> <new val>
+ * delete <var>
+ *
+ * Commands are newline delimeted.
+ */
+
+#define NEWTOK "new"
+#define GETTOK "get"
+#define SETTOK "set"
+#define DELTOK "del"
+
+#define NUM "num"
+#define ARR "arr"
+#define VIEW "view"
+
+#define ERRSHORT 1
+#define ERRBADFMT 2
+#define ERRNOARG 3
+#define ERRNOSUCHTYPE 4
+#define ERRNOSUCHCMD 5
+#define ERRNOTYPE 6
+#define ERRNONAME 7
+#define ERRALREADYEXISTS 8
+#define ERRNOSUCHVAR 9
+#define ERRNOMEM 10
+#define ERRTOOBIG 11
+#define ERRWRONGTYPE 12
+#define ERRINVALIDIDX 13
+
+//max array size in ints
+#define MAXARRSIZE 2*1024*1024
+#define MAXSCRIPTSIZE 2*1024*1024
+
+typedef struct viewtype {
+    char *name;
+    size_t size;
+    int sign;
+} viewtype_t;
+
+static viewtype_t viewtypes[] = { 
+                            {"int", sizeof(int), 1},
+                            {"uint", sizeof(unsigned int), 0},
+                            {"short", sizeof(short), 1},
+                            {"ushort", sizeof(unsigned short), 0},
+                            {"byte", sizeof(char), 1},
+                            {"ubyte", sizeof(unsigned char), 0}
+};
+
+typedef enum {NUMTYPE, ARRTYPE, VIEWTYPE} varenum;
+
+typedef struct var {
+    struct var *next;
+    char *name;
+    varenum type;
+    int refcount;
+} var_t;
+
+typedef struct numvar {
+    var_t v;
+    int num;
+} numvar_t;
+
+typedef struct arrvar {
+    var_t v;
+    size_t size;
+    uint8_t arr[0];
+} arrvar_t;
+
+typedef struct viewvar {
+    var_t v;
+    arrvar_t *arr;
+    viewtype_t *view;
+    int sign;
+    char *bytesize;
+} viewvar_t;
+
+typedef struct nspace {
+    var_t *first;
+    var_t *last;
+    int count;
+} nspace_t;
+
+/**
+ * Create new number variable.
+ *
+ * @param name Name of new variable
+ * @param arg String containing constructor args
+ * @return 0 on success, err number on error
+ */
+static int cgc_newnum(char *name, char *arg); 
+
+/**
+ * Create new array variable.
+ *
+ * @param name Name of new variable
+ * @param arg String containing constructor args
+ * @return 0 on success, err number on error
+ */
+static int cgc_newarr(char *name, char *arg);
+
+/**
+ * Create new view variable.
+ *
+ * @param name Name of new variable
+ * @param arg String containing constructor args
+ * @return 0 on success, err number on error
+ */
+static int cgc_newview(char *name, char *arg);
+
+/**
+ * Handle "new" command
+ *
+ * @return 0 on success, err number on error
+ */
+static int cgc_handlenew();
+
+/**
+ * Handle "get" command
+ *
+ * @return 0 on success, err number on error
+ */
+static int cgc_handleget();
+
+/**
+ * Handle "set" command
+ *
+ * @return 0 on success, err number on error
+ */
+static int cgc_handleset();
+
+/**
+ * Handle "del" command
+ *
+ * @return 0 on success, err number on error
+ */
+static int cgc_handledel();
+
+/**
+ * Delete a variable from the namespace, by name.
+ *
+ * @param name Name of variable
+ * @return 0 on success, err number on error
+ */
+static int delvar(char *name); 
+
+/**
+ * Add a variable to the namespace.
+ *
+ * @param var Allocated variable struct
+ * @param name Name of variable
+ * @param type Type of the variable
+ * @return 0 on success, err number on error
+ */
+static int addvar(var_t *var, char *name, varenum type); 
+
+/**
+ * Get variable by name
+ *
+ * @param name Name of variable
+ * @return variable on success, NULL on error
+ */
+static var_t *getvar(char *name); 
+
+/**
+ * Calculate the total number, in bytes, of a view, from a list of num vars.
+ *
+ * @param varlist List of variable names
+ * @return Size in bytes on success, 0 on error
+ */
+static uint32_t cgc_calc_bytesize(char *varlist); 
+
+/**
+ * Run a line from a script
+ *
+ * @param cmd Line from script
+ * @return 0 on success, err number on failure
+ */
+static int runcmd(char *cmd); 
+
+
+static char *cmds[4] = { NEWTOK, GETTOK, SETTOK, DELTOK };
+static int (*handlers[4])() = { cgc_handlenew, cgc_handleget, cgc_handleset, cgc_handledel };
+static char *types[3] = { NUM, ARR, VIEW }; 
+static int (*constructors[3])(char *, char *) = { cgc_newnum, cgc_newarr, cgc_newview };
+static nspace_t global_nspace = {NULL, 0, 0};
+
+static int delvar(char *name) {
+    var_t *cur = global_nspace.first;
+    var_t *last = NULL;
+    while (cur) {
+        if (cgc_streq(cur->name,name)) {
+            if (last)
+                last->next = cur->next;
+            else
+                global_nspace.first = cur->next;
+
+            if (!cur->next)
+                global_nspace.last = last;
+
+            if (cur->type == VIEWTYPE) {
+                if (!(--(((viewvar_t*)cur)->arr->v.refcount)))
+                    free(((viewvar_t*)cur)->arr);
+            }
+
+            //we keep arrays around until all outstanding refs are gone
+            if (cur->refcount <= 0) //should be 0
+                free(cur);
+
+            global_nspace.count--;
+
+            return 0;
+        }
+        last = cur;
+        cur = cur->next;
+    }
+    return ERRNOSUCHVAR;
+}
+
+static int addvar(var_t *var, char *name, varenum type) {
+
+    if (!(var->name = calloc_Pvz(strlen(name)+1)))
+        return ERRNOMEM;
+
+    strcpy(var->name, name);
+
+    var->type = type;
+    if (global_nspace.last)
+        global_nspace.last->next = var;
+    global_nspace.last = var;
+    if (!global_nspace.first)
+        global_nspace.first = var; 
+    var->next = NULL; //just to be safe
+    global_nspace.count++;
+    return 0;
+}
+
+static var_t *getvar(char *name) {
+    var_t *cur = NULL;
+    if (global_nspace.count <= 0 || !global_nspace.first)
+        return NULL;
+
+    cur = global_nspace.first;
+    while (cur) {
+        if (cgc_streq(cur->name, name))
+            return cur;
+        cur = cur->next;
+    }
+    return NULL;
+}
+
+static uint32_t cgc_calc_bytesize(char *varlist) {
+    char *varname = NULL;
+    char *varlistcpy = NULL;
+    char *varlistcpy_strtok = NULL;
+    var_t *var = NULL;
+    uint32_t val = 0;
+
+    if (!(varlistcpy = calloc_Pvz(strlen(varlist)+1)))
+        return 0;
+
+    strcpy(varlistcpy,varlist);
+    varlistcpy_strtok = varlistcpy;
+
+    //we allow this to overflow, but result is checked for size elsewhere
+    while ((varname = strtok_PcPcc(varlistcpy_strtok,','))) {
+        varlistcpy_strtok = NULL; //for strtok
+        if (strlen(varname) == 0)
+            break;
+        if (!(var = getvar(varname))) {
+            val = 0;
+            break;
+        }
+        if (var->type != NUMTYPE) {
+            val = 0;
+            break;
+        }
+        val += ((numvar_t*)var)->num;
+    }
+    free(varlistcpy);
+    return val;
+}
+
+static int cgc_newnum(char *name, char *arg) {
+    numvar_t *n = NULL;
+    int res = 0;
+
+    if (!(n = calloc_Pvz(sizeof(numvar_t))))
+        return ERRNOMEM;
+
+    n->num = str2int_dPc(arg);
+
+    res = addvar((var_t*)n, name, NUMTYPE);
+
+    if(res)
+        free(n);
+
+    return res;
+}
+
+static int cgc_newarr(char *name, char *arg) {
+    arrvar_t *a = NULL; 
+    int res = 0;
+
+    uint32_t size = str2uint_ud32Pc(arg);
+
+    if (size > MAXARRSIZE)
+        return ERRTOOBIG;
+
+    if (!(a = calloc_Pvz(sizeof(arrvar_t)+(size*sizeof(int)))))
+        return ERRNOMEM;
+
+    a->size = size*sizeof(int);
+
+    res = addvar((var_t*)a, name, ARRTYPE);
+
+    if (res)
+        free(a);
+
+    return res;
+}
+
+static int cgc_newview(char *name, char *arg) {
+    viewvar_t *v = NULL;
+    arrvar_t *a = NULL;
+    int i = 0;
+    int res = 0;
+
+    char *type = strtok_PcPcc(NULL,' ');
+
+    if (!type || strlen(type) == 0)
+        return ERRNOTYPE;
+
+    if (!(a = (arrvar_t*)getvar(arg))) 
+        return ERRNOSUCHVAR;
+
+    if (a->v.type != ARRTYPE) 
+        return ERRWRONGTYPE;
+
+    if (!(v = calloc_Pvz(sizeof(viewvar_t))))
+        return ERRNOMEM;
+
+    for (i=0; i < sizeof(viewtypes)/sizeof(viewtype_t); i++) {
+        if (cgc_streq(type,viewtypes[i].name)) {
+            v->view = &viewtypes[i];
+            break;
+        }
+    }
+
+    if (!v->view) {
+        free(v);
+        return ERRNOSUCHTYPE;
+    }
+
+    v->arr = a;
+
+    res = addvar((var_t*)v, name, VIEWTYPE);
+
+    if (res)
+        free(v);
+
+    return res;
+}
+
+static int cgc_handlenew() {
+    char *type = NULL;
+    char *name = NULL;
+    char *arg = NULL;
+    int i = 0;
+
+    type = strtok_PcPcc(NULL,' ');
+
+    if (!type || strlen(type) == 0)
+        return ERRNOTYPE;
+
+    name = strtok_PcPcc(NULL,' ');
+
+    if (!name)
+        return ERRNONAME;
+
+    if (getvar(name))
+        return ERRALREADYEXISTS;
+
+    arg = strtok_PcPcc(NULL, ' ');
+
+    if (!arg || strlen(arg) == 0)
+        return ERRNOARG;
+
+    for (i = 0; i < sizeof(types)/sizeof(types[0]); i+=1) {
+        if (cgc_streq(type,types[i]))
+            return constructors[i](name,arg);
+    }
+
+    return ERRNOSUCHTYPE;
+
+}
+
+static int cgc_handleget() {
+    var_t *var = NULL;
+    viewvar_t *view = NULL;
+    char out[12] = {0};
+    char *name = strtok_PcPcc(NULL, ' ');
+    char *arg = NULL;
+    char *subarg = NULL;
+    uint32_t val = 0;
+    uint32_t mask = 0;
+    int idx = 0;
+    int i = 0;
+
+    if (!name || strlen(name) == 0)
+        return ERRNONAME;
+
+    if (!(var = getvar(name)))
+        return ERRNOSUCHVAR;
+
+    switch (var->type) {
+        case NUMTYPE:
+            int2str_dPcdd(out, sizeof(out), ((numvar_t*)var)->num);
+            break;
+
+        case ARRTYPE:
+            if (!(arg = strtok_PcPcc(NULL, ' ')))
+                return ERRNOARG;
+            
+            idx = str2uint_ud32Pc(arg);
+
+            if (idx >= ((arrvar_t*)var)->size/sizeof(int))
+                return ERRINVALIDIDX;
+
+            int2str_dPcdd(out, sizeof(out), ((int*)((arrvar_t*)var)->arr)[idx]);
+            break;
+
+        case VIEWTYPE:
+            view = (viewvar_t*)var;
+
+            if (!(arg = strtok_PcPcc(NULL, ' ')))
+                return ERRNOARG;
+            
+            idx = str2uint_ud32Pc(arg)*view->view->size;
+
+            if (view->bytesize) {
+                #ifndef PATCHED
+                if (!(idx+view->view->size < cgc_calc_bytesize(view->bytesize)))
+                #else
+                if (!(idx+view->view->size < cgc_calc_bytesize(view->bytesize) && cgc_calc_bytesize(view->bytesize) < view->arr->size))
+                #endif
+                    return ERRINVALIDIDX;
+            } else if (idx+view->view->size > view->arr->size) {
+                return ERRINVALIDIDX;
+            }
+
+            for(i=0; i < view->view->size; i++) 
+                val |=  view->arr->arr[i+idx] << (i*8);
+
+            if (view->view->sign) {
+                if (view->view->size == sizeof(int))
+                    int2str_dPcdd(out, sizeof(out), val);
+                else if (view->view->size == sizeof(short))
+                    int2str_dPcdd(out, sizeof(out), (short)val);
+                else if (view->view->size == sizeof(char))
+                    int2str_dPcdd(out, sizeof(out), (char)val);
+            } else {
+                uint2str_dPcdud32(out, sizeof(out), val);
+            }
+
+            break;
+        default:
+            return ERRNOSUCHTYPE;
+    }
+
+    SSENDL(strlen(out),out);
+    return 0;
+}
+
+static int cgc_handleset() {
+    var_t *var = NULL;
+    char *name = strtok_PcPcc(NULL, ' ');
+    char *arg = NULL, *arg2 = NULL, *varlist = NULL;
+    uint32_t idx = 0;
+    uint32_t val = 0;
+
+    if (!name || strlen(name) == 0)
+        return ERRNONAME;
+
+    if (!(var = getvar(name)))
+        return ERRNOSUCHVAR;
+
+    if (!(arg = strtok_PcPcc(NULL, ' ')))
+        return ERRNOARG;
+
+    switch (var->type) {
+        case NUMTYPE:
+            ((numvar_t*)var)->num = str2int_dPc(arg);
+            return 0;
+        case ARRTYPE:
+            idx = str2int_dPc(arg);
+
+            if (idx >= ((arrvar_t*)var)->size/sizeof(int))
+                return ERRINVALIDIDX;
+
+            if (!(arg = strtok_PcPcc(NULL, ' ')))
+                return ERRNOARG;
+
+            ((int*)&((arrvar_t*)var)->arr)[idx] = str2int_dPc(arg);
+
+            return 0;
+        case VIEWTYPE:
+            if (!(arg2 = strtok_PcPcc(NULL, ' ')))
+                return ERRNOARG;
+
+            if (!(varlist = calloc_Pvz(strlen(arg2)+1)))
+                return ERRNOMEM;
+
+            strcpy(varlist,arg2);
+
+            if (!cgc_streq(arg,"byteSize")) {
+                free(varlist);
+                return ERRNOSUCHVAR;
+            }
+
+            val = cgc_calc_bytesize(arg2);
+
+            if (!(var = getvar(name))) {
+                free(varlist);
+                return ERRNOSUCHVAR;
+            }
+
+            if (val > ((viewvar_t*)var)->arr->size) {
+                free(varlist);
+                return ERRTOOBIG;
+            }
+
+            if (((viewvar_t*)var)->bytesize)
+                free(((viewvar_t*)var)->bytesize);
+
+            ((viewvar_t*)var)->bytesize = varlist;
+
+            return 0;
+
+        default:
+            return ERRNOSUCHTYPE;
+    }
+}
+
+static int cgc_handledel() {
+    char *name = strtok_PcPcc(NULL,' ');
+
+    if (!name || strlen(name)==0)
+        return ERRNONAME;
+
+    return delvar(name);
+}
+
+static int runcmd(char *cmd) {
+    int i;
+
+    cmd = strtok_PcPcc(cmd,' ');
+
+    if (!cmd || strlen(cmd) == 0)
+        return ERRSHORT;
+
+    for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); i+=1) {
+        if (cgc_streq(cmd,cmds[i]))
+            return handlers[i]();
+    }
+
+    return ERRNOSUCHCMD;
+}
+
+int cgc_run_viewscript(char *script) {
+
+    char *cur = script;
+    char **lines;
+    int res = 0;
+    int idx = 0;
+    int count = 0;
+    //this is properly null-terminated by main()
+    int len = strlen(script);
+
+    if (len > MAXSCRIPTSIZE)
+        return ERRTOOBIG;
+
+    while(*cur) {
+        if (*cur == '\n')
+            count++;
+        cur++;
+    }
+
+    if (count == 0)
+        return ERRSHORT;
+
+    if (!(lines = calloc_Pvz((count+1)*sizeof(char *))))
+        return ERRNOMEM;
+
+    lines[0] = strtok_PcPcc(script,'\n');
+    #ifdef PATCHED
+    while (idx < count && (lines[++idx] = strtok_PcPcc(NULL,'\n')));
+    #else 
+    while ((lines[++idx] = strtok_PcPcc(NULL,'\n')));
+    #endif
+    for (idx = 0; idx < count; idx++) {
+        if ((res = runcmd(lines[idx])))
+            return res;
+    }
+
+    free(lines);
+
+    LOG("Done.");
+
+    return 0;
+}
diff --git a/cgc-challenges/lib/common.c b/cgc-challenges/lib/common.c
index 6e945c075..3da10035d 100644
--- a/cgc-challenges/lib/common.c
+++ b/cgc-challenges/lib/common.c
@@ -54,3 +54,149 @@ char *strsep(char **stringp, const char *delim)
 
   return (char *) delim;
 }
+
+void *calloc_Pvz(size_t size)
+{
+	return calloc(1, size);
+}
+
+char *strtok_PcPcc(char *s, char sep)
+{
+char tok[2] = {0};
+
+tok[0] = sep;
+return (strtok(s, tok));
+}
+
+int str2int_dPc(const char* str_buf) {
+    int result = 0;
+    int max_chars = 10; // max number of chars cgc_read from str_buf
+    int i = 0;
+    int sign = 0;
+
+    if (str_buf == NULL)
+        return result;
+
+    if (str_buf[0] == '-') {
+        sign = -1;
+        i++;
+        max_chars++;
+    }
+
+    for (; i < max_chars; i++) {
+        if ( str_buf[i] >= '0' && str_buf[i] <= '9') {
+            result *= 10;
+            result += str_buf[i] - '0';
+
+        } else {
+            break;
+        }
+    }
+
+    if (sign == -1)
+        result = -result;
+
+    return result;
+}
+
+uint32_t str2uint_ud32Pc(const char* str_buf) {
+    int result = 0;
+    int max_chars = 10; // max number of chars cgc_read from str_buf
+    int i = 0;
+
+    if (str_buf == NULL)
+        return result;
+
+    for (; i < max_chars; i++) {
+        if ( str_buf[i] >= '0' && str_buf[i] <= '9') {
+            result *= 10;
+            result += str_buf[i] - '0';
+
+        } else {
+            break;
+        }
+    }
+
+    return result;
+}
+
+int int2str_dPcdd(char* str_buf, int buf_size, int i) {
+
+    int idx = 0;
+    int tmp = 0;
+    int digit = 0;
+
+    // at least fits 1 digit and '\0'
+    if (buf_size < 2) {
+        return -1;
+    }
+
+    if (i < 0) {
+        if (buf_size < 3)
+            return -1;
+        str_buf[idx++] = '-';
+    } else {
+        i *= -1; // make i negative
+    }
+
+    // i is always 0 or negative at this point.
+    tmp = i;
+
+    // increment index in str_buf to where rightmost digit goes
+    do {
+        idx++;
+        tmp = tmp/10;
+    } while (tmp < 0);
+
+    // see if this number will fit in the buffer
+    if (idx >= buf_size)
+        return -1;
+
+    // insert '\0'
+    str_buf[idx--] = '\0';
+
+    // move left through string, writing digits along the way
+    do {
+        digit = -1 * (i % 10);
+        str_buf[idx--] = '0' + digit;
+        i /= 10;
+    } while (i < 0);
+
+    return 0;
+}
+
+int uint2str_dPcdud32(char* str_buf, int buf_size, uint32_t i) {
+
+    int idx = 0;
+    uint32_t tmp = 0;
+    int digit = 0;
+
+    // at least fits 1 digit and '\0'
+    if (buf_size < 2) {
+        return -1;
+    }
+
+    tmp = i;
+
+    // increment index in str_buf to where rightmost digit goes
+    do {
+        idx++;
+        tmp = tmp/10;
+    } while (tmp > 0);
+
+    // see if this number will fit in the buffer
+    if (idx >= buf_size)
+        return -1;
+
+    // insert '\0'
+    str_buf[idx--] = '\0';
+
+    // move left through string, writing digits along the way
+    do {
+        digit = i % 10;
+        str_buf[idx--] = '0' + digit;
+        i /= 10;
+    } while (i > 0);
+
+    return 0;
+}
diff --git a/cgc-challenges/lib/common.h b/cgc-challenges/lib/common.h
index a773f062e..6d9670e37 100644
--- a/cgc-challenges/lib/common.h
+++ b/cgc-challenges/lib/common.h
@@ -8,6 +8,7 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
@@ -21,6 +22,8 @@
 
 int receive_bytes_iPcz (char *buffer, size_t count);
 
+#define SSENDL(s,b) if(cgc_sendline(STDOUT,b,s)<0) cgc__terminate(6);
+#define LOG(b) SSENDL(sizeof(b)-1,b);
 int __prng_state;
 
 /*@ assigns __prng_state \from seedValue; */
@@ -29,6 +32,17 @@ void seed_prng( uint32_t seedValue );
 /*@ assigns \result, __prng_state \from __prng_state; */
 uint32_t cgc_prng( void );
 
+void *calloc_Pvz(size_t size);
+
 char *strsep(char **stringp, const char *delim);
 
+char *strtok_PcPcc(char *s, char sep);
+
+int str2int_dPc(const char* str_buf);
+
+uint32_t str2uint_ud32Pc(const char* str_buf);
+
+int int2str_dPcdd(char* str_buf, int buf_size, int i);
+
+int uint2str_dPcdud32(char* str_buf, int buf_size, uint32_t i);
 #endif
diff --git a/cgc-challenges/lib/fc_stubs.h b/cgc-challenges/lib/fc_stubs.h
index 154f342e5..90da23f5a 100644
--- a/cgc-challenges/lib/fc_stubs.h
+++ b/cgc-challenges/lib/fc_stubs.h
@@ -1,4 +1,22 @@
 #include <math.h>
+#include <stdlib.h> 
 
 /*@ assigns \result \from x, y; */
 extern double remainder(double x, double y);
+
+/*@
+  requires \valid(buf+(0..size-1));
+  assigns buf[0..size-1] \from indirect:fd, indirect:term, indirect:size;
+  assigns \result \from indirect:fd, indirect:term, indirect:size;
+ */
+int cgc_recvuntil(int fd, char *buf, size_t size, char term);
+
+/*@
+  requires valid_s1: valid_read_string(s1);
+  requires valid_s2: valid_read_string(s2);
+  assigns \result \from indirect:s1, indirect:s2, indirect: s1[0..], indirect: s2[0..];
+  ensures result_equal_or_diff: \result==0 || \result==1;
+  */
+int cgc_streq(char *s1, char *s2);
+
+
diff --git a/cgc-challenges/lib/libcgc.c b/cgc-challenges/lib/libcgc.c
index abd304ab3..635c0a1b6 100644
--- a/cgc-challenges/lib/libcgc.c
+++ b/cgc-challenges/lib/libcgc.c
@@ -224,6 +224,42 @@ int cgc_random(void *buf, size_t count, size_t *rnd_bytes) {
     return 0;
 }
 
+int cgc_sendall(int fd, const char *buf, size_t size) {
+    size_t sent = 0;
+    size_t total = 0;
+
+    if (!buf)
+        return -1;
+
+    if (!size)
+        return 0;
+
+    while (size) {
+        if (cgc_transmit(fd, buf, size, &sent)) {
+            return -1;
+        }
+
+        buf += sent;
+        total += sent;
+        size -= sent;
+    }
+
+    return total;
+}
+
+int cgc_sendline(int fd, const char *buf, size_t size) {
+    int ret;
+    ret = cgc_sendall(fd, buf, size);
+    if (ret < 0) {
+        return ret;
+    } else {
+        if (cgc_transmit(fd, "\n", 1, &size))
+            return -1;
+        else
+            return ++ret;
+    }
+}
+
 // Frama-C/Eva cannot handle mmap(); implicitly handled by -absolute-valid-range
 /*@
   assigns \nothing;
diff --git a/cgc-challenges/lib/libcgc.h b/cgc-challenges/lib/libcgc.h
index 19acd0405..e83e226d4 100644
--- a/cgc-challenges/lib/libcgc.h
+++ b/cgc-challenges/lib/libcgc.h
@@ -49,6 +49,8 @@ int cgc_fdwait(int nfds, fd_set *readfds, fd_set *writefds,
 int cgc_allocate(size_t length, int is_X, void **addr);
 int cgc_deallocate(void *addr, size_t length);
 int cgc_random(void *buf, size_t count, size_t *rnd_bytes);
+int cgc_sendline(int fd, const char *buf, size_t size);
+int cgc_sendall(int fd, const char *buf, size_t size);
 
 // All of the following functions are defined in asm (maths.S/maths_win.asm)
 
-- 
GitLab