Coverage Report

Created: 2022-01-03 11:46

/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
5.14k
{
63
5.14k
    ZydisFuzzControlBlock control_block;
64
5.14k
    if (read_fn(
65
5.14k
        stream_ctx, (ZyanU8*)&control_block, sizeof(control_block)) != sizeof(control_block))
66
4.80k
    {
67
4.80k
        ZYDIS_MAYBE_FPUTS("Not enough bytes to fuzz\n", ZYAN_STDERR);
68
4.80k
        return EXIT_SUCCESS;
69
4.80k
    }
70
341
    control_block.string[ZYAN_ARRAY_LENGTH(control_block.string) - 1] = 0;
71
72
341
    ZydisDecoder decoder;
73
341
    if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, control_block.machine_mode,
74
341
        control_block.stack_width)))
75
0
    {
76
0
        ZYDIS_MAYBE_FPUTS("Failed to initialize decoder\n", ZYAN_STDERR);
77
0
        return EXIT_FAILURE;
78
0
    }
79
3.41k
    for (int mode = 0; mode <= ZYDIS_DECODER_MODE_MAX_VALUE; ++mode)
80
3.06k
    {
81
3.06k
        if (!ZYAN_SUCCESS(ZydisDecoderEnableMode(&decoder, (ZydisDecoderMode)mode,
82
3.06k
            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
3.06k
    }
88
89
341
    ZydisFormatter formatter;
90
341
    if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, control_block.formatter_style)))
91
0
    {
92
0
        ZYDIS_MAYBE_FPUTS("Failed to initialize formatter\n", ZYAN_STDERR);
93
0
        return EXIT_FAILURE;
94
0
    }
95
8.79k
    for (int prop = 0; prop <= ZYDIS_FORMATTER_PROP_MAX_VALUE; ++prop)
96
8.79k
    {
97
8.79k
        switch (prop)
98
8.79k
        {
99
341
        case ZYDIS_FORMATTER_PROP_DEC_PREFIX:
100
659
        case ZYDIS_FORMATTER_PROP_DEC_SUFFIX:
101
659
        case ZYDIS_FORMATTER_PROP_HEX_PREFIX:
102
659
        case ZYDIS_FORMATTER_PROP_HEX_SUFFIX:
103
659
            control_block.formatter_properties[prop] =
104
659
                control_block.formatter_properties[prop] ? (ZyanUPointer)&control_block.string : 0;
105
659
            break;
106
8.13k
        default:
107
8.13k
            break;
108
8.79k
        }
109
8.79k
        if (!ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter, (ZydisFormatterProperty)prop,
110
8.79k
            control_block.formatter_properties[prop])))
111
341
        {
112
341
            ZYDIS_MAYBE_FPUTS("Failed to set formatter-attribute\n", ZYAN_STDERR);
113
341
            return EXIT_FAILURE;
114
341
        }
115
8.79k
    }
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, 
124
0
        operands, ZYDIS_MAX_OPERAND_COUNT, 0);
125
0
    if (!ZYAN_SUCCESS(status))
126
0
    {
127
0
        return EXIT_FAILURE;
128
0
    }
129
130
0
    ZydisValidateEnumRanges(&instruction, operands, instruction.operand_count);
131
132
    // Fuzz formatter.
133
0
    char format_buffer[256];
134
    // Allow the control block to artificially restrict the buffer size.
135
0
    ZyanUSize output_len = ZYAN_MIN(sizeof(format_buffer), control_block.formatter_max_len);
136
0
    ZydisFormatterFormatInstruction(&formatter, &instruction, operands,
137
0
        instruction.operand_count_visible, format_buffer, output_len, control_block.u64);
138
139
    // Fuzz tokenizer.
140
0
    const ZydisFormatterToken* token;
141
0
    status = ZydisFormatterTokenizeInstruction(&formatter, &instruction, operands,
142
0
        instruction.operand_count_visible, format_buffer, output_len, control_block.u64, &token);
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);
167
168
        // Fuzz single operand tokenization.
169
0
        ZydisFormatterTokenizeOperand(&formatter, &instruction, op, format_buffer, output_len,
170
0
            control_block.u64, &token);
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
    ZydisInstructionSegments segments;
183
0
    ZydisGetInstructionSegments(&instruction, &segments);
184
185
    // Feature enable check helper.
186
0
    ZydisIsFeatureEnabled((ZydisFeature)control_block.u64);
187
188
    // Register helpers.
189
0
    ZydisRegisterEncode((ZydisRegisterClass)(control_block.u64 >> 8), (ZyanU8)control_block.u64);
190
0
    ZydisRegisterGetId((ZydisRegister)control_block.u64);
191
0
    ZydisRegisterGetClass((ZydisRegister)control_block.u64);
192
0
    ZydisRegisterGetWidth(control_block.machine_mode, (ZydisRegister)control_block.u64);
193
0
    ZydisRegisterGetLargestEnclosing(control_block.machine_mode, (ZydisRegister)control_block.u64);
194
0
    ZydisRegisterGetString((ZydisRegister)control_block.u64);
195
0
    ZydisRegisterGetStringWrapped((ZydisRegister)control_block.u64);
196
0
    ZydisRegisterClassGetWidth(control_block.machine_mode, (ZydisRegisterClass)control_block.u64);
197
198
0
    return EXIT_SUCCESS;
199
0
}
200
201
/* ============================================================================================== */