Talos security advisory for Blender product (TALOS-2017-0451)
Open, NormalPublic


System Information
Operating system and graphics card

Blender Version
Tested Versions - Blender v2.78c (32-bit)

Short description of error Files sent via separate communication including report
Exact steps for others to reproduce the error
Based on a (as simple as possible) attached .blend file with minimum amount of steps



I guess there's some internal emails for you to look at?

LazyDodo (LazyDodo) triaged this task as Normal priority.Sep 27 2017, 8:23 PM

I have all the information in a private mail. It's quite interesting and elaborately documented.
It also includes a .blend that would (i guess) create an exploit. Will send that to the hardcore devs here in private

Thanks for your response/review. Look forward to hearing any feedback/new developments.

Just for everyone's interest, this is part of the report in the mail.

2017-MM-DD (published patch date)

Blender multires_load_old_dm base vertex map Integer Overflow Code Execution Vulnerability


An exploitable integer overflow exists in the multires_load_old_dm functionality of the Blender open-source 3d creation suite v2.78c. A specially crafted .blend file can cause an integer overflow resulting in a buffer overflow which can allow for code execution under the context of the application. An attacker can convince a user to open a .blend file in order to trigger this vulnerability.

Tested Versions

Blender v2.78c (32-bit)

Product URLs


CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H


CWE-190 - Integer Overflow or Wraparound


Blender is a professional, open-source 3d computer graphics application. It is used for creating animated films, visual effects, art, 3d printed applications, and video games. It is also capable of doing minimalistic video editing and sequencing as needed by the user. There are various features that it provides which allow for a user to perform a multitude of actions as required by a particular project.

This vulnerability occurs when loading an old Multires structure from a Mesh into a newer format. When handling an older version of a .blend file, the application will call a function to initialize the base vertices used for multi-resolution meshes. When allocating space for these vertices, the application will use the total number of vertices in some arithmetic which can overflow. This will then be used to perform an allocation which can be made to be smaller than the total number of vertices used to initialize an array. When initializing this array, the application can then write outside the bounds of the array which causes a heap-based buffer overflow.

After loading all the basic-blocks in a file, the application will call the blo_do_versions_250 function. This function will check the version of the file as specified in the FileGlobals structure and use it to perform various transformations on the data-structures in the file in order to provide backwards compatibility. At [1], the application will check if the version is less than or equal to 250 and that the subversionfile field is less than 1 (exclusive). After this is verified, the application will iterate through all the Object data-blocks in the file and at [2] check to see if its type field is set to OB_MESH(1). If so, then the object and its associated Mesh that's pointed to by the data field is then passed the multires_load_old function at [3].

void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
    if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 1)) {    // [1]
        for (ob = main->object.first; ob; ob = ob->id.next) {
            if (ob->type == OB_MESH) {                                                          // [2]
                Mesh *me = blo_do_versions_newlibadr(fd, lib, ob->data);
                void *olddata = ob->data;
                ob->data = me;
                if (me && me->id.lib == NULL && me->mr && me->mr->level_count > 1) {
                    multires_load_old(ob, me);                                                  // [3]

                ob->data = olddata;

Once inside the multires_load_old function, at [4] the application will assign a pointer to a Multires structure from the Mesh structure's mr field. Dereferencing the levels field results in a MultiresData structure that contains a number of fields that are re-assigned to the Mesh structure. In these fields, the value of totvert is significant to note as it is used to trigger this vulnerability. Once re-assigning the fields at [5], the application will then convert the faces defined by the Mesh into polygons which is then used to create a DerivedMesh object. This and the Mesh itself are passed as arguments to multires_load_old_dm at [6].

void multires_load_old(Object *ob, Mesh *me)
    lvl = me->mr->levels.first;                     // [4]
    me->totvert = lvl->totvert;
    me->totedge = lvl->totedge;
    me->totface = lvl->totface;

    /* multiresModifier_subdivide (actually, multires_subdivide) expects polys, not tessfaces! */
    BKE_mesh_convert_mfaces_to_mpolys(me);          // [5]
    orig = CDDM_from_mesh(me);
    dm = multires_make_derived_from_derived(orig, mmd, ob, 0);

    multires_load_old_dm(dm, me, mmd->totlvl + 1);  // [6]

The multires_load_old_dm function is responsible for converting the old Multires-formatted structure into its newer format. At [7], the application will assign the mr field belonging to the Mesh to a pointer. At [8], the application will extract the total number of vertices defined within the DerivedMesh that was made earlier using the fields from the Mesh structure and assign the result to the totvert variable. Once this is done, at [9] the application will use this variable to calculate a product using the size of an int (4) with the number of vertices and pass this as a size for an allocation. If the result of this arithmetic has a result larger than a 32-bit number, then this allocation will overflow resulting in an undersized buffer. At [10], when the application attempts to initialize this array, the application will use the difference between the total number of vertices in the first MultiresData and the total number of vertices in the second MultiresData from the file to write into the array. During this, an out-of-bounds write can occur resulting in a heap-based buffer overflow. Within the provided proof-of-concept, the value used for the level 1 totvert field is 1. This type of overwrite can allow for code execution within the context of the application.

static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
    MultiresLevel *lvl, *lvl1;
    Multires *mr = me->mr;                                          // [7]
    vsrc = mr->verts;
    vdst = dm->getVertArray(dm);
    totvert = (unsigned int)dm->getNumVerts(dm);                    // [8]
    vvmap = MEM_callocN(sizeof(int) * totvert, "multires vvmap");   // [9]

    lvl1 = mr->levels.first;
    /* Load base verts */
    for (i = 0; i < lvl1->totvert; ++i) {
        vvmap[totvert - lvl1->totvert + i] = src;                   // [10]

Crash Information

(2a50.2a9c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000001 ecx=00000002 edx=328d6ffc esi=329c6fd4 edi=02da1710
eip=014aa00b esp=002fe8f8 ebp=002fe968 iopl=0         nv up ei pl nz na po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010203
014aa00b 891c82          mov     dword ptr [edx+eax*4],ebx ds:002b:328d7000=????????

0:000> !heap -p -a @edx
    address 328d6ffc found in
    _DPH_HEAP_ROOT @ 4a1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                328612a4:         328d6ff8                4 -         328d6000             2000
    6b7e8d9c verifier!AVrfDebugPageHeapAllocate+0x0000023c
    77d6fb79 ntdll!RtlDebugAllocateHeap+0x00000032
    77d09a73 ntdll!RtlpAllocateHeap+0x0003914a
    77cd0b43 ntdll!RtlAllocateHeap+0x0000014c
    0292f5b3 blender!xmlGetThreadId+0x0000c0b3
    02915fc1 blender!xmlListWalk+0x00223241
    017cd129 blender!osl_texture_set_swrap_code+0x00171e99
    014a9fe2 blender!PyInit_mathutils_noise_types+0x0028b562
    014a9dbb blender!PyInit_mathutils_noise_types+0x0028b33b
    013681b4 blender!PyInit_mathutils_noise_types+0x00149734
    013582f0 blender!PyInit_mathutils_noise_types+0x00139870
    0134ee74 blender!PyInit_mathutils_noise_types+0x001303f4
    01361989 blender!PyInit_mathutils_noise_types+0x00142f09
    01401fab blender!PyInit_mathutils_noise_types+0x001e352b
    00e6ddca blender!xmlFileMatch+0x000078fa
    00e6e88f blender!xmlFileMatch+0x000083bf
    00e6f7b1 blender!xmlFileMatch+0x000092e1
    00e7bd3f blender!xmlFileMatch+0x0001586f
    00e7c8c5 blender!xmlFileMatch+0x000163f5
    00e7c4a6 blender!xmlFileMatch+0x00015fd6
    00e7abfa blender!xmlFileMatch+0x0001472a
    00e6c583 blender!xmlFileMatch+0x000060b3
    00e69b1b blender!xmlFileMatch+0x0000364b
    0290a125 blender!xmlListWalk+0x002173a5
    75f7919f KERNEL32!BaseThreadInitThunk+0x0000000e
    77cda8cb ntdll!__RtlUserThreadStart+0x00000020
    77cda8a1 ntdll!_RtlUserThreadStart+0x0000001b

0:000> lm a blender.exe
Browse full module list
start    end        module name
00cd0000 04638000   blender  C (export symbols)       blender.exe

Exploit Proof-of-Concept

Included with this advisory is a generator for the vulnerability. This proof-of-concept requires python and takes a single-argument which is the filename to write the .blend file to.

$ python poc.py.zip $FILENAME.blend

To trigger the vulnerability, one can simply open the file or use it as a library. It can also be passed as an argument to the blender executable.

$ /path/to/blender.exe $FILENAME.blend


In order to mitigate this vulnerability, it is recommended to not use untrusted blender files.


Discovered by a member of Cisco Talos.


YYYY-MM-DD - Vendor Disclosure
YYYY-MM-DD - Public Release

There are a total of 19 issues outstanding. Are there any additional updates for the following:

Ton Roosendaal (ton) added a comment.EditedNov 7 2017, 7:42 PM

The Cisco team keeps mailing me in private about this. I really don't mind a public discussion.

I wrote:

The discussion on this topic can be done in public.
What I heard however, is that the vulnerability is an extreme theoritical case, not something that would happen in an end-user case.

Cisco reply:

All 21 vulnerabilities that we reported have proof of concepts that trigger the vulnerability and result in a crash, I would say that's pretty far from theoretical. Obviously an attacker would need to do some more work to turn the crashes
into an actual exploit that executes code, but that is not simply theoretical.

My reply:

Sorry for being unclear. I mean that the situations are not practical; as in, created in a practical situation of using Blender.
The vulnerabilities are "theoretical" as in "unlikely to happen, only by purposed sabotage".

That being said, it's not something we ignore, but the investment of resources (using volunteers?!) in fixing this, would not really justify the benefits.
Would you help us fixing this?

So exploits are unlikely to be created accidentally by using Blender. What we're saying is that if an attacker purposefully creates a malicious file that a user then loads, that user could be compromised. The vulnerabilities exist not only in .blend files, but also in BMP, TIFF and other file formats supported by Blender.

Realistically, Blender is not well protected against these kinds of attacks, and the same is true for other CG software (often you can run arbitrary embedded scripts on file load, which Blender at least prevents). Anyone capable of exploiting these reported vulnerabilities can find 10 more in Blender and its library dependencies. As far as I'm concerned, opening a file with Blender should be considered like opening a file with the Python interpreter, you have the trust to the source it is coming from.

CG artists might not be aware of this and that's a problem, but fixing these issues one by one is also a waste of time in my opinion. You'd need to completely review the code and architecture to get anywhere near real security, and I don't see that happening soon for Blender, or similar CG software for that matter.

Ton Roosendaal (ton) added a comment.EditedFri, Jan 12, 7:36 PM

Cisco wrote this yesterday:

For the record - a day after Brecht's reply I talked to a Cisco engineer who offered to help us with it.
Brecht is speaking here on his own terms, as one of the core team members but it's not an official Blender Foundation statement that we don't take these vulnerabilities seriously. There are just no simple or easy answers.

@Yves Younan (yyounan) now that they are published and I wouldn't mind taking a quick peek (I'm not with the BF, had no access before). Most of the reports mention

Included with this advisory is a generator for the vulnerability.

but I don't think they made it onto the website? anything you can do there?

Right, I am not speaking for the Blender Foundation. Nor am I saying vulnerabilities should not be taken seriously, but rather that if anyone is serious about making loading arbitrary .blend files in Blender secure, fixing these issues reported by TALOS will not get us much closer to that. Users should understand that loading untrusted scene files in Blender and other CG software is not currently secure, and not get the false impression that software developers addressing the occasional reported issue means it will be secure.

For background on security and arbitrary code execution in CG software in general, see here:

(Also not speaking for the Blender Foundation)

Thinking what could be the solution could be here, since currently a blend file is basically a memory dump which has few validation checks on load.


  • Keep blend file loading fast for the common case (When "Trusted Source" is enabled).
  • When "Trusted Source" is disabled, run extra validation code on the blend file... checking everything from.
    • Edge/loop/polygon vertex ranges (that all indices are in valid ranges, unless they're bounds checked at run-time)
    • That allocated memory is the expected size (Mesh.mvert length is consistent with Mesh.totvert for eg).
    • That strings are null terminated (with a few exceptions where it's not needed).
  • Recovering gracefully from these errors doesn't have to be a priority - any data with an error can be removed for eg, Loading the file could abort... or worst case Blender could exit (although I'd rather avoid that).

It would not be so hard to setup a fuzzer that uses existing Blend files in our test repository, injecting errors, which runs as part of a test, using tools such as ASAN / Valgrind to detect errors.

One area I think might end up being difficult to solve well is making sure partially loaded files don't have errors with invalid data - making sure versioning code can optionally perform these extra checks too.

Nevertheless - validating a blend file once it's loaded could be a first step, other issues could be handled on a case-by-case basis.

  • Note that I generally agree with Brecht's comments, just suggesting how this might be handled.
  • This could be investigated in a branch, it won't touch too many files for the fuzzing-tests + post-load-validation.
  • Once in a while we get bug reports containing corrupt files, so there is some use for this as a way to recover data. OTOH there is a limit to what we can reasonably recover depending on the kind of corruption.
  • On the down-side it's possible this ends up being a fools errand (where we can't even get close to resolving 100% of the the errors exposed by fuzzing - spending time trying to fix hypothetical errors which could be better spent investigating bugs users are actually experiencing)

I agree it would be good to validate .blend file contents, in the generic ways that you mention it probably wouldn't add too much code complexity? The tricky part is the more complex data relations, mesh being the primary one for which we already have a validation function, but there's other ones which could be corrupted too (particles, curves, node trees, ..).

There's vulnerabilities after .blend file loading as well, if you can create a modifier setup that crashes for example, or can make a memory allocation fail in code that doesn't check if malloc returns NULL, ... .

I think the security issues in image file loading are probably the important thing to fix first, since those are generally expected to be safe to load. Maybe updating to the latest library versions for all our dependencies. But note that for example even the latest OpenEXR release has issues too:

Right, making data which doesn't crash but is logically invalid is a problem, although I'm not sure these are security issues.

  • Linked list that's circular.
  • Null pointers that are expected to be valid (Object.data for Meshes for eg).
  • Modifiers or configurations that allocate more memory than is available.

AFAIK these could cause infinite loops or crash on NULL pointer access *. but aren't bugs that expose Blender to attacks.

\* If it's indexed it could be used to exploit I'd imagine.

Right, what I mean is that invalid data that slips through .blend file loading could cause crashes later on, because the code generally assumes it to be valid and what happens when it isn't is unpredictable. And also technically valid data can cause problems.

For example an attacker could stuff executable code in mesh vertex coordinates (which can be arbitrary bits), and as a result all mesh processing code would need to be checked for buffer overflows, in modifiers, rendering, etc. I'm not sure what kind of severity such crashes would be assigned, but it's not obvious to me that they would be harder to exploit than the multires issue described in T52924#462765.

And to be a bit more explicit: if I had to guess, then I estimate that seriously securing Blender against these types of attacks would take at least 4 developers working full time for 2 years. Which is not an argument against addressing vulnerabilities, but just to give an idea of the cost.

I thought that the main culprit was that we allow memory size be calculated without checks for integer overflows.
A way to fix is it to use a malloc function that accepts two args (how calloc() does it) and to make an integer mult function with boundary checks.

And: get a GSoC student to help with it :)

The reported vulnerabilities indeed are all based on cases where there is some overflow in computing the size for memory allocation, and which can be triggered by changing an integer in the file.

While it's fine to address issues raised in these reports - the errors found were using an automated tool, in some ways it's not so different from this kinds of reports (T18799 T39858) just more detailed.

Anyone looking could probably find as many buffer overrun bugs in blend file loading code (unterminated strings in the blend file for eg).
There are quite a few places that could be used for intentional stack smashing.

While all kinds of security risks should be taken seriously, it seems odd only to bother fixing issues with CVE's, when other kinds of errors aren't hard to spot in the code.

Indeed, that's the point I was trying to make in T52924#469725. In my opinion there is nothing we can do to fundamentally improve .blend file loading security against these types of (difficult and somewhat unlikely) attacks in the short term. Ironically, if we had worse security and allowed executing embedded scripts on load by default as a feature, like other software, then these wouldn't really be vulnerabilities.

However there's some practical issues like FreeBSD giving build errors when a package version has open CVEs, and just the fact that it looks bad. For image files at least we can consider any known issues important to fix. So we might as well get the CVEs fixed for 2.79a I think.

@Brecht Van Lommel (brecht) the time you posted, I didn't realize these were found with an automatic detection method.

Some additional comments:

  • The buffer overruns I listed above are in fact quite crappy code and *could* lead to crashes (in practice they it's unlikely), good to solve still - but not priority.
  • We use an old OpenJPEG 1.5.2 (current version is 2.3). See CVE's I've upgraded the library in temp-openjpeg23 branch. Last time we looked into using the new library there was a conflict with OpenImageIO. Not sure if it's resolved now.

oiio will build against openjpeg 2.x, however when updating the openjpeg in /extern we'll also have to update (atleast for windows) the oiio/openjpeg libs in svn so this upgrade will have to be coordinated with the platform teams.

The image related CVEs reported here are now fixed.

Our libpng, libjpeg and openexr versions also have open CVEs, and possibly other libraries. I've created D3005 for these image library updates, but I doubt we can get this done for 2.79a.

We now have fixes for the other vulnerabilities in .blend file loading ass well.

While the specific overflow issue may be fixed, loading the repro .blend files may still crash because they are incomplete and corrupt. The way they crash may be impossible to exploit, but this is difficult to prove. As already mentioned, making loading of malicious .blend files safe in general would be a huge project, so that was never going to happen in the short term.

@Brecht Van Lommel (brecht) What I need to look for/change in greasepencil-object branch to apply these fixes?

As this branch was not part of your update patch, I would like to apply the fix before merge to 2.8 and avoid add new vulnerabilities when the merge will be done.

Merge with blender2.8 as you were already doing, and use MEM_malloc_arrayN() functions in new code. But note that we did not use these functions in all of Blender yet, just a few parts related to the reports. So even if the grease pencil code did not use them, that wouldn't make much difference.

Was it done on purpose that the vulnerability fixes have been pushed to the branch blender-v2.79-release and not blender-v2.79a-release?

This comment was removed by marc dion (marcclintdion).

Was it done on purpose that the vulnerability fixes have been pushed to the branch blender-v2.79-release and not blender-v2.79a-release?

Thanks for catching that, fixed now.