[erlang-bugs] Buffer overflow in etrs_save_mb[]

Matthew Reilly matthew.reilly@REDACTED
Wed Dec 20 23:48:27 CET 2006


Erlang/OTP team,

There is a buffer overflow that can occur in the beam interpreter in
the etrs_save_mb[] array. This can occur if a module contains a large
number of binary matches. This buffer overflow is known to exist for all
Erlang/OTP versions between R10B-6 and R11B-2. Sample code is attached
that causes a SEGV (at least on Linux systems).

The source of the overflow is the opcode "bs_save".

The code in BEAM that interprets this opcode is in
erts/emulator/beam/beam_emu.c:process_main():
 OpCase(bs_save_I): {
     Eterm* next;

     PreFetch(1, next);
     erts_save_mb[Arg(0)] = erts_mb;
     NextPF(1, next);
 }

This saves the current value of "erts_mb" into the array
"erts_save_mb[1024]" at an offset of "Arg(0)". This code does not do
any bounds checking on this array. If a compiled ".beam" file has an
opcode such as "{bs_save,1040}", then the beam interpreter's memory will
be corrupted.

The erlang byte-code compiler can easily generate arguments to "bs_save"
that are greater than 1024. If a module contains matching to static 
binary values, the compiler generates code for each byte in the binaries
such as:
...
    {bs_save,1040}.
    {test,is_eq_exact,{f,1},[{x,12},{integer,21}]}.
    {bs_restore,1040}.
...
    {bs_save,1041}.
    {test,is_eq_exact,{f,1},[{x,13},{integer,182}]}.
    {bs_restore,1041}.
...

Even though the saved value is never referenced again, the compiler
increments the arg to "bs_save" and it does so without checking if the
argument exceeds the size of the "erts_save_mb[]" array.

I have not tried this code with HiPE, but since HiPE uses the function
erts/emulator/beam/erl_bits.c:erts_bs_save() (which also does not check
the bounds of erts_save_mb), it most likely has the same bug:
void erts_bs_save(ERL_BITS_PROTO_1(int index))
{
    erts_save_mb[index] = erts_mb;
}


Most likely, to avoid this bug:

- the compiler should re-use args to "bs_save" (especially where it
immediately does a "bs_restore") instead of just incremented it each
byte.

- the beam runtime should check the offsets for "bs_save" at beam file
load time to make sure it is < MAX_REG (perhaps in beam_validator?)


Thank you,
Matt Reilly
SIPphone Inc.

%%%%%%%%%%%% Begin buffer_overflow.erl %%%%%%%%%%%%%
%% Test with:
%% $ erlc buffer_overflow.erl
%% $ erl -s buffer_overflow crash
-module(buffer_overflow).

-export([
    crash/0
]).

m(<<196,202,66,56,160,185,35,130,13,204,80,154,111,117,132,155>>) -> 1;
m(<<200,30,114,141,157,76,47,99,111,6,127,137,204,20,134,44>>) -> 2;
m(<<236,203,200,126,75,92,226,254,40,48,143,217,242,167,186,243>>) -> 3;
m(<<168,127,246,121,162,243,231,29,145,129,166,123,117,66,18,44>>) -> 4;
m(<<228,218,59,127,187,206,35,69,215,119,43,6,116,163,24,213>>) -> 5;
m(<<22,121,9,28,90,136,15,175,111,181,230,8,126,177,178,220>>) -> 6;
m(<<143,20,228,95,206,234,22,122,90,54,222,221,75,234,37,67>>) -> 7;
m(<<201,240,248,149,251,152,171,145,89,245,31,208,41,126,35,109>>) -> 8;
m(<<69,196,140,206,46,45,127,189,234,26,252,81,199,198,173,38>>) -> 9;
m(<<211,217,68,104,2,164,66,89,117,93,56,230,209,99,232,32>>) -> 10;
m(<<101,18,189,67,217,202,166,224,44,153,11,10,130,101,45,202>>) -> 11;
m(<<194,10,212,215,111,233,119,89,170,39,160,201,155,255,103,16>>) ->12;
m(<<197,28,228,16,193,36,161,14,13,181,228,185,127,194,175,57>>) -> 13;
m(<<170,179,35,137,34,188,194,90,111,96,110,181,37,255,220,86>>) -> 14;
m(<<155,243,28,127,240,98,147,106,150,211,200,189,31,143,47,243>>) ->15;
m(<<199,77,151,176,30,174,37,126,68,170,157,91,173,233,123,175>>) -> 16;
m(<<112,239,223,46,201,176,134,7,151,149,196,66,99,107,85,251>>) -> 17;
m(<<111,73,34,244,85,104,22,26,140,223,74,210,41,159,109,35>>) -> 18;
m(<<31,14,61,173,153,144,131,69,247,67,159,143,250,189,255,196>>) -> 19;
m(<<152,241,55,8,33,1,148,196,117,104,123,230,16,106,59,132>>) -> 20;
m(<<60,89,220,4,142,136,80,36,59,232,7,154,92,116,208,121>>) -> 21;
m(<<182,215,103,210,248,237,93,33,164,75,14,88,134,104,12,185>>) -> 22;
m(<<55,105,60,252,116,128,73,228,93,135,184,199,216,185,170,205>>) ->23;
m(<<31,241,222,119,64,5,248,218,19,244,41,67,136,28,101,95>>) -> 24;
m(<<142,41,106,6,122,55,86,51,112,222,208,95,90,59,243,236>>) -> 25;
m(<<78,115,44,237,52,99,208,109,224,202,154,21,182,21,54,119>>) -> 26;
m(<<2,231,79,16,224,50,122,216,104,209,56,242,180,253,214,240>>) -> 27;
m(<<51,231,95,240,157,214,1,187,230,159,53,16,57,21,33,137>>) -> 28;
m(<<110,169,171,27,170,14,251,158,25,9,68,64,195,23,226,27>>) -> 29;
m(<<52,23,60,179,143,7,248,157,219,235,194,172,145,40,48,63>>) -> 30;
m(<<193,106,83,32,250,71,85,48,217,88,60,52,253,53,110,245>>) -> 31;
m(<<99,100,211,240,244,149,182,171,157,207,141,59,92,110,11,1>>) -> 32;
m(<<24,43,224,197,205,205,80,114,187,24,100,205,238,77,61,110>>) -> 33;
m(<<227,105,133,61,247,102,250,68,225,237,15,246,19,245,99,189>>) -> 34;
m(<<28,56,60,211,11,124,41,138,181,2,147,173,254,203,123,24>>) -> 35;
m(<<25,202,20,231,234,99,40,164,46,14,177,61,88,94,76,34>>) -> 36;
m(<<165,191,201,224,121,100,248,221,222,185,95,197,132,205,150,93>>)->37;
m(<<165,119,27,206,147,226,0,195,111,124,217,223,208,229,222,170>>)->38;
m(<<214,125,138,180,244,193,11,242,42,163,83,226,120,121,19,60>>) -> 39;
m(<<214,69,146,14,57,95,237,173,123,187,237,14,202,63,226,224>>) -> 40;
m(<<52,22,167,95,76,234,145,9,80,124,172,216,226,242,174,252>>) -> 41;
m(<<161,208,198,232,63,2,115,39,216,70,16,99,244,172,88,166>>) -> 42;
m(<<23,230,33,102,252,133,134,223,164,209,188,14,23,66,192,139>>) -> 43;
m(<<247,23,113,99,200,51,223,244,179,143,200,210,135,47,30,198>>) -> 44;
m(<<108,131,73,204,114,96,174,98,227,177,57,104,49,168,57,143>>) -> 45;
m(<<217,212,244,149,232,117,162,224,117,161,164,166,225,185,119,15>>)->46;
m(<<103,198,161,231,206,86,211,214,250,116,138,182,217,175,63,215>>)->47;
m(<<100,46,146,239,183,148,33,115,72,129,181,62,30,27,24,182>>) -> 48;
m(<<244,87,197,69,169,222,216,143,24,236,238,71,20,90,114,192>>) -> 49;
m(<<192,199,199,109,48,189,61,202,239,201,111,64,39,91,220,10>>) -> 50;
m(<<40,56,2,58,119,141,250,236,220,33,39,8,247,33,183,136>>) -> 51;
m(<<154,17,88,21,77,250,66,202,221,189,6,148,164,233,189,200>>) -> 52;
m(<<216,44,141,22,25,173,129,118,214,101,69,60,251,46,85,240>>) -> 53;
m(<<166,132,236,238,231,111,197,34,119,50,134,168,149,188,132,54>>)->54;
m(<<181,59,58,61,106,185,12,224,38,130,41,21,28,155,222,17>>) -> 55;
m(<<159,97,64,142,58,251,99,62,80,205,241,178,13,230,244,102>>) -> 56;
m(<<114,179,42,31,117,75,161,192,155,54,149,224,203,108,222,127>>) ->57;
m(<<102,240,65,225,106,96,146,139,5,167,226,40,168,156,55,153>>) -> 58;
m(<<9,63,101,224,128,162,149,248,7,107,28,87,34,164,106,162>>) -> 59;
m(<<7,43,3,11,161,38,178,244,178,55,79,52,43,233,237,68>>) -> 60;
m(<<127,57,248,49,127,189,177,152,142,244,198,40,235,160,37,145>>) ->61;
m(<<68,246,131,168,65,99,179,82,58,254,87,194,224,8,188,140>>) -> 62;
m(<<3,175,219,214,110,121,41,177,37,248,89,120,52,250,131,164>>) -> 63;
m(<<234,93,47,28,70,8,35,46,7,211,170,61,153,142,81,53>>) -> 64;
m(<<252,73,12,164,92,0,177,36,155,190,53,84,164,253,246,251>>) -> 65;
m(<<50,149,199,106,203,244,202,174,211,60,54,177,181,252,44,177>>) ->66;
m(<<115,91,144,180,86,129,37,237,108,63,103,136,25,182,224,88>>) -> 67;
m(<<163,243,144,216,142,76,65,242,116,123,250,47,27,95,135,219>>) -> 68;
m(<<20,191,166,187,20,135,94,69,187,160,40,162,30,211,128,70>>) -> 69;
m(<<124,187,196,9,236,153,15,25,199,140,117,189,30,6,242,21>>) -> 70;
m(<<226,196,32,217,40,212,191,140,224,255,46,193,155,55,21,20>>) -> 71;
m(<<50,187,144,232,151,106,171,82,152,213,218,16,254,102,242,29>>) ->72;
m(<<210,221,234,24,240,6,101,206,134,35,227,107,212,227,199,197>>) ->73;
m(<<173,97,171,20,50,35,239,188,36,199,210,88,59,230,146,81>>) -> 74;
m(<<208,155,244,21,68,163,54,90,70,201,7,126,187,94,53,195>>) -> 75;
m(<<251,215,147,157,103,73,151,205,180,105,45,52,222,134,51,196>>) ->76;
m(<<40,221,44,121,85,206,146,100,86,36,11,47,240,16,11,222>>) -> 77;
m(<<53,244,168,212,101,230,225,237,192,95,61,138,182,88,197,81>>) -> 78;
m(<<209,254,23,61,8,233,89,57,122,223,52,177,215,126,136,215>>) -> 79;
m(<<240,51,171,55,195,2,1,247,63,20,36,73,208,55,2,141>>) -> 80;
m(<<67,236,81,125,104,182,237,211,1,91,62,220,154,17,54,123>>) -> 81;
m(<<151,120,213,210,25,197,8,11,154,106,23,190,240,41,51,28>>) -> 82;
m(<<254,159,194,137,195,255,10,241,66,182,211,190,173,152,169,35>>)->83;
m(<<104,211,10,149,148,114,139,195,154,162,75,233,75,49,157,33>>) -> 84;
m(<<62,248,21,65,111,119,80,152,254,151,112,4,1,92,97,147>>) -> 85;
m(<<147,219,133,237,144,156,19,131,143,249,92,207,169,76,235,217>>)->86;
m(<<199,225,36,159,252,3,235,157,237,144,140,35,107,209,153,109>>) ->87;
m(<<42,56,164,169,49,108,73,229,168,51,81,124,69,211,16,112>>) -> 88;
m(<<118,71,150,107,115,67,194,144,72,103,50,82,228,144,247,54>>) -> 89;
m(<<134,19,152,94,196,158,184,247,87,174,100,57,232,121,187,42>>) -> 90;
m(<<84,34,154,191,207,165,100,158,112,3,184,61,212,117,82,148>>) -> 91;
m(<<146,204,34,117,50,209,126,86,224,121,2,178,84,223,173,16>>) -> 92;
m(<<152,220,232,61,165,123,3,149,225,99,70,124,157,174,82,27>>) -> 93;
m(<<244,185,236,48,173,159,104,248,155,41,99,151,134,203,98,239>>) ->94;
m(<<129,43,75,162,135,245,238,11,201,212,59,191,91,190,135,251>>) -> 95;
m(<<38,101,125,95,249,2,13,42,190,254,85,135,150,185,149,132>>) -> 96;
m(<<226,239,82,79,191,61,159,230,17,213,168,233,15,239,220,156>>) -> 97;
m(<<237,61,44,33,153,30,59,239,94,6,151,19,175,159,166,202>>) -> 98;
m(<<172,98,122,177,204,189,182,46,201,110,112,47,7,246,66,91>>) -> 99;
m(<<248,153,19,157,245,225,5,147,150,67,20,21,231,112,198,221>>) -> 100.

crash() ->
    lists:foreach(
        fun(N) ->
            io:format("Trying to match md5(~B)~n",[N]),
            BinaryToMatch = erlang:md5(integer_to_list(N)),

            %% The pattern matching on binaries for this call
            %% will cause buffer overflow.
            m(BinaryToMatch)
        end,
        lists:seq(1,100)
    ).
%%%%%%%%%%%% End buffer_overflow.erl %%%%%%%%%%%%%

-- 
Matthew Reilly
SIPphone Inc.
matthew.reilly@REDACTED
Gizmo Project name: matt 




More information about the erlang-bugs mailing list