etc~ scripts and random things |
| git clone https://github.com/djnnvx/etc.git |
| log | files | refs | archive |
fuzz_prefs_message.c (4101B)
1 /* 2 * AFL++ / LibFuzzer harness — send_initial_message() stack overflow 3 * 4 * Target: protocol.c:26 (SET_WINDOW_TITLE) and protocol.c:29 (SET_PREFERENCES) 5 * 6 * unsigned char message[LWS_PRE + 1 + 4096]; // 4129 bytes 7 * unsigned char *p = &message[LWS_PRE]; // 4097 bytes of headroom 8 * 9 * SET_WINDOW_TITLE: 10 * n = sprintf((char *)p, "%c%s (%s)", cmd, server->command, hostname); 11 * Overflows when server->command > ~3965 bytes (hostname takes up to 127). 12 * 13 * SET_PREFERENCES: 14 * n = sprintf((char *)p, "%c%s", cmd, server->prefs_json); 15 * Overflows when server->prefs_json > 4095 bytes. 16 * 17 * In real ttyd, both fields are admin-controlled (CLI flags --pref, command 18 * argv). This harness makes them fuzzer-controlled to find the overflow and 19 * any downstream UB (wrong return value → unexpected -1 from send_initial_message 20 * → lws_close_reason path, etc.). 21 * 22 * Input format: 23 * [prefs_len:2 BE][prefs_json bytes][cmd_len:2 BE][command bytes] 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <stdint.h> 30 #include <stdbool.h> 31 #include <json-c/json.h> 32 33 #include "fuzz_lws_mock.h" 34 #include "ttyd-src/src/protocol.c" 35 36 extern struct server _fuzz_server; 37 extern void fuzz_server_reset(void); 38 39 static char prefs_buf[65536]; 40 static char cmd_buf[65536]; 41 42 int fuzz_target(const uint8_t *data, size_t size) { 43 if (size < 4) return 0; 44 45 /* Parse prefs_json */ 46 uint16_t prefs_len = (uint16_t)((data[0] << 8) | data[1]); 47 size_t off = 2; 48 if (prefs_len > size - off) prefs_len = (uint16_t)(size - off); 49 if (prefs_len > sizeof(prefs_buf)-1) prefs_len = sizeof(prefs_buf) - 1; 50 memcpy(prefs_buf, data + off, prefs_len); 51 prefs_buf[prefs_len] = '\0'; 52 off += prefs_len; 53 54 /* Parse command */ 55 if (off + 2 > size) return 0; 56 uint16_t cmd_len = (uint16_t)((data[off] << 8) | data[off + 1]); 57 off += 2; 58 if (cmd_len > size - off) cmd_len = (uint16_t)(size - off); 59 if (cmd_len > sizeof(cmd_buf) - 1) cmd_len = sizeof(cmd_buf) - 1; 60 memcpy(cmd_buf, data + off, cmd_len); 61 cmd_buf[cmd_len] = '\0'; 62 63 fuzz_lws_reset(); 64 fuzz_server_reset(); 65 _fuzz_server.prefs_json = prefs_buf; 66 _fuzz_server.command = cmd_buf; 67 strncpy(_fuzz_server.terminal_type, "xterm-256color", 68 sizeof(_fuzz_server.terminal_type) - 1); 69 fuzz_lws_set_uri_path("/ws", 3); 70 71 struct lws mock_wsi = {0}; 72 struct pss_tty pss; 73 memset(&pss, 0, sizeof(pss)); 74 75 /* FILTER: no auth, no origin — always passes */ 76 if (callback_tty(&mock_wsi, LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, 77 &pss, NULL, 0) != 0) 78 goto cleanup; 79 80 if (callback_tty(&mock_wsi, LWS_CALLBACK_ESTABLISHED, 81 &pss, NULL, 0) != 0) 82 goto cleanup; 83 84 /* 85 * Drive through: 86 * WRITEABLE call 1 → SET_WINDOW_TITLE (sprintf with server->command) 87 * WRITEABLE call 2 → SET_PREFERENCES (sprintf with server->prefs_json) 88 * WRITEABLE call 3 → sets initialized=true, calls pty_resume(NULL) 89 */ 90 for (int i = 0; i < 3; i++) 91 callback_tty(&mock_wsi, LWS_CALLBACK_SERVER_WRITEABLE, &pss, NULL, 0); 92 93 cleanup: 94 callback_tty(&mock_wsi, LWS_CALLBACK_CLOSED, &pss, NULL, 0); 95 return 0; 96 } 97 98 #ifdef __AFL_FUZZ_TESTCASE_LEN 99 __AFL_FUZZ_INIT(); 100 int main(void) { 101 #ifdef __AFL_HAVE_MANUAL_CONTROL 102 __AFL_INIT(); 103 #endif 104 unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; 105 while (__AFL_LOOP(10000)) { 106 fuzz_target(buf, __AFL_FUZZ_TESTCASE_LEN); 107 } 108 return 0; 109 } 110 111 #else 112 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 113 return fuzz_target(data, size); 114 } 115 116 #ifndef LIBFUZZER 117 int main(int argc, char **argv) { 118 if (argc != 2) { fprintf(stderr, "Usage: %s <input_file>\n", argv[0]); return 1; } 119 FILE *f = fopen(argv[1], "rb"); 120 if (!f) { perror("fopen"); return 1; } 121 fseek(f, 0, SEEK_END); long sz = ftell(f); rewind(f); 122 uint8_t *buf = malloc(sz); 123 fread(buf, 1, sz, f); fclose(f); 124 fuzz_target(buf, sz); 125 free(buf); 126 return 0; 127 } 128 #endif 129 #endif