Repository navigation
Expand file tree
/
Copy pathCVE-2026-54696.patch
More file actions
116 lines (104 loc) · 4.08 KB
/
Copy pathCVE-2026-54696.patch
File metadata and controls
116 lines (104 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
generator.c: don't start with a stack buffer in IO case
Fixes a heap buffer overflow in JSON.dump(obj, io) / JSON::State#generate(obj, io).
CVE-2026-54696; ruby/json fd6a65bd08 adapted to the json 2.18.0 bundled with Ruby 4.0:
https://github.com/ruby/json/commit/fd6a65bd08e5f3a429c03919ebfd8dd19158f095
--- a/ext/json/fbuffer/fbuffer.h
+++ b/ext/json/fbuffer/fbuffer.h
@@ -37,13 +37,17 @@
static inline void fbuffer_append_char(FBuffer *fb, char newchr);
static VALUE fbuffer_finalize(FBuffer *fb);
-static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
+static void fbuffer_init(FBuffer *fb, unsigned long initial_length, VALUE io, char *stack_buffer, long stack_buffer_size)
{
- fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
- if (stack_buffer) {
+ if (RTEST(io)) {
+ JSON_ASSERT(fb->type == FBUFFER_HEAP_ALLOCATED);
+ fb->io = io;
+ fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_IO_BUFFER_SIZE;
+ } else {
fb->type = FBUFFER_STACK_ALLOCATED;
fb->ptr = stack_buffer;
fb->capa = stack_buffer_size;
+ fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
}
#if JSON_DEBUG
fb->requested = 0;
@@ -79,45 +83,40 @@
fbuffer_clear(fb);
}
-static void fbuffer_realloc(FBuffer *fb, unsigned long required)
+static void fbuffer_realloc(FBuffer *fb, unsigned long new_capa)
{
- if (required > fb->capa) {
+ if (new_capa > fb->capa) {
if (fb->type == FBUFFER_STACK_ALLOCATED) {
const char *old_buffer = fb->ptr;
- fb->ptr = ALLOC_N(char, required);
+ fb->ptr = ALLOC_N(char, new_capa);
fb->type = FBUFFER_HEAP_ALLOCATED;
MEMCPY(fb->ptr, old_buffer, char, fb->len);
} else {
- REALLOC_N(fb->ptr, char, required);
+ REALLOC_N(fb->ptr, char, new_capa);
}
- fb->capa = required;
+ fb->capa = new_capa;
}
}
static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
{
if (RB_UNLIKELY(fb->io)) {
- if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
- fbuffer_realloc(fb, FBUFFER_IO_BUFFER_SIZE);
- } else {
+ if (fb->capa != 0) {
fbuffer_flush(fb);
- }
-
- if (RB_LIKELY(requested < fb->capa)) {
- return;
+ if (RB_LIKELY(requested < fb->capa)) {
+ return;
+ }
}
}
- unsigned long required;
+ unsigned long new_capa = fb->capa ? fb->capa : fb->initial_length;
+ unsigned long needed_capa = requested + fb->len;
- if (RB_UNLIKELY(!fb->ptr)) {
- fb->ptr = ALLOC_N(char, fb->initial_length);
- fb->capa = fb->initial_length;
+ while (new_capa < needed_capa) {
+ new_capa *= 2;
}
- for (required = fb->capa; requested > required - fb->len; required <<= 1);
-
- fbuffer_realloc(fb, required);
+ fbuffer_realloc(fb, new_capa);
}
static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -1490,10 +1490,8 @@
GET_STATE(self);
char stack_buffer[FBUFFER_STACK_SIZE];
- FBuffer buffer = {
- .io = RTEST(io) ? io : Qfalse,
- };
- fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
+ FBuffer buffer = { 0 };
+ fbuffer_init(&buffer, state->buffer_initial_length, io, stack_buffer, FBUFFER_STACK_SIZE);
struct generate_json_data data = {
.buffer = &buffer,
@@ -2027,10 +2025,8 @@
configure_state(&state, Qfalse, opts);
char stack_buffer[FBUFFER_STACK_SIZE];
- FBuffer buffer = {
- .io = RTEST(io) ? io : Qfalse,
- };
- fbuffer_stack_init(&buffer, state.buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
+ FBuffer buffer = { 0 };
+ fbuffer_init(&buffer, state.buffer_initial_length, io, stack_buffer, FBUFFER_STACK_SIZE);
struct generate_json_data data = {
.buffer = &buffer,