Coverage Report

Created: 2025-07-18 06:33

/src/zydis/tools/ZydisFuzzDecoder.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************************************
2
3
  Zyan Disassembler Library (Zydis)
4
5
  Original Author : Joel Hoener
6
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
25
***************************************************************************************************/
26
27
/**
28
 * @file
29
 *
30
 * This file implements fuzz target for decoder, formatter and various utility functions.
31
 */
32
33
#include "ZydisFuzzShared.h"
34
35
/* ============================================================================================== */
36
/* Enums and types                                                                                */
37
/* ============================================================================================== */
38
39
/**
40
 * Main fuzzer control block data structure.
41
 */
42
typedef struct ZydisFuzzControlBlock_
43
{
44
    ZydisMachineMode machine_mode;
45
    ZydisStackWidth stack_width;
46
    ZyanBool decoder_mode[ZYDIS_DECODER_MODE_MAX_VALUE + 1];
47
    ZydisFormatterStyle formatter_style;
48
    ZyanU64 u64; // u64 used for all kind of non-overlapping purposes
49
    ZyanUPointer formatter_properties[ZYDIS_FORMATTER_PROP_MAX_VALUE + 1];
50
    char string[16];
51
    ZyanU16 formatter_max_len;
52
} ZydisFuzzControlBlock;
53
54
/* ============================================================================================== */
55
/* Fuzz target                                                                                    */
56
/* ============================================================================================== */
57
58
// We disable enum sanitization here because we actually want Zydis to be tested with
59
// possibly invalid enum values in mind, thus need to be able to create them here.
60
ZYAN_NO_SANITIZE("enum")
61
int ZydisFuzzTarget(ZydisStreamRead read_fn, void* stream_ctx)
62
1.73k
{
63
1.73k
    ZydisFuzzControlBlock control_block;
64
1.73k
    if (read_fn(
65
1.73k
        stream_ctx, (ZyanU8*)&control_block, sizeof(control_block)) != sizeof(control_block))
66
23
    {
67
23
        ZYDIS_MAYBE_FPUTS("Not enough bytes to fuzz\n", ZYAN_STDERR);
68
23
        return EXIT_SUCCESS;
69
23
    }
70
1.70k
    control_block.string[ZYAN_ARRAY_LENGTH(control_block.string) - 1] = 0;
71
72
1.70k
    ZydisDecoder decoder;
73
1.70k
    if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, control_block.machine_mode,
74
1.70k
        control_block.stack_width)))
75
108
    {
76
108
        ZYDIS_MAYBE_FPUTS("Failed to initialize decoder\n", ZYAN_STDERR);
77
108
        return EXIT_FAILURE;
78
108
    }
79
20.7k
    for (int mode = 0; mode <= ZYDIS_DECODER_MODE_MAX_VALUE; ++mode)
80
19.1k
    {
81
19.1k
        if (!ZYAN_SUCCESS(ZydisDecoderEnableMode(&decoder, (ZydisDecoderMode)mode,
82
19.1k
            control_block.decoder_mode[mode] ? 1 : 0)))
83
0
        {
84
0
            ZYDIS_MAYBE_FPUTS("Failed to adjust decoder-mode\n", ZYAN_STDERR);
85
0
            return EXIT_FAILURE;
86
0
        }
87
19.1k
    }
88
89
1.59k
    ZydisFormatter formatter;
90
1.59k
    if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, control_block.formatter_style)))
91
49
    {
92
49
        ZYDIS_MAYBE_FPUTS("Failed to initialize formatter\n", ZYAN_STDERR);
93
49
        return EXIT_FAILURE;
94
49
    }
95
25.8k
    for (int prop = 0; prop <= ZYDIS_FORMATTER_PROP_MAX_VALUE; ++prop)
96
25.8k
    {
97
25.8k
        switch (prop)
98
25.8k
        {
99
433
        case ZYDIS_FORMATTER_PROP_DEC_PREFIX:
100
852
        case ZYDIS_FORMATTER_PROP_DEC_SUFFIX:
101
1.26k
        case ZYDIS_FORMATTER_PROP_HEX_PREFIX:
102
1.67k
        case ZYDIS_FORMATTER_PROP_HEX_SUFFIX:
103
1.67k
            control_block.formatter_properties[prop] =
104
1.67k
                control_block.formatter_properties[prop] ? (ZyanUPointer)&control_block.string : 0;
105
1.67k
            break;
106
24.1k
        default:
107
24.1k
            break;
108
25.8k
        }
109
25.8k
        if (!ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter, (ZydisFormatterProperty)prop,
110
25.8k
            control_block.formatter_properties[prop])))
111
1.55k
        {
112
1.55k
            ZYDIS_MAYBE_FPUTS("Failed to set formatter-attribute\n", ZYAN_STDERR);
113
1.55k
            return EXIT_FAILURE;
114
1.55k
        }
115
25.8k
    }
116
117
0
    ZyanU8 buffer[32];
118
0
    ZyanUSize input_len = read_fn(stream_ctx, buffer, sizeof(buffer));
119
0
    ZydisDecodedInstruction instruction;
120
0
    ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
121
122
    // Fuzz decoder.
123
0
    ZyanStatus status = ZydisDecoderDecodeFull(&decoder, buffer, input_len, &instruction, operands);
124
0
    if (!ZYAN_SUCCESS(status))
125
0
    {
126
0
        return EXIT_FAILURE;
127
0
    }
128
129
0
    ZydisValidateEnumRanges(&instruction, operands, instruction.operand_count);
130
131
    // Fuzz formatter.
132
0
    char format_buffer[256];
133
    // Allow the control block to artificially restrict the buffer size.
134
0
    ZyanUSize output_len = ZYAN_MIN(sizeof(format_buffer), control_block.formatter_max_len);
135
0
    ZydisFormatterFormatInstruction(&formatter, &instruction, operands,
136
0
        instruction.operand_count_visible, format_buffer, output_len, control_block.u64, ZYAN_NULL);
137
138
    // Fuzz tokenizer.
139
0
    const ZydisFormatterToken* token;
140
0
    status = ZydisFormatterTokenizeInstruction(&formatter, &instruction, operands,
141
0
        instruction.operand_count_visible, format_buffer, output_len, control_block.u64, &token,
142
0
        ZYAN_NULL);
143
144
    // Walk tokens.
145
0
    while (ZYAN_SUCCESS(status))
146
0
    {
147
0
        ZydisTokenType type;
148
0
        ZyanConstCharPointer value;
149
0
        if (!ZYAN_SUCCESS(status = ZydisFormatterTokenGetValue(token, &type, &value)))
150
0
        {
151
0
            ZYDIS_MAYBE_FPUTS("Failed to get token value\n", ZYAN_STDERR);
152
0
            break;
153
0
        }
154
155
0
        status = ZydisFormatterTokenNext(&token);
156
0
    }
157
158
0
    if (instruction.operand_count_visible > 0)
159
0
    {
160
        // Fuzz single operand formatting. We reuse rt-address for operand selection.
161
        // It's casted to u8 because modulo is way cheaper on that.
162
0
        ZyanU8 op_idx = (ZyanU8)control_block.u64 % instruction.operand_count_visible;
163
0
        const ZydisDecodedOperand* op = &operands[op_idx];
164
165
0
        ZydisFormatterFormatOperand(&formatter, &instruction, op, format_buffer, output_len,
166
0
            control_block.u64, ZYAN_NULL);
167
168
        // Fuzz single operand tokenization.
169
0
        ZydisFormatterTokenizeOperand(&formatter, &instruction, op, format_buffer, output_len,
170
0
            control_block.u64, &token, ZYAN_NULL);
171
172
        // Address translation helper.
173
0
        ZyanU64 abs_addr;
174
0
        ZydisCalcAbsoluteAddress(&instruction, op, control_block.u64, &abs_addr);
175
0
    }
176
177
    // Mnemonic helpers.
178
0
    ZydisMnemonicGetString((ZydisMnemonic)control_block.u64);
179
0
    ZydisMnemonicGetStringWrapped((ZydisMnemonic)control_block.u64);
180
181
    // Instruction segment helper.
182
0
#   ifndef ZYDIS_DISABLE_SEGMENT
183
0
    ZydisInstructionSegments segments;
184
0
    ZydisGetInstructionSegments(&instruction, &segments);
185
0
#   endif
186
187
    // Feature enable check helper.
188
0
    ZydisIsFeatureEnabled((ZydisFeature)control_block.u64);
189
190
    // Register helpers.
191
0
    ZydisRegisterEncode((ZydisRegisterClass)(control_block.u64 >> 8), (ZyanU8)control_block.u64);
192
0
    ZydisRegisterGetId((ZydisRegister)control_block.u64);
193
0
    ZydisRegisterGetClass((ZydisRegister)control_block.u64);
194
0
    ZydisRegisterGetWidth(control_block.machine_mode, (ZydisRegister)control_block.u64);
195
0
    ZydisRegisterGetLargestEnclosing(control_block.machine_mode, (ZydisRegister)control_block.u64);
196
0
    ZydisRegisterGetString((ZydisRegister)control_block.u64);
197
0
    ZydisRegisterGetStringWrapped((ZydisRegister)control_block.u64);
198
0
    ZydisRegisterClassGetWidth(control_block.machine_mode, (ZydisRegisterClass)control_block.u64);
199
200
0
    return EXIT_SUCCESS;
201
0
}
202
203
/* ============================================================================================== */