xref: /openbmc/qemu/qobject/json-streamer.c (revision f1f7e4bf)
1 /*
2  * JSON streaming support
3  *
4  * Copyright IBM, Corp. 2009
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10  * See the COPYING.LIB file in the top-level directory.
11  *
12  */
13 
14 #include "qemu-common.h"
15 #include "qapi/qmp/json-lexer.h"
16 #include "qapi/qmp/json-streamer.h"
17 
18 #define MAX_TOKEN_SIZE (64ULL << 20)
19 #define MAX_TOKEN_COUNT (2ULL << 20)
20 #define MAX_NESTING (1ULL << 10)
21 
22 static void json_message_free_tokens(JSONMessageParser *parser)
23 {
24     if (parser->tokens) {
25         g_queue_free(parser->tokens);
26         parser->tokens = NULL;
27     }
28 }
29 
30 static void json_message_process_token(JSONLexer *lexer, GString *input,
31                                        JSONTokenType type, int x, int y)
32 {
33     JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
34     JSONToken *token;
35 
36     switch (type) {
37     case JSON_LCURLY:
38         parser->brace_count++;
39         break;
40     case JSON_RCURLY:
41         parser->brace_count--;
42         break;
43     case JSON_LSQUARE:
44         parser->bracket_count++;
45         break;
46     case JSON_RSQUARE:
47         parser->bracket_count--;
48         break;
49     default:
50         break;
51     }
52 
53     token = g_malloc(sizeof(JSONToken) + input->len + 1);
54     token->type = type;
55     memcpy(token->str, input->str, input->len);
56     token->str[input->len] = 0;
57     token->x = x;
58     token->y = y;
59 
60     parser->token_size += input->len;
61 
62     g_queue_push_tail(parser->tokens, token);
63 
64     if (type == JSON_ERROR) {
65         goto out_emit_bad;
66     } else if (parser->brace_count < 0 ||
67         parser->bracket_count < 0 ||
68         (parser->brace_count == 0 &&
69          parser->bracket_count == 0)) {
70         goto out_emit;
71     } else if (parser->token_size > MAX_TOKEN_SIZE ||
72                g_queue_get_length(parser->tokens) > MAX_TOKEN_COUNT ||
73                parser->bracket_count + parser->brace_count > MAX_NESTING) {
74         /* Security consideration, we limit total memory allocated per object
75          * and the maximum recursion depth that a message can force.
76          */
77         goto out_emit_bad;
78     }
79 
80     return;
81 
82 out_emit_bad:
83     /*
84      * Clear out token list and tell the parser to emit an error
85      * indication by passing it a NULL list
86      */
87     json_message_free_tokens(parser);
88 out_emit:
89     /* send current list of tokens to parser and reset tokenizer */
90     parser->brace_count = 0;
91     parser->bracket_count = 0;
92     /* parser->emit takes ownership of parser->tokens.  */
93     parser->emit(parser, parser->tokens);
94     parser->tokens = g_queue_new();
95     parser->token_size = 0;
96 }
97 
98 void json_message_parser_init(JSONMessageParser *parser,
99                               void (*func)(JSONMessageParser *, GQueue *))
100 {
101     parser->emit = func;
102     parser->brace_count = 0;
103     parser->bracket_count = 0;
104     parser->tokens = g_queue_new();
105     parser->token_size = 0;
106 
107     json_lexer_init(&parser->lexer, json_message_process_token);
108 }
109 
110 int json_message_parser_feed(JSONMessageParser *parser,
111                              const char *buffer, size_t size)
112 {
113     return json_lexer_feed(&parser->lexer, buffer, size);
114 }
115 
116 int json_message_parser_flush(JSONMessageParser *parser)
117 {
118     return json_lexer_flush(&parser->lexer);
119 }
120 
121 void json_message_parser_destroy(JSONMessageParser *parser)
122 {
123     json_lexer_destroy(&parser->lexer);
124     json_message_free_tokens(parser);
125 }
126