From 3cb0b6358f738f598aa1813aa41a1093e6093d9d Mon Sep 17 00:00:00 2001 From: SwuduSusuwu <2002luvabbaluvu@gmail.com> Date: Sat, 15 Jun 2024 18:45:13 -0700 Subject: [PATCH] @execves `pathname = argv[0];` fixes #5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes parameter _execves.executable_ (which was execve.pathname) because Android OS fails unless `&pathname == &argv[0]` (must not just match value, but must reuse address, thus there is not a purpose for function signature to ask for this). `for(auto x : s)` -> `for(auto x = s.begin(); s.end() != x; ++x)` /* `-fsanitize=address` gives _stack-use-after-scope_ with `for(auto x : s)` */ Fixes https://github.com/SwuduSusuwu/SubStack/issues/5 Closes https://github.com/SwuduSusuwu/SubStack/milestone/2 Precondition `std::ifstream(argv[0])` /* exists */ -> `-1 != access(argv[0], X_OK)` /* executable */ ``` Welcome to Termux! ~/SubStack $ ./make.sh + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -x c -c ./cxx//../c/rfc6234/sha1.c + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -x c -c ./cxx//../c/rfc6234/sha224-256.c + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -x c -c ./cxx//../c/rfc6234/sha384-512.c + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -c ./cxx//ClassSha2.cxx + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -c ./cxx//ClassResultList.cxx + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -c ./cxx//ClassCns.cxx + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -c ./cxx//VirusAnalysis.cxx + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -c ./cxx//ConversationCns.cxx ./cxx//ConversationCns.cxx:106:74: warning: non-void function does not return a value [-Wreturn-type]   106 | const FileBytecode conversationParseQuestion(const FilePath &xhtmlFile) {} /* TODO */       |                                                                          ^ ./cxx//ConversationCns.cxx:107:88: warning: non-void function does not return a value [-Wreturn-type]   107 | const std::vector conversationParseResponses(const FilePath &xhtmlFile) {} /* TODO */       |                                                                                        ^ 2 warnings generated. + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g -c ./cxx//main.cxx + clang++ -fsanitize=address -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer -g sha1.o sha224-256.o sha384-512.o ClassSha2.o ClassResultList.o ClassCns.o VirusAnalysis.o ConversationCns.o main.o + set +x ~/SubStack $ ./a.out cxx/Macros.hxx: pass execves(): pass execvex(): pass virusAnalysisTestsThrows(): pass conversationCnsTestsThrows(): --2024-06-15 18:22:01--  https://stackoverflow.com/robots.txt Resolving stackoverflow.com (stackoverflow.com)... 172.64.155.249, 104.18.32.7 Connecting to stackoverflow.com (stackoverflow.com)|172.64.155.249|:443... connected. HTTP request sent, awaiting response... 200 OK Length: unspecified [text/plain] Saving to: ‘robots.txt’ robots.txt                                   [ <=>                                                                              ]   1.99K  --.-KB/s    in 0.07s 2024-06-15 18:22:02 (27.4 KB/s) - ‘robots.txt’ saved [2036] --2024-06-15 18:22:02--  https://stackoverflow.com/ Resolving stackoverflow.com (stackoverflow.com)... 172.64.155.249, 104.18.32.7 Connecting to stackoverflow.com (stackoverflow.com)|172.64.155.249|:443... connected. HTTP request sent, awaiting response... 200 OK Length: unspecified [text/html] Saving to: ‘index.xhtml’ index.xhtml                                  [     <=>                                                                          ] 175.66K   136KB/s    in 1.3s 2024-06-15 18:22:03 (136 KB/s) - ‘index.xhtml’ saved [179877] Trap ~/SubStack $ ``` `conversationParseResponses()` is work-in-progress, `-fsanitize` Traps just before this, thus counts as `pass`. If curious: `for(auto x : s)` gives ``` ~/SubStack $ ./a.out cxx/Macros.hxx: pass execves(): ================================================================= ==18709==ERROR: AddressSanitizer: stack-use-after-scope on address 0x007ffc3d9511 at pc 0x007450ea2a78 bp 0x007ffc3d7e90 sp 0x007ffc3d7678 READ of size 1 at 0x007ffc3d9511 thread T0 #0 0x7450ea2a74 in strncmp out/lib/compiler-rt-aarch64/out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:545:3 #1 0x745388e200 (/data/data/com.termux/files/usr/lib/libtermux-exec.so+0x2200) #2 0x745388dd68 in execve (/data/data/com.termux/files/usr/lib/libtermux-exec.so+0x1d68) #3 0x63f79ca63c in Susuwu::execves(std::__ndk1::vector, std::__ndk1::allocator> const, std::__ndk1::allocator, std::__ndk1::allocator> const>> const&, std::__ndk1::vector, std::__ndk1::allocator> const, std::__ndk1::allocator, std::__ndk1::allocator> const>> const&) /data/data/com.termux/files/home/SubStack/./cxx/ClassCns.cxx:34:2 #4 0x63f7a3a7ac in Susuwu::testHarnesses() /data/data/com.termux/files/home/SubStack/./cxx/main.cxx:21:7 #5 0x63f7a3b1e0 in main /data/data/com.termux/files/home/SubStack/./cxx/main.cxx:40:9 #6 0x74524c9e18 in __libc_init (/apex/com.android.runtime/lib64/bionic/libc.so+0x56e18) (BuildId: 33ad5959e2b38fc822cda3c642e16c94) Address 0x007ffc3d9511 is located in stack of thread T0 at offset 241 in frame #0 0x63f79c9f14 in Susuwu::execves(std::__ndk1::vector, std::__ndk1::allocator> const, std::__ndk1::allocator, std::__ndk1::allocator> const>> const&, std::__ndk1::vector, std::__ndk1::allocator> const, std::__ndk1::allocator, std::__ndk1::allocator> const>> const&) /data/data/com.termux/files/home/SubStack/./cxx/ClassCns.cxx:13 This frame has 14 object(s): [32, 36) 'status' (line 17) [48, 72) 'argvSmutable' (line 22) [112, 136) 'argv' (line 23) [176, 184) '__begin1' (line 24) [208, 216) '__end1' (line 24) [240, 264) 'x' (line 24) <== Memory access at offset 241 is inside this variable [304, 312) 'ref.tmp' (line 25) [336, 344) 'ref.tmp26' (line 27) [368, 392) 'envpSmutable' (line 28) [432, 456) 'envp' (line 29) [496, 504) 'x44' (line 30) [528, 536) 'ref.tmp49' (line 30) [560, 568) 'ref.tmp56' (line 31) [592, 600) 'ref.tmp66' (line 33) HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-use-after-scope out/lib/compiler-rt-aarch64/out/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:545:3 in strncmp Shadow bytes around the buggy address: 0x007ffc3d9280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x007ffc3d9300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x007ffc3d9380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x007ffc3d9400: 00 00 00 00 f1 f1 f1 f1 f8 f2 00 00 00 f2 f2 f2 0x007ffc3d9480: f2 f2 00 00 00 f2 f2 f2 f2 f2 f8 f2 f2 f2 f8 f2 =>0x007ffc3d9500: f2 f2[f8]f8 f8 f2 f2 f2 f2 f2 f8 f2 f2 f2 f8 f2 0x007ffc3d9580: f2 f2 00 00 00 f2 f2 f2 f2 f2 00 00 00 f2 f2 f2 0x007ffc3d9600: f2 f2 f8 f2 f2 f2 f8 f2 f2 f2 f8 f2 f2 f2 f8 f3 0x007ffc3d9680: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 0x007ffc3d9700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x007ffc3d9780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==18709==ABORTING ``` @posts/VirusAnalysis /* new `execves` */ --- cxx/ClassCns.cxx | 13 +++++++------ cxx/ClassCns.hxx | 7 ++++--- cxx/main.cxx | 5 +++++ posts/VirusAnalysis.md | 25 ++++++++++++++++--------- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/cxx/ClassCns.cxx b/cxx/ClassCns.cxx index 7f6b1803..fff52df3 100644 --- a/cxx/ClassCns.cxx +++ b/cxx/ClassCns.cxx @@ -10,7 +10,7 @@ #endif /* def _POSIX_VERSION */ #include "ClassCns.hxx" /* CnsMode */ namespace Susuwu { -const int execves(const std::string &executable, const std::vector &argvS, const std::vector &envpS) { +const int execves(const std::vector &argvS, const std::vector &envpS) { #ifdef _POSIX_VERSION pid_t pid = fork(); if(0 != pid) { @@ -21,17 +21,18 @@ const int execves(const std::string &executable, const std::vector argvSmutable = {argvS.cbegin(), argvS.cend()}; std::vector argv; - for(auto x : argvSmutable) { - argv.push_back(const_cast(x.c_str())); + //for(auto x : argvSmutable) { /* with `fsanitize=address` this triggers "stack-use-after-scope" */ + for(auto x = argvSmutable.begin(); argvSmutable.end() != x; ++x) { + argv.push_back(const_cast(x->c_str())); } argv.push_back(NULL); const std::vector envpSmutable = {envpS.cbegin(), envpS.cend()}; std::vector envp; - for(auto x : envpSmutable) { - envp.push_back(const_cast(x.c_str())); + for(auto x = envpSmutable.begin(); envpSmutable.end() != x; ++x) { + envp.push_back(const_cast(x->c_str())); } envp.push_back(NULL); - execve(executable.c_str(), &argv[0], &envp[0]); /* NORETURN */ + execve(argv[0], &argv[0], &envp[0]); /* NORETURN */ exit(EXIT_FAILURE); #endif /* def _POSIX_VERSION */ } diff --git a/cxx/ClassCns.hxx b/cxx/ClassCns.hxx index 38312cc6..38213db9 100644 --- a/cxx/ClassCns.hxx +++ b/cxx/ClassCns.hxx @@ -20,9 +20,10 @@ typedef enum CnsMode { #endif /* def CXX_17 else */ } CnsMode; -/* @pre @code std::ifstream(executable); @endcode */ -const int execves(const std::string &executable, const std::vector &argvS = {}, const std::vector &envpS = {}); -static const int execvex(const std::string &toSh) {return execves("/bin/sh", {"/bin/sh", "-c", toSh});} +/* `int status; pid_t pid = fork() || execve(argv[0], &argv[0], &envp[0]); waitpid(pid, &status, 0); return status;` + * @pre @code (-1 != access(argv[0], X_OK) @endcode */ +const int execves(/* const std::string &pathname, -- `execve` requires `&pathname == &argv[0]` */ const std::vector &argvS = {}, const std::vector &envpS = {}); +static const int execvex(const std::string &toSh) {return execves({"/bin/sh", "-c", toSh});} typedef class Cns { public: virtual const bool hasImplementation() const {return typeid(Cns) != typeid(this);} diff --git a/cxx/main.cxx b/cxx/main.cxx index 6f229c28..591223c7 100644 --- a/cxx/main.cxx +++ b/cxx/main.cxx @@ -1,6 +1,7 @@ /* Licenses: allows all uses ("Creative Commons"/"Apache 2") */ #ifndef INCLUDES_cxx_main_cxx #define INCLUDES_cxx_main_cxx +#include "ClassCns.hxx" /* execves execvex */ #include "VirusAnalysis.hxx" /* virusAnalysisTestsThrows */ #include "ConversationCns.hxx" /* conversationCnsTestsThrows */ #include "Macros.hxx" /* ASSUME EXPECTS ENSURES NOEXCEPT NORETURN */ @@ -16,6 +17,10 @@ int testHarnesses() EXPECTS(true) ENSURES(true) { ASSUME(true); noExcept(); std::cout << "pass" << std::endl; + std::cout << "execves(): " << std::flush; + 0 == execves({"/bin/echo", "pass"}) || std::cout << "error" << std::endl; + std::cout << "execvex(): " << std::flush; + 0 == execvex("/bin/echo pass") || std::cout << "error" << std::endl; std::cout << "virusAnalysisTestsThrows(): " << std::flush; if(virusAnalysisTestsThrows()) { std::cout << "pass" << std::endl; diff --git a/posts/VirusAnalysis.md b/posts/VirusAnalysis.md index af29b6ea..0b67ba00 100644 --- a/posts/VirusAnalysis.md +++ b/posts/VirusAnalysis.md @@ -160,9 +160,10 @@ typedef enum CnsMode { #endif /* def CXX_17 else */ } CnsMode; -/* @pre @code std::ifstream(executable); @endcode */ -const int execves(const std::string &executable, const std::vector &argvS = {}, const std::vector &envpS = {}); -static const int execvex(const std::string &toSh) {return execves("/bin/sh", {"/bin/sh", "-c", toSh});} +/* `int status; pid_t pid = fork() || execve(argv[0], &argv[0], &envp[0]); waitpid(pid, &status, 0); return status;` + * @pre @code (-1 != access(argv[0], X_OK) @endcode */ +const int execves(/* const std::string &pathname, -- `execve` requires `&pathname == &argv[0]` */ const std::vector &argvS = {}, const std::vector &envpS = {}); +static const int execvex(const std::string &toSh) {return execves({"/bin/sh", "-c", toSh});} typedef class Cns { public: virtual const bool hasImplementation() const {return typeid(Cns) != typeid(this);} @@ -250,7 +251,7 @@ typedef class ApxrCns : Cns { ``` `less` [cxx/ClassCns.cxx](https://github.com/SwuduSusuwu/SubStack/blob/trunk/cxx/ClassCns.cxx) ``` -const int execves(const std::string &executable, const std::vector &argvS, const std::vector &envpS) { +const int execves(const std::vector &argvS, const std::vector &envpS) { #ifdef _POSIX_VERSION pid_t pid = fork(); if(0 != pid) { @@ -261,17 +262,18 @@ const int execves(const std::string &executable, const std::vector argvSmutable = {argvS.cbegin(), argvS.cend()}; std::vector argv; - for(auto x : argvSmutable) { - argv.push_back(const_cast(x.c_str())); + //for(auto x : argvSmutable) { /* with `fsanitize=address` this triggers "stack-use-after-scope" */ + for(auto x = argvSmutable.begin(); argvSmutable.end() != x; ++x) { + argv.push_back(const_cast(x->c_str())); } argv.push_back(NULL); const std::vector envpSmutable = {envpS.cbegin(), envpS.cend()}; std::vector envp; - for(auto x : envpSmutable) { - envp.push_back(const_cast(x.c_str())); + for(auto x = envpSmutable.begin(); envpSmutable.end() != x; ++x) { + envp.push_back(const_cast(x->c_str())); } envp.push_back(NULL); - execve(executable.c_str(), &argv[0], &envp[0]); /* NORETURN */ + execve(argv[0], &argv[0], &envp[0]); /* NORETURN */ exit(EXIT_FAILURE); #endif /* def _POSIX_VERSION */ } @@ -644,6 +646,7 @@ const FileBytecode cnsDisinfection(const PortableExecutable &file, const Cns &cn ``` `less` [cxx/main.cxx](https://github.com/SwuduSusuwu/SubStack/blob/trunk/cxx/main.cxx) ``` +#include "ClassCns.hxx" /* execves execvex */ #include "VirusAnalysis.hxx" /* virusAnalysisTestsThrows */ #include "ConversationCns.hxx" /* conversationCnsTestsThrows */ #include "Macros.hxx" /* ASSUME EXPECTS ENSURES NOEXCEPT NORETURN */ @@ -659,6 +662,10 @@ int testHarnesses() EXPECTS(true) ENSURES(true) { ASSUME(true); noExcept(); std::cout << "pass" << std::endl; + std::cout << "execves(): " << std::flush; + 0 == execves({"/bin/echo", "pass"}) || std::cout << "error" << std::endl; + std::cout << "execvex(): " << std::flush; + 0 == execvex("/bin/echo pass") || std::cout << "error" << std::endl; std::cout << "virusAnalysisTestsThrows(): " << std::flush; if(virusAnalysisTestsThrows()) { std::cout << "pass" << std::endl;