From 903b5607bc0eea01aa9872a2a53221a953c7a559 Mon Sep 17 00:00:00 2001 From: Eli Kobrin Date: Wed, 16 Nov 2022 18:19:50 +0300 Subject: Fix argv-fuzz. --- utils/argv_fuzzing/argv-fuzz-inl.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index c15c0271..68a0c93d 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -34,6 +34,7 @@ #ifndef _HAVE_ARGV_FUZZ_INL #define _HAVE_ARGV_FUZZ_INL +#include #include #define AFL_INIT_ARGV() \ @@ -63,22 +64,22 @@ static char **afl_init_argv(int *argc) { char *ptr = in_buf; int rc = 0; - if (read(0, in_buf, MAX_CMDLINE_LEN - 2) < 0) {} - - while (*ptr && rc < MAX_CMDLINE_PAR) { + ssize_t num = 0; + if ((num = read(0, in_buf, MAX_CMDLINE_LEN - 2)) < 0) {} + if (in_buf[num - 1] == '\n') { + in_buf[num - 1] = 0; + } - ret[rc] = ptr; + char delim = ' '; + char *curarg = strtok(ptr, &delim); + while (curarg && rc < MAX_CMDLINE_PAR) { + ret[rc] = curarg; if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; rc++; - - while (*ptr) - ptr++; - ptr++; - + curarg = strtok(NULL, &delim); } *argc = rc; - return ret; } @@ -87,4 +88,3 @@ static char **afl_init_argv(int *argc) { #undef MAX_CMDLINE_PAR #endif /* !_HAVE_ARGV_FUZZ_INL */ - -- cgit 1.4.1 From 3d07f0ab791565feb904f5897b22ef924fc06a48 Mon Sep 17 00:00:00 2001 From: Eli Kobrin Date: Thu, 17 Nov 2022 14:14:11 +0300 Subject: Handle empty input. --- utils/argv_fuzzing/argv-fuzz-inl.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index 68a0c93d..2ec433e1 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -65,7 +65,10 @@ static char **afl_init_argv(int *argc) { int rc = 0; ssize_t num = 0; - if ((num = read(0, in_buf, MAX_CMDLINE_LEN - 2)) < 0) {} + if ((num = read(0, in_buf, MAX_CMDLINE_LEN - 2)) <= 0) { + *argc = 0; + return ret; + } if (in_buf[num - 1] == '\n') { in_buf[num - 1] = 0; } -- cgit 1.4.1 From 8f9726d4a901880808d46706cdb9024c5d08bb7e Mon Sep 17 00:00:00 2001 From: Eli Kobrin Date: Thu, 17 Nov 2022 17:27:13 +0300 Subject: Fix delim. --- utils/argv_fuzzing/argv-fuzz-inl.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index 2ec433e1..94d4c123 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -73,13 +73,12 @@ static char **afl_init_argv(int *argc) { in_buf[num - 1] = 0; } - char delim = ' '; - char *curarg = strtok(ptr, &delim); + char *curarg = strtok(ptr, " "); while (curarg && rc < MAX_CMDLINE_PAR) { ret[rc] = curarg; if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; rc++; - curarg = strtok(NULL, &delim); + curarg = strtok(NULL, " "); } *argc = rc; -- cgit 1.4.1 From ba788591dc50ba01088a9e0ed76ae29878eedbdd Mon Sep 17 00:00:00 2001 From: Eli Kobrin Date: Thu, 17 Nov 2022 17:38:45 +0300 Subject: Handle read() error. --- utils/argv_fuzzing/argv-fuzz-inl.h | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index 94d4c123..917c6222 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -34,7 +34,7 @@ #ifndef _HAVE_ARGV_FUZZ_INL #define _HAVE_ARGV_FUZZ_INL -#include +#include #include #define AFL_INIT_ARGV() \ @@ -64,24 +64,27 @@ static char **afl_init_argv(int *argc) { char *ptr = in_buf; int rc = 0; - ssize_t num = 0; - if ((num = read(0, in_buf, MAX_CMDLINE_LEN - 2)) <= 0) { - *argc = 0; - return ret; - } - if (in_buf[num - 1] == '\n') { - in_buf[num - 1] = 0; + ssize_t num = read(0, in_buf, MAX_CMDLINE_LEN - 2); + if (num < 0) { + abort(); } + in_buf[num] = '\0'; + in_buf[num + 1] = '\0'; + + while (*ptr && rc < MAX_CMDLINE_PAR) { - char *curarg = strtok(ptr, " "); - while (curarg && rc < MAX_CMDLINE_PAR) { - ret[rc] = curarg; + ret[rc] = ptr; if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; rc++; - curarg = strtok(NULL, " "); + + while (*ptr) + ptr++; + ptr++; + } *argc = rc; + return ret; } @@ -90,3 +93,4 @@ static char **afl_init_argv(int *argc) { #undef MAX_CMDLINE_PAR #endif /* !_HAVE_ARGV_FUZZ_INL */ + -- cgit 1.4.1 From d7e788a3c0138637147621cc4d6ab8087e0af956 Mon Sep 17 00:00:00 2001 From: kobrineli Date: Fri, 18 Nov 2022 13:35:51 +0300 Subject: Exit on read error. --- utils/argv_fuzzing/argv-fuzz-inl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index 917c6222..e350dd4e 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -66,7 +66,7 @@ static char **afl_init_argv(int *argc) { ssize_t num = read(0, in_buf, MAX_CMDLINE_LEN - 2); if (num < 0) { - abort(); + exit(1); } in_buf[num] = '\0'; in_buf[num + 1] = '\0'; -- cgit 1.4.1 From e26c173041b185d7ea37aa923cca3ec4aed51b1b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 13 Dec 2022 09:13:52 +0100 Subject: code format --- frida_mode/src/instrument/instrument_arm32.c | 4 ++++ utils/argv_fuzzing/argv-fuzz-inl.h | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c index 84dbb3be..51f78a35 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -276,9 +276,13 @@ gpointer instrument_cur(GumStalkerOutput *output) { gpointer curr = NULL; if (output->encoding == GUM_INSTRUCTION_SPECIAL) { + curr = gum_thumb_writer_cur(output->writer.thumb); + } else { + curr = gum_arm_writer_cur(output->writer.arm); + } return curr; diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index e350dd4e..ec22c53b 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -65,9 +65,7 @@ static char **afl_init_argv(int *argc) { int rc = 0; ssize_t num = read(0, in_buf, MAX_CMDLINE_LEN - 2); - if (num < 0) { - exit(1); - } + if (num < 1) { _exit(1); } in_buf[num] = '\0'; in_buf[num + 1] = '\0'; -- cgit 1.4.1 From 6fe38b2138ed993f3af28fc5ab92fda8f7542ef7 Mon Sep 17 00:00:00 2001 From: Maciej Domanski Date: Tue, 27 Dec 2022 15:39:47 +0100 Subject: argv fuzz persistent --- utils/argv_fuzzing/argv-fuzz-inl.h | 43 ++++++++++++++++++++++++++ utils/argv_fuzzing/argv_fuzz_demo.c | 16 ++++++++++ utils/argv_fuzzing/argv_fuzz_persistent_demo.c | 28 +++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 utils/argv_fuzzing/argv_fuzz_demo.c create mode 100644 utils/argv_fuzzing/argv_fuzz_persistent_demo.c (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index ec22c53b..d3440799 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -29,6 +29,10 @@ If you would like to always preserve argv[0], use this instead: AFL_INIT_SET0("prog_name"); + To enable persistent fuzzing, use the AFL_INIT_ARGV_PERSISTENT macro with + buf as argument, or use AFL_INIT_SET0_PERSISTENT("prog_name", buf) + to preserver argv[0]. buf should be defined as: + unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; */ #ifndef _HAVE_ARGV_FUZZ_INL @@ -53,6 +57,20 @@ \ } while (0) +#define AFL_INIT_ARGV_PERSISTENT(persistent_buff) \ + do { \ + argv = afl_init_argv_persistent(&argc, persistent_buff); \ + } while (0) + +#define AFL_INIT_SET0_PERSISTENT(_p, persistent_buff) \ + do { \ + \ + argv = afl_init_argv_persistent(&argc, persistent_buff); \ + argv[0] = (_p); \ + if (!argc) argc = 1; \ + \ + } while (0) + #define MAX_CMDLINE_LEN 100000 #define MAX_CMDLINE_PAR 50000 @@ -87,6 +105,31 @@ static char **afl_init_argv(int *argc) { } +static char **afl_init_argv_persistent(int *argc, unsigned char *persistent_buff) { + + static char *ret[MAX_CMDLINE_PAR]; + + unsigned char *ptr = persistent_buff; + int rc = 0; + + while (*ptr && rc < MAX_CMDLINE_PAR) { + + ret[rc] = (char *)ptr; + if (ret[rc][0] == 0x02 && !ret[rc][1]) ret[rc]++; + rc++; + + while (*ptr) + ptr++; + ptr++; + + } + + *argc = rc; + + return ret; + +} + #undef MAX_CMDLINE_LEN #undef MAX_CMDLINE_PAR diff --git a/utils/argv_fuzzing/argv_fuzz_demo.c b/utils/argv_fuzzing/argv_fuzz_demo.c new file mode 100644 index 00000000..f4375316 --- /dev/null +++ b/utils/argv_fuzzing/argv_fuzz_demo.c @@ -0,0 +1,16 @@ +#include +#include +#include "argv-fuzz-inl.h" + +int main(int argc, char **argv) { +AFL_INIT_ARGV(); + if (argc > 1 && strcmp(argv[1], "XYZ") == 0) { + if (strcmp(argv[2], "TEST2") == 0) { + abort(); + } + } else { + printf("Bad number of arguments!\n"); + } + + return 0; +} \ No newline at end of file diff --git a/utils/argv_fuzzing/argv_fuzz_persistent_demo.c b/utils/argv_fuzzing/argv_fuzz_persistent_demo.c new file mode 100644 index 00000000..5ecda22b --- /dev/null +++ b/utils/argv_fuzzing/argv_fuzz_persistent_demo.c @@ -0,0 +1,28 @@ +#include +#include +#include "argv-fuzz-inl.h" + +__AFL_FUZZ_INIT(); + +int main(int argc, char **argv) { +#ifdef __AFL_HAVE_MANUAL_CONTROL + __AFL_INIT(); +#endif + unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; + + while (__AFL_LOOP(100000)) { + int len = __AFL_FUZZ_TESTCASE_LEN; + + if (len < 8) continue; + + AFL_INIT_ARGV_P(buf); + + if (argc > 1 && strcmp(argv[1], "XYZ") == 0) { + if (strcmp(argv[2], "TEST2") == 0) { abort(); } + } else { + printf("Bad number of arguments!\n"); + } + } + + return 0; +} \ No newline at end of file -- cgit 1.4.1 From b189640a927e9ed17347b26f6579b0e41dcdda38 Mon Sep 17 00:00:00 2001 From: Maciej Domanski Date: Tue, 27 Dec 2022 16:54:36 +0100 Subject: cleanup --- .custom-format.py | 15 +++++++------ utils/argv_fuzzing/README.md | 4 ++-- utils/argv_fuzzing/argv-fuzz-inl.h | 31 ++++++++++++++------------ utils/argv_fuzzing/argv_fuzz_demo.c | 13 +++++++---- utils/argv_fuzzing/argv_fuzz_persistent_demo.c | 11 ++++++++- 5 files changed, 46 insertions(+), 28 deletions(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/.custom-format.py b/.custom-format.py index 428d7b0d..00f6280f 100755 --- a/.custom-format.py +++ b/.custom-format.py @@ -26,15 +26,16 @@ import shutil with open(".clang-format") as f: fmt = f.read() -CURRENT_LLVM = os.getenv('LLVM_VERSION', 14) -CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "") +#CURRENT_LLVM = os.getenv('LLVM_VERSION', 14) +#CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "") -if shutil.which(CLANG_FORMAT_BIN) is None: - CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}" +#if shutil.which(CLANG_FORMAT_BIN) is None: +# CLANG_FORMAT_BIN = f"clang-format-{CURRENT_LLVM}" -if shutil.which(CLANG_FORMAT_BIN) is None: - print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.") - exit(1) +#if shutil.which(CLANG_FORMAT_BIN) is None: +# print(f"[!] clang-format-{CURRENT_LLVM} is needed. Aborted.") +# exit(1) +CLANG_FORMAT_BIN = "clang-format" COLUMN_LIMIT = 80 for line in fmt.split("\n"): diff --git a/utils/argv_fuzzing/README.md b/utils/argv_fuzzing/README.md index e9224995..bcf388c7 100644 --- a/utils/argv_fuzzing/README.md +++ b/utils/argv_fuzzing/README.md @@ -1,4 +1,4 @@ -# argvfuzz +#argvfuzz AFL++ supports fuzzing file inputs or stdin. When source is available, `argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin. @@ -13,4 +13,4 @@ A few conditions need to be fulfilled for this mechanism to work correctly: 2. If the target binary does not use the default libc's `_start` implementation (crt1.o), the hook may not run. 3. The hook will replace argv with pointers to `.data` of `argvfuzz.so`. If the - target binary expects argv to be living on the stack, things may go wrong. \ No newline at end of file + target binary expects argv to be living on the stack, things may go wrong. diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index d3440799..bb8f2813 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -57,18 +57,20 @@ \ } while (0) -#define AFL_INIT_ARGV_PERSISTENT(persistent_buff) \ - do { \ - argv = afl_init_argv_persistent(&argc, persistent_buff); \ - } while (0) - -#define AFL_INIT_SET0_PERSISTENT(_p, persistent_buff) \ - do { \ - \ - argv = afl_init_argv_persistent(&argc, persistent_buff); \ - argv[0] = (_p); \ - if (!argc) argc = 1; \ - \ +#define AFL_INIT_ARGV_PERSISTENT(persistent_buff) \ + do { \ + \ + argv = afl_init_argv_persistent(&argc, persistent_buff); \ + \ + } while (0) + +#define AFL_INIT_SET0_PERSISTENT(_p, persistent_buff) \ + do { \ + \ + argv = afl_init_argv_persistent(&argc, persistent_buff); \ + argv[0] = (_p); \ + if (!argc) argc = 1; \ + \ } while (0) #define MAX_CMDLINE_LEN 100000 @@ -105,12 +107,13 @@ static char **afl_init_argv(int *argc) { } -static char **afl_init_argv_persistent(int *argc, unsigned char *persistent_buff) { +static char **afl_init_argv_persistent(int *argc, + unsigned char *persistent_buff) { static char *ret[MAX_CMDLINE_PAR]; unsigned char *ptr = persistent_buff; - int rc = 0; + int rc = 0; while (*ptr && rc < MAX_CMDLINE_PAR) { diff --git a/utils/argv_fuzzing/argv_fuzz_demo.c b/utils/argv_fuzzing/argv_fuzz_demo.c index 5fe4d704..6ab1e2e5 100644 --- a/utils/argv_fuzzing/argv_fuzz_demo.c +++ b/utils/argv_fuzzing/argv_fuzz_demo.c @@ -3,6 +3,7 @@ #include "argv-fuzz-inl.h" int main(int argc, char **argv) { + // Initialize the argv array for use with the AFL (American Fuzzy Lop) tool AFL_INIT_ARGV(); @@ -12,12 +13,16 @@ int main(int argc, char **argv) { an error message is printed. If the values do match, the program calls the abort() function. */ if (argc > 1 && strcmp(argv[1], "XYZ") == 0) { - if (strcmp(argv[2], "TEST2") == 0) { - abort(); - } + + if (strcmp(argv[2], "TEST2") == 0) { abort(); } + } else { + printf("Bad number of arguments!\n"); + } return 0; -} \ No newline at end of file + +} + diff --git a/utils/argv_fuzzing/argv_fuzz_persistent_demo.c b/utils/argv_fuzzing/argv_fuzz_persistent_demo.c index a96cf1fe..08a62c62 100644 --- a/utils/argv_fuzzing/argv_fuzz_persistent_demo.c +++ b/utils/argv_fuzzing/argv_fuzz_persistent_demo.c @@ -16,6 +16,7 @@ __AFL_FUZZ_INIT(); one of the arguments. */ int main(int argc, char **argv) { + #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif @@ -25,6 +26,7 @@ int main(int argc, char **argv) { the loop and allowing the program to terminate. It protects against accidental memory leaks and similar issues. */ while (__AFL_LOOP(100000)) { + int len = __AFL_FUZZ_TESTCASE_LEN; // Check that the length of the test case is at least 8 bytes @@ -37,13 +39,20 @@ int main(int argc, char **argv) { If so, call the "abort" function to terminate the program. Otherwise, print an error message. */ if (argc > 1 && strcmp(argv[1], "XYZ") == 0) { + if (strcmp(argv[2], "TEST2") == 0) { abort(); } + } else { + printf("Bad number of arguments!\n"); + } + } + /* Exiting the loop allows the program to terminate normally. AFL will restart the process with a clean slate for allocated memory, file descriptors, etc. */ return 0; -} \ No newline at end of file + +} -- cgit 1.4.1 From 3188cac1d074352e9110d83c7ad5c3d5684d90f8 Mon Sep 17 00:00:00 2001 From: Maciej Domanski Date: Tue, 27 Dec 2022 16:57:30 +0100 Subject: cleanup --- utils/argv_fuzzing/README.md | 2 +- utils/argv_fuzzing/argv-fuzz-inl.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/README.md b/utils/argv_fuzzing/README.md index bcf388c7..ca90f26c 100644 --- a/utils/argv_fuzzing/README.md +++ b/utils/argv_fuzzing/README.md @@ -1,4 +1,4 @@ -#argvfuzz +# argvfuzz feature AFL++ supports fuzzing file inputs or stdin. When source is available, `argv-fuzz-inl.h` can be used to change `main()` to build argv from stdin. diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index bb8f2813..abe86d3c 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -29,10 +29,10 @@ If you would like to always preserve argv[0], use this instead: AFL_INIT_SET0("prog_name"); - To enable persistent fuzzing, use the AFL_INIT_ARGV_PERSISTENT macro with - buf as argument, or use AFL_INIT_SET0_PERSISTENT("prog_name", buf) - to preserver argv[0]. buf should be defined as: - unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; + To enable persistent fuzzing, use the AFL_INIT_ARGV_PERSISTENT macro with + buf as argument, or use AFL_INIT_SET0_PERSISTENT("prog_name", buf) + to preserver argv[0]. buf should be defined as: + unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; */ #ifndef _HAVE_ARGV_FUZZ_INL -- cgit 1.4.1 From c0c985a2781f84313db80eea3662ec88fb264292 Mon Sep 17 00:00:00 2001 From: Maciej Domanski Date: Wed, 28 Dec 2022 09:48:10 +0100 Subject: minor changes --- utils/argv_fuzzing/argv-fuzz-inl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils/argv_fuzzing/argv-fuzz-inl.h') diff --git a/utils/argv_fuzzing/argv-fuzz-inl.h b/utils/argv_fuzzing/argv-fuzz-inl.h index abe86d3c..cb0af2bc 100644 --- a/utils/argv_fuzzing/argv-fuzz-inl.h +++ b/utils/argv_fuzzing/argv-fuzz-inl.h @@ -31,7 +31,8 @@ To enable persistent fuzzing, use the AFL_INIT_ARGV_PERSISTENT macro with buf as argument, or use AFL_INIT_SET0_PERSISTENT("prog_name", buf) - to preserver argv[0]. buf should be defined as: + to preserver argv[0]. buf is a pointer to a buffer containing + the input data for the current test case being processed defined as: unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; */ -- cgit 1.4.1