Open Bug 1902439 Opened 9 months ago Updated 16 hours ago

Missing status checks in WriteBitmap()

Categories

(Firefox :: Shell Integration, defect, P3)

defect

Tracking

()

ASSIGNED

People

(Reporter: mozillabugs, Assigned: jilvin)

Details

(Keywords: good-first-bug)

Attachments

(1 file)

WriteBitmap() (browser/components/shell/nsWindowsShellService.cpp) fails to check the status of nsIOutputStream::Write(). This means that if Write() fails, WriteBitmap() writes a malformed bitmap file to disk without detecting that fact. These files are used by nsWindowsShellService::SetDesktopBackground() to implement the "Set image as desktop background" context menu item. Thus, any exploit would have to involve some defect in Windows.

The bug that really matters is on line 473: if Write() writes the first row successfully (thus setting written to bytesPerRow), any combination of the following rows can fail without changing the value of written, thus spuriously causing the function to conclude that it successfully wrote the file.

You can verify that this is so by using a debugger to trace a Write() call down to where _PR_MD_WRITE() calls the Windows API WriteFile(), then manually skipping that call and setting rv == 0 (as WriteFile() does on failure), then tracing back out to WriteBitmap().

Code from FIREFOX_126_0_RELEASE:

    406: static nsresult WriteBitmap(nsIFile* aFile, imgIContainer* aImage) {
    407:   nsresult rv;
    460:   // write the bitmap headers and rgb pixel data to the file
    461:   rv = NS_ERROR_FAILURE;
    462:   if (stream) {
    463:     uint32_t written;
    464:     stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
    465:     if (written == sizeof(BITMAPFILEHEADER)) {
    466:       stream->Write((const char*)&bmi, sizeof(BITMAPINFOHEADER), &written);
    467:       if (written == sizeof(BITMAPINFOHEADER)) {
    468:         // write out the image data backwards because the desktop won't
    469:         // show bitmaps with negative heights for top-to-bottom
    470:         uint32_t i = map.mStride * height;
    471:         do {
    472:           i -= map.mStride;
    473:           stream->Write(((const char*)map.mData) + i, bytesPerRow, &written);
    474:           if (written == bytesPerRow) {
    475:             rv = NS_OK;
    476:           } else {
    477:             rv = NS_ERROR_FAILURE;
    478:             break;
    479:           }
    480:         } while (i != 0);
    481:       }
    482:     }
    483: 
    484:     stream->Close();
    485:   }
    ...
    489:   return rv;
    490: }

There is also a similar bug in WinUtils::WriteBitmap(nsIFile* , SourceSurface* ) (widget/windows/WinUtils.cpp) but searchfox says that only WinUtils::WriteBitmap(nsIFile*, imgIContainer*) calls that, and that nothing calls WinUtils::WriteBitmap(nsIFile*, imgIContainer*).

Flags: sec-bounty?

Thanks for the report. This is obviously a bug, but it doesn't strike me as having security implications. Our sec review team will evaluate.

Agreed, functional bug but not an exploit.

Group: firefox-core-security

Hi! It looks to me as if the easiest fix would be to move the FileDescriptorOutputStream.cpp#50 one line up and use the resulting negative epsilon as not so magic number. Rewriting to handle the return type NS_ERROR_FAILURE would be nicer though.

Severity: -- → S4
Keywords: good-first-bug
Priority: -- → P3
Flags: sec-bounty? → sec-bounty-
Assignee: nobody → jilvinjacob
Status: NEW → ASSIGNED

This good-first-bug hasn't had any activity for 2 months, it is automatically unassigned.
For more information, please visit BugBot documentation.

Assignee: jilvinjacob → nobody
Status: ASSIGNED → NEW

Bad bot.

Assignee: nobody → jilvinjacob
Status: NEW → ASSIGNED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: