Skip to content

Commit afeab61

Browse files
authored
fix(🔐): remove potential buffer over-reads (#3086)
1 parent c09746c commit afeab61

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed

packages/skia/cpp/api/JsiSkCanvas.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,12 @@ class JsiSkCanvas : public JsiSkHostObject {
243243

244244
auto jsiPoints = arguments[1].asObject(runtime).asArray(runtime);
245245
auto pointsSize = jsiPoints.size(runtime);
246+
247+
// Check if we have at least one point
248+
if (pointsSize == 0) {
249+
throw std::invalid_argument("Points array must not be empty");
250+
}
251+
246252
points.reserve(pointsSize);
247253

248254
for (int i = 0; i < pointsSize; i++) {
@@ -274,6 +280,12 @@ class JsiSkCanvas : public JsiSkHostObject {
274280

275281
auto jsiCubics = arguments[0].asObject(runtime).asArray(runtime);
276282
auto cubicsSize = jsiCubics.size(runtime);
283+
284+
// Validate cubic points - must be exactly 12 points
285+
if (cubicsSize != 12) {
286+
throw std::invalid_argument("Cubic points array must contain exactly 12 points");
287+
}
288+
277289
cubics.reserve(cubicsSize);
278290
for (int i = 0; i < cubicsSize; i++) {
279291
std::shared_ptr<SkPoint> point = JsiSkPoint::fromValue(
@@ -284,6 +296,12 @@ class JsiSkCanvas : public JsiSkHostObject {
284296
if (count >= 2 && !arguments[1].isNull() && !arguments[1].isUndefined()) {
285297
auto jsiColors = arguments[1].asObject(runtime).asArray(runtime);
286298
auto colorsSize = jsiColors.size(runtime);
299+
300+
// Validate colors array - must be exactly 4 colors
301+
if (colorsSize != 4) {
302+
throw std::invalid_argument("Colors array must contain exactly 4 colors");
303+
}
304+
287305
colors.reserve(colorsSize);
288306
for (int i = 0; i < colorsSize; i++) {
289307
SkColor color = JsiSkColor::fromValue(
@@ -295,6 +313,12 @@ class JsiSkCanvas : public JsiSkHostObject {
295313
if (count >= 3 && !arguments[2].isNull() && !arguments[2].isUndefined()) {
296314
auto jsiTexs = arguments[2].asObject(runtime).asArray(runtime);
297315
auto texsSize = jsiTexs.size(runtime);
316+
317+
// Validate textures array - must be exactly 4 points
318+
if (texsSize != 4) {
319+
throw std::invalid_argument("Texture coordinates array must contain exactly 4 points");
320+
}
321+
298322
texs.reserve(texsSize);
299323
for (int i = 0; i < texsSize; i++) {
300324
auto point = JsiSkPoint::fromValue(
@@ -306,7 +330,8 @@ class JsiSkCanvas : public JsiSkHostObject {
306330
auto paint =
307331
count >= 4 ? JsiSkPaint::fromValue(runtime, arguments[4]) : nullptr;
308332
auto blendMode = static_cast<SkBlendMode>(arguments[3].asNumber());
309-
_canvas->drawPatch(cubics.data(), colors.data(), texs.data(), blendMode,
333+
_canvas->drawPatch(cubics.data(), colors.empty() ? nullptr : colors.data(),
334+
texs.empty() ? nullptr : texs.data(), blendMode,
310335
*paint);
311336
return jsi::Value::undefined();
312337
}
@@ -364,6 +389,12 @@ class JsiSkCanvas : public JsiSkHostObject {
364389

365390
std::vector<SkGlyphID> glyphs;
366391
int glyphsSize = static_cast<int>(jsiGlyphs.size(runtime));
392+
393+
// Validate that glyphs and positions arrays have the same size
394+
if (glyphsSize != pointsSize) {
395+
throw std::invalid_argument("Glyphs and positions arrays must have the same length");
396+
}
397+
367398
glyphs.reserve(glyphsSize);
368399
for (int i = 0; i < glyphsSize; i++) {
369400
glyphs.push_back(jsiGlyphs.getValueAtIndex(runtime, i).asNumber());
@@ -522,11 +553,22 @@ class JsiSkCanvas : public JsiSkHostObject {
522553
runtime, rects.getValueAtIndex(runtime, i).asObject(runtime));
523554
skRects.push_back(*rect.get());
524555
}
556+
557+
// Validate transforms and rects have the same size
558+
if (xformsSize != rectsSize) {
559+
throw std::invalid_argument("Transforms and rects arrays must have the same length");
560+
}
525561

526562
std::vector<SkColor> colors;
527563
if (count > 5 && !arguments[5].isUndefined()) {
528564
auto colorsArray = arguments[5].asObject(runtime).asArray(runtime);
529565
int colorsSize = static_cast<int>(colorsArray.size(runtime));
566+
567+
// Validate colors array matches the size of sprites and transforms
568+
if (colorsSize != rectsSize) {
569+
throw std::invalid_argument("Colors array must have the same length as rects/transforms");
570+
}
571+
530572
colors.reserve(colorsSize);
531573
for (int i = 0; i < colorsSize; i++) {
532574
// Convert from [r,g,b,a] in [0,1] to SkColor
@@ -551,7 +593,8 @@ class JsiSkCanvas : public JsiSkHostObject {
551593
sampling = SamplingOptionsFromValue(runtime, arguments[6]);
552594
}
553595
_canvas->drawAtlas(atlas.get(), xforms.data(), skRects.data(),
554-
colors.data(), skRects.size(), blendMode, sampling,
596+
colors.empty() ? nullptr : colors.data(),
597+
skRects.size(), blendMode, sampling,
555598
nullptr, paint.get());
556599

557600
return jsi::Value::undefined();

packages/skia/cpp/api/recorder/Drawings.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,16 @@ class PatchCmd : public Command {
637637
}
638638

639639
void draw(DrawingCtx *ctx) {
640+
// Validate colors array has exactly 4 colors if provided
641+
if (props.colors.has_value() && props.colors.value().size() != 4) {
642+
throw std::invalid_argument("Colors array for patch must have exactly 4 colors");
643+
}
644+
645+
// Validate texture array has exactly 4 points if provided
646+
if (props.texture.has_value() && props.texture.value().size() != 4) {
647+
throw std::invalid_argument("Texture coordinates array for patch must have exactly 4 points");
648+
}
649+
640650
// Determine default blend mode based on presence of colors
641651
SkBlendMode defaultBlendMode = props.colors.has_value()
642652
? SkBlendMode::kDstOver
@@ -676,6 +686,15 @@ class VerticesCmd : public Command {
676686
}
677687

678688
void draw(DrawingCtx *ctx) {
689+
// Validate array sizes
690+
if (props.colors.has_value() && props.colors.value().size() != props.vertices.size()) {
691+
throw std::invalid_argument("Colors array must have the same size as vertices array");
692+
}
693+
694+
if (props.textures.has_value() && props.textures.value().size() != props.vertices.size()) {
695+
throw std::invalid_argument("Textures array must have the same size as vertices array");
696+
}
697+
679698
// Create vertices using MakeCopy
680699
auto vertices = SkVertices::MakeCopy(
681700
props.mode, static_cast<int>(props.vertices.size()),
@@ -909,6 +928,16 @@ class AtlasCmd : public Command {
909928

910929
void draw(DrawingCtx *ctx) {
911930
if (props.image) {
931+
// Validate transforms and sprites have the same size
932+
if (props.transforms.size() != props.sprites.size()) {
933+
throw std::invalid_argument("transforms and sprites arrays must have the same length");
934+
}
935+
936+
// Validate colors array matches if provided
937+
if (props.colors.has_value() && props.colors.value().size() != props.transforms.size()) {
938+
throw std::invalid_argument("colors array must have the same length as transforms/sprites");
939+
}
940+
912941
auto colors =
913942
props.colors.has_value() ? props.colors.value().data() : nullptr;
914943
auto blendMode = props.blendMode.value_or(SkBlendMode::kDstOver);

packages/skia/cpp/api/recorder/Shaders.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,16 @@ class LinearGradientCmd : public Command {
239239
}
240240

241241
void pushShader(DrawingCtx *ctx) {
242+
// Validate colors array has at least 2 colors
243+
if (props.colors.size() < 2) {
244+
throw std::invalid_argument("Colors array must have at least 2 colors");
245+
}
246+
247+
// Validate positions array matches colors array in size
248+
if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
249+
throw std::invalid_argument("Positions array must have the same size as colors array");
250+
}
251+
242252
SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
243253
const SkPoint pts[2] = {props.start, props.end};
244254
auto shader = SkGradientShader::MakeLinear(
@@ -276,6 +286,16 @@ class RadialGradientCmd : public Command {
276286
}
277287

278288
void pushShader(DrawingCtx *ctx) {
289+
// Validate colors array has at least 2 colors
290+
if (props.colors.size() < 2) {
291+
throw std::invalid_argument("Colors array must have at least 2 colors");
292+
}
293+
294+
// Validate positions array matches colors array in size
295+
if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
296+
throw std::invalid_argument("Positions array must have the same size as colors array");
297+
}
298+
279299
SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
280300
auto shader = SkGradientShader::MakeRadial(
281301
props.center, props.radius, props.colors.data(),
@@ -314,6 +334,16 @@ class SweepGradientCmd : public Command {
314334
}
315335

316336
void pushShader(DrawingCtx *ctx) {
337+
// Validate colors array has at least 2 colors
338+
if (props.colors.size() < 2) {
339+
throw std::invalid_argument("Colors array must have at least 2 colors");
340+
}
341+
342+
// Validate positions array matches colors array in size
343+
if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
344+
throw std::invalid_argument("Positions array must have the same size as colors array");
345+
}
346+
317347
SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
318348
auto shader = SkGradientShader::MakeSweep(
319349
props.center.x(), props.center.y(), props.colors.data(),
@@ -355,6 +385,16 @@ class TwoPointConicalGradientCmd : public Command {
355385
}
356386

357387
void pushShader(DrawingCtx *ctx) {
388+
// Validate colors array has at least 2 colors
389+
if (props.colors.size() < 2) {
390+
throw std::invalid_argument("Colors array must have at least 2 colors");
391+
}
392+
393+
// Validate positions array matches colors array in size
394+
if (props.positions.has_value() && props.positions.value().size() != props.colors.size()) {
395+
throw std::invalid_argument("Positions array must have the same size as colors array");
396+
}
397+
358398
SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin);
359399
auto shader = SkGradientShader::MakeTwoPointConical(
360400
props.start, props.startRadius, props.end, props.endRadius,

0 commit comments

Comments
 (0)