/** * @brief Performs semantic analysis of root object - tells if given JSON * is valid Docker image confuguration: * https://github.com/docker/docker/blob/master/image/spec/v1.md#image-json-description * @param val_ JSON document * @return is valid Docker image spec? */ bool is_valid_root_object (std::shared_ptr<json_value> val_) { bool ret = true; /* * id -> J_STRING, is_hexadecimal_256bits() * created -> J_STRING, is_iso8601_datetime() * os -> J_STRING, is_os() * parent -> J_STRING, is_hexadecimal_256bits() * Size -> J_INT * architecture -> J_STRING, is_architecture() * author -> J_STRING * checksum -> J_STRING * config -> J_OBJECT / J_NULL, is_valid_config() */ if (val_->jtype() != json_type::J_OBJECT) { return false; } auto object = std::static_pointer_cast< json_object >(val_); // type std::shared_ptr< json_object > // validate id auto id = object->find("\"id\""); // id is of type std::shared_ptr< json_value > if (id != nullptr) { if (id->jtype() != json_type::J_STRING) { std::cerr << "id isn't string" << std::endl; ret = false; } else { if (!is_hexadecimal_256bits(id->to_string())) { std::cerr << "id isn't valid hexadecimal string" << std::endl; ret = false; } } } else { std::cerr << "id doesn't exist" << std::endl; ret = false; } // validate created auto created = object->find("\"created\""); if (created != nullptr) { if (created->jtype() != json_type::J_STRING) { std::cerr << "created isn't string" << std::endl; ret = false; } else { if (!is_iso8601_datetime(created->to_string())) { std::cerr << "created isn't valid datetime string" << std::endl; ret = false; } } } // validate os auto os = object->find("\"os\""); if (os != nullptr) { if (os->jtype() != json_type::J_STRING) { std::cerr << "os isn't string" << std::endl; ret = false; } else { if (!is_os(os->to_string())) { std::cerr << "os isn't valid os string" << std::endl; ret = false; } } } // validate parent auto parent = object->find("\"parent\""); if (parent != nullptr) { if (parent->jtype() != json_type::J_STRING) { std::cerr << "parent isn't string" << std::endl; ret = false; } else { if (!is_hexadecimal_256bits(parent->to_string())) { std::cerr << "parent isn't valid hexadecimal string" << std::endl; ret = false; } } } // validate Size auto size = object->find("\"Size\""); if (size != nullptr) { if (size->jtype() != json_type::J_INT) { std::cerr << "size isn't int" << std::endl; ret = false; } else { if (std::static_pointer_cast<json_int>(size)->value() < 0) { std::cerr << "Size is negative" << std::endl; ret = false; } } } // validate architecture auto architecture = object->find("\"architecture\""); if (architecture != nullptr) { if (architecture->jtype() != json_type::J_STRING) { std::cerr << "architecture isn't string" << std::endl; ret = false; } else { if (!is_architecture(architecture->to_string())) { std::cerr << "architecture isn't valid architecture string" << std::endl; ret = false; } } } // validate author auto author = object->find("\"author\""); if (author != nullptr) { if (author->jtype() != json_type::J_STRING) { std::cerr << "author isn't string" << std::endl; ret = false; } } // validate checksum auto checksum = object->find("\"checksum\""); if (checksum != nullptr) { if (checksum->jtype() != json_type::J_STRING) { std::cerr << "checksum isn't string" << std::endl; ret = false; } } // validate config auto config = object->find("\"config\""); if (config != nullptr) { if (config->jtype() == json_type::J_NULL) { ; // can be null, is valid } else if (config->jtype() == json_type::J_OBJECT) { if (!is_valid_config(config)) { std::cerr << "config isn't valid" << std::endl; ret = false; } } else { std::cerr << "config isn't valid type" << std::endl; ret = false; } } return ret; }
int main(int argc, char *argv[]) { char *buffer = NULL; size_t bufsiz = 0; ssize_t bytes_read = 0; FILE *stream = stdin; union { cParseNumber num; double real; char str[2048]; } var; puts("AFL test harness"); read_env_config(); read_test_config(); if (!is_valid_config()) { die("test configuration is not valid"); } obj = cparse_object_with_class_name("Fuzzer"); atexit(harness_cleanup); while((bytes_read = getline(&buffer, &bufsiz, stream)) >= 0) { char key[128]; size_t len = strlen(buffer); if (len > 0) { buffer[len-1] = '\0'; } if (buffer[0] == '\0') { break; } if (sscanf(buffer, "%s = %d", key, &var.num) == 2) { cparse_object_set_number(obj, key, var.num); } else if (sscanf(buffer, "%s = %lf", key, &var.real) == 2) { cparse_object_set_real(obj, key, var.num); } else if (sscanf(buffer, "%s = %[^\n]", key, var.str) == 2) { cparse_object_set_string(obj, key, var.str); } else if (sscanf(buffer, "%s = %s", key, var.str) == 2 && !strcmp(var.str, "true")) { cparse_object_set_bool(obj, key, true); } else if (sscanf(buffer, "%s = %s", key, var.str) == 2 && !strcmp(var.str, "false")) { cparse_object_set_bool(obj, key, false); } else if (sscanf(buffer, "%s == %[^\n]", key, var.str) == 2) { if (harness_compare_string(key, var.str)) { exit(1); } } else if (sscanf(buffer, "%s != %[^\n]", key, var.str) == 2) { if (!harness_compare_string(key, var.str)) { exit(1); } } else if (sscanf(buffer, "%s == %d", key, &var.num) == 2) { if (harness_compare_number(key, var.num)) { exit(1); } } else if (sscanf(buffer, "%s != %d", key, &var.num) == 2) { if (!harness_compare_number(key, var.num)) { exit(1); } } else if (sscanf(buffer, "%s == %lf", key, &var.real) == 2) { if (harness_compare_real(key, var.real, MAX_REL_ERR)) { exit(1); } } else if (sscanf(buffer, "%s != %lf", key, &var.real) == 2) { if (!harness_compare_real(key, var.real, MAX_REL_ERR)) { exit(1); } } else if ((sscanf(buffer, "%s == %s", key, var.str) == 2 && !strcmp(var.str, "true")) || (sscanf(buffer, "%s != %s", key, var.str) == 2 && !strcmp(var.str, "false"))) { if (harness_compare_bool(key, true)) { exit(1); } } else if ((sscanf(buffer, "%s == %s", key, var.str) == 2 && !strcmp(var.str, "false")) || (sscanf(buffer, "%s != %s", key, var.str) == 2 && !strcmp(var.str, "true"))) { if (harness_compare_bool(key, false)) { exit(1); } } else if (sscanf(buffer, "rem %s", key) == 1) { if (!cparse_object_contains(obj, key)) { printf("object does not contain key (%s)\n", key); } else { cparse_object_remove(obj, key); } } else if (!strcmp(buffer, "save")) { if (!cparse_object_save(obj, &error)) { puts(cparse_error_message(error)); cparse_error_free(error); error = NULL; } } else if (!strcmp(buffer, "delete")) { if (!cparse_object_delete(obj, &error)) { puts(cparse_error_message(error)); cparse_error_free(error); error = NULL; } } else if (!strcmp(buffer, "refresh")) { if (!cparse_object_refresh(obj, &error)) { puts(cparse_error_message(error)); cparse_error_free(error); error = NULL; } } else if (!strcmp(buffer, "fetch")) { if (!cparse_object_fetch(obj, &error)) { puts(cparse_error_message(error)); cparse_error_free(error); error = NULL; } } else { printf("No op (%s) in AFL harness\n", buffer); } } return 0; }