Skip to content

Commit 4dc6234

Browse files
committed
avoid integer overflow in ensureSurface
width * height * approxBytesPerPixel was too big Zig found via ubsan
1 parent f48aeff commit 4dc6234

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

src/Canvas.cc

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
"with at least a family (string) and optionally weight (string/number) " \
3333
"and style (string)."
3434

35+
#define CAIRO_MAX_SIZE 32767
36+
3537
using namespace std;
3638

3739
std::vector<FontFace> Canvas::font_face_list;
@@ -87,6 +89,11 @@ Canvas::Canvas(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Canvas>(info),
8789
_surface = nullptr;
8890
_closure = nullptr;
8991
format = CAIRO_FORMAT_ARGB32;
92+
this->width = 0;
93+
this->height = 0;
94+
95+
int32_t width;
96+
int32_t height;
9097

9198
if (info[0].IsNumber()) {
9299
width = info[0].As<Napi::Number>().Int32Value();
@@ -112,6 +119,21 @@ Canvas::Canvas(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Canvas>(info),
112119
type = CANVAS_TYPE_IMAGE;
113120
}
114121

122+
if (width > CAIRO_MAX_SIZE || width < 0) {
123+
std::string msg = "Canvas width must be between 0 and " + std::to_string(CAIRO_MAX_SIZE);
124+
Napi::Error::New(env, msg).ThrowAsJavaScriptException();
125+
return;
126+
}
127+
128+
if (height > CAIRO_MAX_SIZE || height < 0) {
129+
std::string msg = "Canvas height must be between 0 and " + std::to_string(CAIRO_MAX_SIZE);
130+
Napi::Error::New(env, msg).ThrowAsJavaScriptException();
131+
return;
132+
}
133+
134+
this->width = width;
135+
this->height = height;
136+
115137
cairo_status_t status = cairo_surface_status(ensureSurface());
116138

117139
if (status != CAIRO_STATUS_SUCCESS) {
@@ -164,8 +186,11 @@ Canvas::GetWidth(const Napi::CallbackInfo& info) {
164186
void
165187
Canvas::SetWidth(const Napi::CallbackInfo& info, const Napi::Value& value) {
166188
if (value.IsNumber()) {
167-
int width = value.As<Napi::Number>().Uint32Value();
168-
resurface(info.This().As<Napi::Object>(), width, this->height);
189+
int32_t width = value.As<Napi::Number>().Int32Value();
190+
if (width >= 0 && width <= CAIRO_MAX_SIZE) {
191+
this->width = width;
192+
resurface(info.This().As<Napi::Object>(), width, this->height);
193+
}
169194
}
170195
}
171196

@@ -185,8 +210,11 @@ Canvas::GetHeight(const Napi::CallbackInfo& info) {
185210
void
186211
Canvas::SetHeight(const Napi::CallbackInfo& info, const Napi::Value& value) {
187212
if (value.IsNumber()) {
188-
int height = value.As<Napi::Number>().Uint32Value();
189-
resurface(info.This().As<Napi::Object>(), this->width, height);
213+
int32_t height = value.As<Napi::Number>().Uint32Value();
214+
if (height >= 0 && height <= CAIRO_MAX_SIZE) {
215+
this->height = height;
216+
resurface(info.This().As<Napi::Object>(), this->width, height);
217+
}
190218
}
191219
}
192220

test/canvas.test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,11 @@ describe('Canvas', function () {
416416
assert.equal(canvas.width, 50)
417417
assert.equal(canvas.height, 70)
418418

419+
canvas.width = 60_000;
420+
canvas.height = 60_000;
421+
assert.equal(canvas.width, 50)
422+
assert.equal(canvas.height, 70)
423+
419424
context.font = '20px arial'
420425
assert.equal(context.font, '20px arial')
421426
canvas.width |= 0

0 commit comments

Comments
 (0)