Librairie SandBox développé par Firefox. ====Théorie==== [[https://plsyssec.github.io/rlbox_sandboxing_api/sphinx/|Doc]] {{ :lib:rlbox:overview_rlbox_sandboxing_api_documentation_2020-08-08_13_38_15_.html |Archive du 31/03/202 le 08/08/2020}} [[https://github.com/PLSysSec/rlbox_sandboxing_api|Code source]] {{ :lib:rlbox:rlbox_sandboxing_api-master-2020-07-17.zip |Archive du 17/07/2020 le 08/08/2020}} [[https://arxiv.org/abs/2003.00572|Théorie]] {{ :lib:rlbox:2003.00572.pdf |Archive du 10/03/2020 le 08/08/2020}} [[https://www.usenix.org/system/files/sec20_slides_narayan.pdf|Diaporama]] {{ :lib:rlbox:sec20_slides_narayan.pdf |Archive du 22/07/2020 le 13/07/2021}} De ce que j'ai compris, cela force la réalisation d'une copie dans le tas de la donnée à transmettre à la librairie. Cela est sécuritaire car : * même si la donnée est déclarée en ''const'' dans la librairie, elle vient peut-être d'une donnée où la mémoire est accessible en écriture. * Le fait de passer la donnée directement peut permettre de déterminer l'aléa de l%%'%%''ASLR'' (Address space layout randomization) ou de déduire le pointeur vers la table virtuelle. * en cas de buffer overflow, on ne risque pas d'écrire sur la pile. * Lorsque la fonction renvoie sa valeur, il y a : * une vérification automatique de type UBSan pour vérifier que la variable qui va héberger la valeur est assez grande pour la valeur renvoyée. * Une vérification manuelle peut être ajoutée. La fonction doit alors être écrite par le développeur. ====Exemples==== ===Fonction renvoyant un char* alloué=== La libération de la mémoire du texte renvoyé est à notre charge. #define RLBOX_SINGLE_THREADED_INVOCATIONS #define RLBOX_USE_STATIC_CALLS() rlbox_noop_sandbox_lookup_symbol #include #include #include #include #include #include #include #include // Classe libérant la mémoire quand la donnée n'est plus utilisée. template class AutoFree { public: AutoFree(rlbox::tainted taint) : _taint(taint) { } ~AutoFree() { free(_taint.UNSAFE_unverified()); } rlbox::tainted& get() { return _taint; } private: rlbox::tainted _taint; }; // Fonction risquée char* unsecure_function(char* data, int nb) { char* retval = static_cast(malloc(sizeof(char) * (strlen(data) + 1))); strcpy(retval, data); return retval; } // Fonction sécurisée std::string secure_function(rlbox::rlbox_sandbox& sandbox, const std::string& unsafe_data) { size_t helloSize = unsafe_data.length() + 1; auto taintedStr = sandbox.malloc_in_sandbox(helloSize); // La librairie n'ayant pas la possibilité d'écrire, on le fait à sa place. std::strncpy( taintedStr.unverified_safe_pointer_because(helloSize, "writing only"), unsafe_data.c_str(), helloSize); // On récupère la valeur de retour de façon sécurisée. AutoFree retvalTainted( sandbox.invoke_sandbox_function(unsecure_function, taintedStr, 3)); // On récupère la valeur de retour après vérification. auto retval = retvalTainted.get().copy_and_verify_string( [](std::unique_ptr ret) -> std::optional { size_t len = strlen(ret.get()); if (simdjson::validate_utf8(ret.get(), len)) return std::optional(std::string{ret.get(), len}); else return std::nullopt; }); sandbox.free_in_sandbox(taintedStr); return retval.value_or("nullptr"); } int main() { rlbox::rlbox_sandbox sandbox; sandbox.create_sandbox(); std::cout << secure_function(sandbox, std::string{"\xc3\xb1"}) << std::endl; std::cout << secure_function(sandbox, std::string{"\xc3\x28"}) << std::endl; sandbox.destroy_sandbox(); }