Skip to content

Commit a4bea62

Browse files
trop[bot]MarshallOfSound
authored andcommitted
fix: add missing buffer size check in nativeImage (electron#17569)
1 parent e964d34 commit a4bea62

File tree

2 files changed

+94
-53
lines changed

2 files changed

+94
-53
lines changed

atom/common/api/atom_api_native_image.cc

Lines changed: 77 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -79,49 +79,71 @@ float GetScaleFactorFromOptions(mate::Arguments* args) {
7979
return scale_factor;
8080
}
8181

82-
bool AddImageSkiaRep(gfx::ImageSkia* image,
83-
const unsigned char* data,
84-
size_t size,
85-
int width,
86-
int height,
87-
double scale_factor) {
88-
auto decoded = std::make_unique<SkBitmap>();
82+
bool AddImageSkiaRepFromPNG(gfx::ImageSkia* image,
83+
const unsigned char* data,
84+
size_t size,
85+
double scale_factor) {
86+
SkBitmap bitmap;
87+
if (!gfx::PNGCodec::Decode(data, size, &bitmap))
88+
return false;
89+
90+
image->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale_factor));
91+
return true;
92+
}
93+
94+
bool AddImageSkiaRepFromJPEG(gfx::ImageSkia* image,
95+
const unsigned char* data,
96+
size_t size,
97+
double scale_factor) {
98+
auto bitmap = gfx::JPEGCodec::Decode(data, size);
99+
if (!bitmap)
100+
return false;
101+
102+
// `JPEGCodec::Decode()` doesn't tell `SkBitmap` instance it creates
103+
// that all of its pixels are opaque, that's why the bitmap gets
104+
// an alpha type `kPremul_SkAlphaType` instead of `kOpaque_SkAlphaType`.
105+
// Let's fix it here.
106+
// TODO(alexeykuzmin): This workaround should be removed
107+
// when the `JPEGCodec::Decode()` code is fixed.
108+
// See https://github.com/electron/electron/issues/11294.
109+
bitmap->setAlphaType(SkAlphaType::kOpaque_SkAlphaType);
110+
111+
image->AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale_factor));
112+
return true;
113+
}
89114

115+
bool AddImageSkiaRepFromBuffer(gfx::ImageSkia* image,
116+
const unsigned char* data,
117+
size_t size,
118+
int width,
119+
int height,
120+
double scale_factor) {
90121
// Try PNG first.
91-
if (!gfx::PNGCodec::Decode(data, size, decoded.get())) {
92-
// Try JPEG.
93-
decoded = gfx::JPEGCodec::Decode(data, size);
94-
if (decoded) {
95-
// `JPEGCodec::Decode()` doesn't tell `SkBitmap` instance it creates
96-
// that all of its pixels are opaque, that's why the bitmap gets
97-
// an alpha type `kPremul_SkAlphaType` instead of `kOpaque_SkAlphaType`.
98-
// Let's fix it here.
99-
// TODO(alexeykuzmin): This workaround should be removed
100-
// when the `JPEGCodec::Decode()` code is fixed.
101-
// See https://github.com/electron/electron/issues/11294.
102-
decoded->setAlphaType(SkAlphaType::kOpaque_SkAlphaType);
103-
}
104-
}
122+
if (AddImageSkiaRepFromPNG(image, data, size, scale_factor))
123+
return true;
105124

106-
if (!decoded) {
107-
// Try Bitmap
108-
if (width > 0 && height > 0) {
109-
decoded.reset(new SkBitmap);
110-
decoded->allocN32Pixels(width, height, false);
111-
decoded->setPixels(
112-
const_cast<void*>(reinterpret_cast<const void*>(data)));
113-
} else {
114-
return false;
115-
}
116-
}
125+
// Try JPEG second.
126+
if (AddImageSkiaRepFromJPEG(image, data, size, scale_factor))
127+
return true;
117128

118-
image->AddRepresentation(gfx::ImageSkiaRep(*decoded, scale_factor));
129+
if (width == 0 || height == 0)
130+
return false;
131+
132+
auto info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
133+
if (size < info.computeMinByteSize())
134+
return false;
135+
136+
SkBitmap bitmap;
137+
bitmap.allocN32Pixels(width, height, false);
138+
bitmap.setPixels(const_cast<void*>(reinterpret_cast<const void*>(data)));
139+
140+
image->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale_factor));
119141
return true;
120142
}
121143

122-
bool AddImageSkiaRep(gfx::ImageSkia* image,
123-
const base::FilePath& path,
124-
double scale_factor) {
144+
bool AddImageSkiaRepFromPath(gfx::ImageSkia* image,
145+
const base::FilePath& path,
146+
double scale_factor) {
125147
std::string file_contents;
126148
{
127149
base::ThreadRestrictions::ScopedAllowIO allow_io;
@@ -132,7 +154,8 @@ bool AddImageSkiaRep(gfx::ImageSkia* image,
132154
const unsigned char* data =
133155
reinterpret_cast<const unsigned char*>(file_contents.data());
134156
size_t size = file_contents.size();
135-
return AddImageSkiaRep(image, data, size, 0, 0, scale_factor);
157+
158+
return AddImageSkiaRepFromBuffer(image, data, size, 0, 0, scale_factor);
136159
}
137160

138161
bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
@@ -141,12 +164,12 @@ bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
141164
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
142165
if (base::MatchPattern(filename, "*@*x"))
143166
// Don't search for other representations if the DPI has been specified.
144-
return AddImageSkiaRep(image, path, GetScaleFactorFromPath(path));
167+
return AddImageSkiaRepFromPath(image, path, GetScaleFactorFromPath(path));
145168
else
146-
succeed |= AddImageSkiaRep(image, path, 1.0f);
169+
succeed |= AddImageSkiaRepFromPath(image, path, 1.0f);
147170

148171
for (const ScaleFactorPair& pair : kScaleFactorPairs)
149-
succeed |= AddImageSkiaRep(
172+
succeed |= AddImageSkiaRepFromPath(
150173
image, path.InsertBeforeExtensionASCII(pair.name), pair.scale);
151174
return succeed;
152175
}
@@ -422,19 +445,20 @@ void NativeImage::AddRepresentation(const mate::Dictionary& options) {
422445
v8::Local<v8::Value> buffer;
423446
GURL url;
424447
if (options.Get("buffer", &buffer) && node::Buffer::HasInstance(buffer)) {
425-
AddImageSkiaRep(
426-
&image_skia,
427-
reinterpret_cast<unsigned char*>(node::Buffer::Data(buffer)),
428-
node::Buffer::Length(buffer), width, height, scale_factor);
429-
skia_rep_added = true;
448+
auto* data = reinterpret_cast<unsigned char*>(node::Buffer::Data(buffer));
449+
auto size = node::Buffer::Length(buffer);
450+
skia_rep_added = AddImageSkiaRepFromBuffer(&image_skia, data, size, width,
451+
height, scale_factor);
430452
} else if (options.Get("dataURL", &url)) {
431453
std::string mime_type, charset, data;
432454
if (net::DataURL::Parse(url, &mime_type, &charset, &data)) {
433-
if (mime_type == "image/png" || mime_type == "image/jpeg") {
434-
AddImageSkiaRep(&image_skia,
435-
reinterpret_cast<const unsigned char*>(data.c_str()),
436-
data.size(), width, height, scale_factor);
437-
skia_rep_added = true;
455+
auto* data_ptr = reinterpret_cast<const unsigned char*>(data.c_str());
456+
if (mime_type == "image/png") {
457+
skia_rep_added = AddImageSkiaRepFromPNG(&image_skia, data_ptr,
458+
data.size(), scale_factor);
459+
} else if (mime_type == "image/jpeg") {
460+
skia_rep_added = AddImageSkiaRepFromJPEG(&image_skia, data_ptr,
461+
data.size(), scale_factor);
438462
}
439463
}
440464
}
@@ -525,9 +549,9 @@ mate::Handle<NativeImage> NativeImage::CreateFromBuffer(
525549
}
526550

527551
gfx::ImageSkia image_skia;
528-
AddImageSkiaRep(&image_skia,
529-
reinterpret_cast<unsigned char*>(node::Buffer::Data(buffer)),
530-
node::Buffer::Length(buffer), width, height, scale_factor);
552+
AddImageSkiaRepFromBuffer(
553+
&image_skia, reinterpret_cast<unsigned char*>(node::Buffer::Data(buffer)),
554+
node::Buffer::Length(buffer), width, height, scale_factor);
531555
return Create(args->isolate(), gfx::Image(image_skia));
532556
}
533557

spec/api-native-image-spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ describe('nativeImage module', () => {
130130
expect(nativeImage.createFromBuffer(Buffer.from([])).isEmpty())
131131
})
132132

133+
it('returns an empty image when the buffer is too small', () => {
134+
const image = nativeImage.createFromBuffer(Buffer.from([1, 2, 3, 4]), { width: 100, height: 100 })
135+
expect(image.isEmpty()).to.be.true()
136+
})
137+
133138
it('returns an image created from the given buffer', () => {
134139
const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
135140

@@ -450,6 +455,18 @@ describe('nativeImage module', () => {
450455
})
451456

452457
describe('addRepresentation()', () => {
458+
it('does not add representation when the buffer is too small', () => {
459+
const image = nativeImage.createEmpty()
460+
461+
image.addRepresentation({
462+
buffer: Buffer.from([1, 2, 3, 4]),
463+
width: 100,
464+
height: 100
465+
})
466+
467+
expect(image.isEmpty()).to.be.true()
468+
})
469+
453470
it('supports adding a buffer representation for a scale factor', () => {
454471
const image = nativeImage.createEmpty()
455472

0 commit comments

Comments
 (0)