Line | Count | Source |
1 | | /* |
2 | | * Copyright 2026 Google LLC |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | /* |
18 | | * SQL parser fuzzer for TDengine 3.x. |
19 | | * |
20 | | * This fuzzer exercises the SQL syntax parsing layer (qParseSqlSyntax), |
21 | | * which tokenises and builds an AST from untrusted SQL input without |
22 | | * requiring a running TDengine server or catalog. It is the first |
23 | | * layer of SQL processing and is therefore the highest-risk entry |
24 | | * point for parsing bugs (buffer overflows, OOB reads, infinite loops, |
25 | | * assertion failures, etc.). |
26 | | */ |
27 | | |
28 | | #include <stdint.h> |
29 | | #include <string.h> |
30 | | |
31 | | /* Include the OS abstraction first so TDengine memory wrappers are defined |
32 | | * before any other TDengine headers redefine malloc/free. */ |
33 | | #include "os.h" |
34 | | #include "parser.h" |
35 | | #include "catalog.h" |
36 | | #include "querynodes.h" |
37 | | |
38 | | /* One-time initialisation flag. */ |
39 | | static int g_init = 0; |
40 | | |
41 | | /* Error message buffer reused every call. */ |
42 | 4.98k | #define MSG_BUF_LEN 4096 |
43 | | static char g_msgBuf[MSG_BUF_LEN]; |
44 | | |
45 | 4.98k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
46 | | /* Initialise keyword table once. */ |
47 | 4.98k | if (!g_init) { |
48 | 1 | qInitKeywordsTable(); |
49 | 1 | g_init = 1; |
50 | 1 | } |
51 | | |
52 | | /* Require at least one byte so we always have a null-terminated string. */ |
53 | 4.98k | if (size == 0) { |
54 | 0 | return 0; |
55 | 0 | } |
56 | | |
57 | | /* Copy input and null-terminate so that the parser can treat it as a |
58 | | * C-string safely. We deliberately limit to 64 KB to keep the fuzzer |
59 | | * fast; real SQL queries are never this long in practice. */ |
60 | 4.98k | if (size > 65536) { |
61 | 16 | size = 65536; |
62 | 16 | } |
63 | | /* Use TDengine's memory allocator (direct malloc/free are forbidden). */ |
64 | 4.98k | char *sql = (char *)taosMemoryMalloc(size + 1); |
65 | 4.98k | if (!sql) { |
66 | 0 | return 0; |
67 | 0 | } |
68 | 4.98k | memcpy(sql, data, size); |
69 | 4.98k | sql[size] = '\0'; |
70 | | |
71 | | /* Prepare a minimal parse context. |
72 | | * allocatorId = 0 → use the default (no custom arena allocator). |
73 | | * parseOnly is intentionally left false; we set up enough context |
74 | | * for syntax-only parsing via qParseSqlSyntax. */ |
75 | 4.98k | SParseContext cxt; |
76 | 4.98k | memset(&cxt, 0, sizeof(cxt)); |
77 | 4.98k | cxt.acctId = 1; |
78 | 4.98k | cxt.db = "fuzz_db"; |
79 | 4.98k | cxt.pUser = "root"; |
80 | 4.98k | cxt.isSuperUser = true; |
81 | 4.98k | cxt.enableSysInfo = true; |
82 | 4.98k | cxt.privInfo = (uint16_t)0xFFFF; /* grant all privileges */ |
83 | 4.98k | cxt.pSql = sql; |
84 | 4.98k | cxt.sqlLen = size; |
85 | 4.98k | cxt.pMsg = g_msgBuf; |
86 | 4.98k | cxt.msgLen = MSG_BUF_LEN; |
87 | 4.98k | cxt.svrVer = "3.0.0.0"; |
88 | 4.98k | cxt.allocatorId = 0; |
89 | | |
90 | 4.98k | SQuery *pQuery = NULL; |
91 | 4.98k | SCatalogReq catalogReq; |
92 | 4.98k | memset(&catalogReq, 0, sizeof(catalogReq)); |
93 | | |
94 | | /* Parse SQL syntax only – no network/catalog required. */ |
95 | 4.98k | (void)qParseSqlSyntax(&cxt, &pQuery, &catalogReq); |
96 | | |
97 | | /* Clean up. */ |
98 | 4.98k | if (pQuery) { |
99 | 2.03k | qDestroyQuery(pQuery); |
100 | 2.03k | } |
101 | | |
102 | 4.98k | taosMemoryFree(sql); |
103 | 4.98k | return 0; |
104 | 4.98k | } |