┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
| @@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@     + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@ @   @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@ @    @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@ @      @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@ @@   @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@ @@   @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@.@@@@ @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@ @@@   @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@ @@@@  @@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@ @@@        @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@  @@     @@   @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@ @@@@         @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         @@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@ @@@        @@  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @  @@@@@@@@@# @@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@ @@@        @@@  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   @@   @@@@@@@@@@@@ @@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@ @@@           @  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# @@@@@     @@@  @@@@@@@@  @@@@@@@@@ |
| @@@@@@@@@@@@@@@@ @@@#           @  @@@+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      @@  @@@@@@      @@@@@@ @@@@@@@@@ |
| @@@@@@@@@@@@@@@@ @@@@            @@ @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ :    @@@@@@@@@          @@@@ @@@@@@@@ |
| @@@@@@@@@@@@@@@@@ @@@ @           @@  @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @* @ *  @@@@@@@@             @@@ @@@@@@@@ |
| @@@@@@@@@@@@@@@@@@ @@             @@@   @@ =@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @    @@ @@@@@@@@@@    @ = @@@   @@@ @@@@@@@ |
| @@@@@@@@@@@@@@@@@@@ @@            %@@@@  @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     @    :@@@@@@ #    @  @@@@  @@ @@@ @@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@ @@ #         @@@@@@ @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#   @@        @@@ @    @ @@@@@@@@@ @ @@@ @@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@ @@            @@@@  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ @@  @ @@  @@@    =@ @@@@@@@@@@@@   @@ @@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@ @@@@          @@@@  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@   @  @@      @ @@@@@@@@@@@@@@   @ @@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@ @             @@@@ @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@      @@    @  @@@@@@@@@@@@@@@@  @ @@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@ @@           =@@@@  @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@    @@@@@@@  @ @@@@@@@@@@@@@@@@@@@  @@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@ @@             @@@@ @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@      @@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@ @@            @@@@@  @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@      @@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@ @              @@@@@ @@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@      @@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@ @               @@@@  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@     @@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@              @@@@@@ @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@     @@@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@ @              @@@@@  @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@ @@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @               @@@  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@   @@@@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @               @@@  @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@   @@@@@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @              @@@   @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@   @@@@@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@* @              @@@   @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@   @@@@@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@              @@@@  @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@ @@@@@@@   @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@               @@@   @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@:@   @@@@@ @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @ #               @    @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@   @@@@@@   @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @   =            @@@   @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@       @@@  @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@               @@    @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@       @@  @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@              @@    @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+ @@@@        @  @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@:                 @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@           @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @ @   @@       @@     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@      =@- @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@  -@            @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@      @  .@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@+@  @@@          @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@  @@  @@ @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@    @@          @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@  @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@     @@         @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@= @@@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@   @@@         @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@   @@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @    @@@       @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @    @@@ @@   @@  @@@@@@@@@@@@@@@      *@@@@   @@@@@@@@@@@@ @  @@@ @@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@       @   @@@  @@@@@@@@@    @@@@@@@@@@@@@@@@@   @@@@@@ @ @@   @@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@    @:%    @@   @@   @@@@@@@@@@@@@@@@@@@@@@@@@@@@    @    @   @@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@   @@@@   @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@ @       @@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@         @@@@@@@@@@@@  @ @      @  @@@    @@@@ @@    @@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@   @@@ @%   @@@@  @ @                          @@@@ @@ @@@@@ @@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@  @       @@@@@ @                             @@@   @ @@@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   @@ @   @@   @@@@@@                          @@# @@@@@*  @@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@     @@@@@@@@@@@@@@                         @@  @@@   @@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@    @@@@@@@@@@@@@@@@@    @@* @               :@@@    @@@@@@   @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@    @ @@@@@@@@@@@@@@@  @@                   @@@    @@@@@@%@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@     @@@   @@@@@@@@@@@@                        @ @@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@  +%@@@@@   @@@@@@@@@                   @     @@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@   @@@@@@  @@@@@@@                         @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@   @@@@ @@@@@@ @@@                        @@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@   @@@@@@@@@@@@@@    @@              @@@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@ @ @@@@@@@@            @@@@@@@@@@@@@@@@@   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@    =@@@@@@@@@@@@@@@@@@         @@@@@@@@@@@@@@@@@@@@@* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@ @@@@@@@@ @ @@@@@@@       @@@@@@@@@@@@@@@@@       @@@@@@@@@@@@@@@=@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@# @@@@@@@@@@@@@@   @@@@@@@@@@ *@   @@@@@@@@@@@@@@@       @@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@  @@@@@@ @@@@@    @@@@@@@@@@@@@@%@     %@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@ @@@@@@@@@@@@*    @@@@@@@@@@@@@@        @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@    @@@@@@@@@@@   @@@@@@@@@@@@@@      @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@   - @@@@@@@@       @@@@@@@@@@    :* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@   @@@@@@@@@@@  @      @@@@@@    +@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@     .@@@@@@@        @@   @@@@@@     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@     @ @@@@@-@        *   @ @@@ @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@   @@@@@ @@      @#     @ @  @@@   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@ =@@@@@@@@@@@               @@@@    @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@  @  @@@@@@@@@@@@@   :   @ @     @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@  @@@@@@@@    @@@@@@@@@     @@*     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @      @@@@@@@@@@      @   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@@@ .          .@@     @  *    @@@@@@@@@@@@@@@@@@@ @@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@  @ @@@@                  @@@       @@       @@@@@@@@@@@@@@@@@@@@@@   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@  @ @@@@@@ @@@@@       @@@@@    @  @@          @@@@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@   @ @@@@@  @  @         @@ @     @    :         @@@@@ .@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@      @@ @*     @      @   @:    #@@@@ @@          @#@@@@@@@@@@@ @+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@:      @    @@   @       @  @       @ @@ @@@@  @ @  @@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@     @              @       @ @@@    .    @   @@@@@@@@@@@@ @@@@@@@@@ @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@  @@@@@@@@@@ %       @ @    @@   @@@  @@@*@           @@@@@@@        @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@* @@@@@@@   @@@              @- @@@@@@@@@@          -@@      @@@   @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@  +@@@@@@@@@    @@@    @@@@ @ @        @@@       - @@@ @@@@@@@@@@   @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@   @@@@@@@@@      @@@@ @@@- @@@@@ @@**@@@  @@@@@@@ @@@@@@@@@@@@@@   @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@    @@@@@@@@@@@@@@        @    @@@ @@@@@@@ @       @@@@@@@@@@@@@@@    @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@     @@@@@@@@@@@@@@@@@@    @ -@@ @@ @@@@@@@ @@    @@@@@@@@@@@@@@@@@   @@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@     @@@@@@@@   @@@@@@       @@@@@ @@@@@@@@@   @ @@@@@@@@@@@@@@@@   @@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@   +@@@@@@:      @@@       @@ @@@@@@@@@@@@     @@@@@@@@@@@@@@@   . @@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@@@@-   @@@%                 @@@@@@ @@@@@@@@   @@@@@@@@@@@@@@@@  @ @@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@@@  . @    @                  @@@ @@@@@@@@@+@            @@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@ @ @@@@@@+ @@@@@           :@@@@@@@@@@@@@@@         @@@@@@@@@@@@@@@@@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   @  %  @         @            @@@@@@@@@@@@@@@@@@  @@@@@@@@@@@@@@@@@@@  @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@@ %           @           @@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@  @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    @@ @@@     @         @ @@@@@@@  @@@@@@@ @@@@@@@@@@@@@      @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @     @@@@  @     @@@@@@@ @@ @@@@@@@@@@@@@@@         @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @    @@@@@       +@@@@@          @@@@@@@@@@@@@@    @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @    @@@@@        @@@@         :    @@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @@@@@@   @ *@   @@  @@@@  @ @    @@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@ @@@@@@@*@#@ @@@#   @     @ @@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@ @@@@@@@@@@ @ @@@@ .  @  @@ @@@@@@@@@@@@@@@@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   @@ @@@@@@@@@@@@@@@@%@ @    @@@@@@@@@@@@@@@  @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@  *@@@@@@@@@@@@        @@@@@@@@@@@@@@@.  *@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ %@@@@@@@@@@@@@@@=@ @   @ @@@@@@@@@@@@   @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @% @@@@@@@@@@@@@  @    @   @@@@@@@@@@@     @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@    @@@@@@@@@ @   =     @@@@@@@@  @@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @    @@ @@@@.    @            @@@    @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ @@        @@    @            @@  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@    @@  @@@@     @@*        @@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @#     @  @@@@           @     @@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  @@  @     @@           @ @  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@   @@    @@      @ @  @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   @@@     @@@@    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     @@@@@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 
>home<
Introduction to root-cause analysis on Linux
Introduction> As you may know: finding bugs is one of the greatest thing in life, but once you finally obtained the precious memory corruption you were praying for, you need to actually understand it. In this article we will explore how to conduct a root-cause analysis of a vulnerability in a linux open source program that we compiled ourself, meaning that we were able to disable stripping and enable debugging flag during compilation, which helps greatly. Let's start by installing a gdb extension called pwndbg, not only it prettifies gdb output but it also provides a lot of handy scripts. The bug I recently discovered a vulnerability when fuzzing FFmpeg. You'll have to compile FFmpeg with disable stripping and debugging flag enabled to continue this process. First let's start by running the file against pwndbg: $ pwndbg ./ffmpeg $ start "-i bug_triggering_file -f null -" Passing arguments to the program tested, pwndbg will set a temporary breakpoint in the main function of the program, then execute it until the breakpoint. Run the program with: $ continue The program will then execute itself and run until crash like the following: ffmpeg version N-121008-gf4b044bbe3 Copyright (c) 2000-2025 the FFmpeg developers built with Ubuntu clang version 18.1.3 (1ubuntu1) [mjpeg @ 0x519000001480] not enough bytes remaining in EXIF buffer. entries: 16752 Input #0, jpeg_pipe, from 'bug_triggering_file': Duration: N/A, bitrate: N/A Stream #0:0: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown) Stream mapping: Stream #0:0 -> #0:0 (mjpeg (native) -> wrapped_avframe (native)) [New Thread 0x7ffff1dff6c0 (LWP 197316)] [New Thread 0x7ffff15fe6c0 (LWP 197317)] [New Thread 0x7ffff02f46c0 (LWP 197318)] [New Thread 0x7fffeefea6c0 (LWP 197319)] Press [q] to stop, [?] for help [Thread 0x7fffeefea6c0 (LWP 197319) exited] [mjpeg @ 0x519000002d80] not enough bytes remaining in EXIF buffer. entries: 16752 [mjpeg @ 0x519000002d80] overread 8 [mjpeg @ 0x519000002d80] EOI missing, emulating Thread 4 "dec0:0:mjpeg" received signal SIGSEGV, Segmentation fault. The program ran and then crashed. The first interesting thing we can observe is this: [mjpeg @ 0x519000001480] not enough bytes remaining in EXIF buffer. entries: 16752 [mjpeg @ 0x519000002d80] not enough bytes remaining in EXIF buffer. entries: 16752 [mjpeg @ 0x519000002d80] overread 8 [mjpeg @ 0x519000002d80] EOI missing, emulating Without any context we can already suppose that the EXIF buffer has been overwritten. Then come this line where the crash actually happened: Thread 4 "dec0:0:mjpeg" received signal SIGSEGV, Segmentation fault. The important piece of information here is `dec0:0:mjpeg` which indicates the location of the crashing code. To understand better what is happening pwndbg is display the code we are running, you can use the command: layout next. That will display the source code of the program test above the assembly code. Then we can run the command: r to restart the program. Now we are going to iterate function by function by using the command: next Let's iterate that until we reach the ffmpeg.c:1010 with the following command: $ ret = transcode(sch); If you press next (or enter to replay the last command) one more time the program crashes. Great! We find the last function call before the crash occurs, we are getting closer. Let's restart our program with: start "-i bug_triggering_file -f null -" Set a breakpoint right before the crash: $ break ffmpeg.c:1010 Breakpoint 3 at 0x555555fa5407: file fftools/ffmpeg.c, line 1010. We can continue with command: c until it reaches our breakpoint Then the command: next will trigger the crash. When the program performs a function call, information about the call is generated: the location of the call the arguments and the local variables of the function being called. This forms a block data called the stack frame. The stack frames are allocated in a region of memory called the call stack. A backtrace is a summary of how your program got where it is. We can display it with the command: bt #0 0x0000555555de1636 in __asan::Allocator::Deallocate #1 0x0000555555e79e50 in __interceptor_free () #2 0x0000555557874739 in exif_free_entry (entry=0x51a0000106e0) at libavcodec/exif.c:605 #3 av_exif_free (ifd=0x5150000303d8) at libavcodec/exif.c:620 #4 0x00005555578746fb in exif_free_entry (entry=0x5150000303c0) at libavcodec/exif.c:603 #5 av_exif_free (ifd=ifd@entry=0x50900000ff00) at libavcodec/exif.c:620 #6 0x00005555576a37c5 in exif_attach_ifd (avctx=, frame=, ifd=0x50900000ff00, pbuf=) at libavcodec/decode.c:2405 #7 0x00005555576a3001 in ff_decode_exif_attach_ifd at libavcodec/decode.c:2413 #8 0x0000555557e3ce7b in ff_mjpeg_decode_frame_from_buf (avctx=0x519000002d80, frame=0x515000002ac0, got_frame=0x7ffff02f35e0, avpkt=, buf=0x522000000100 "\377\330\377", , buf_size=5649) at libavcodec/mjpegdec.c:2860 #9 0x000055555769170c in decode_simple_internal (avctx=0x519000002d80, frame=0x515000002ac0, discarded_samples=0x7ffff02f3570) at libavcodec/decode.c:440 #10 decode_simple_receive_frame (avctx=0x519000002d80, frame=0x515000002ac0) at libavcodec/decode.c:600 #11 ff_decode_receive_frame_internal (avctx=avctx@entry=0x519000002d80, frame=frame@entry=0x515000002ac0) at libavcodec/decode.c:636 #12 0x0000555557694443 in decode_receive_frame_internal (avctx=avctx@entry=0x519000002d80, frame=0x515000002ac0) at libavcodec/decode.c:653 #13 0x0000555557694136 in avcodec_send_packet (avctx=avctx@entry=0x519000002d80, avpkt=0x510000010040) at libavcodec/decode.c:729 #14 0x0000555555ec178c in packet_decode (dp=0x513000000c80, pkt=0x510000010040, frame=0x51500002fd40) at fftools/ffmpeg_dec.c:724 #15 decoder_thread (arg=) at fftools/ffmpeg_dec.c:952 #16 0x0000555555f55867 in task_wrapper (arg=0x50c0000005a8) at fftools/ffmpeg_sched.c:2534 #17 0x0000555555e77b6d in asan_thread_start(void*) () #18 0x00007ffff569caa4 in start_thread (arg=) at ./nptl/pthread_create.c:447 #19 0x00007ffff5729c3c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78 This line seems interesting: #8 0x0000555557e3ce7b in ff_mjpeg_decode_frame_from_buf (avctx=0x519000002d80, frame=0x515000002ac0, got_frame=0x7ffff02f35e0, avpkt=, buf=0x522000000100 "\377\330\377", incomplete sequence \340>, buf_size=5649) at libavcodec/mjpegdec.c:2860 Let's investigate it a bit with the command: frame {frame_number} pwndbg> frame 8 #8 0x0000555557e3ce7b in ff_mjpeg_decode_frame_from_buf (avctx=0x519000002d80, frame=0x515000002ac0, got_frame=0x7ffff02f35e0, avpkt=, buf=0x522000000100 "\377\330\377", , buf_size=5649) at libavcodec/mjpegdec.c:2860 2860 ret = ff_decode_exif_attach_ifd(avctx, frame, &s->exif_metadata); We can then inspect the value at of the local variables at this stages: pwndbg> print buf $2 = (const uint8_t *) 0x522000000100 "\377\330\377", pwndbg> print frame $3 = (AVFrame *) 0x515000002ac0 pwndbg> print &s->exif_metadata $4 = (AVExifMetadata *) 0x52100000f998 Seems that we found an interesting new breakpoint location: libavcodec/mjpegdec.c:2860. Let's restart our program and set a breakpoint there: $ start "-i bug_triggering_file -f null -" $ break mjpegdec.c:2860 $ continue ─ In file: /home/s0urc3/Dev/ffmpeg/libavcodec/mjpegdec.c:2860 2855 } 2856 } 2857 } 2858 2859 if (s->exif_metadata.entries) { ► 2860 ret = ff_decode_exif_attach_ifd(avctx, frame, &s->exif_metadata); 2861 av_exif_free(&s->exif_metadata); 2862 if (ret < 0) 2863 av_log(avctx, AV_LOG_WARNING, "couldn't attach EXIF metadata\n"); 2864 } 2865 It seems that we found an interesting function, let's have a look at the source code: int ff_decode_exif_attach_ifd(AVCodecContext *avctx, AVFrame *frame, const AVExifMetadata *ifd) { AVBufferRef *dummy = NULL; return exif_attach_ifd(avctx, frame, ifd, &dummy); } Let's restart our program and set a breakpoint there: break decode.c:2411 Now we can step instruction per instruction to identify the exact crash point with command: stepi By stepping we land in the ff_decode_exif_attach_ifd function from decode.c file. Now things gets a bit messy, we iterate through
asan
stuff which is not really interesting for us and produce a lot of lines to iterate through. If we continue to step we will land in the exif_attach_ifd function from decode.c file. After a while we will visit the exif.c file and go through a bunch of functions. There a few loop that compares values, which makes this task absolutely impossible to run by hand. What we need is a program that allows us to see the exact step right before the crash. That's where RR comes in place. This tool allows us to record the execution of our program then replay it. It integrates gdb too so we can use the same commands as before to investigate our crash. (More info in this article) Let's run our program under rr: rr record {program} {args} Then replay it: rr replay Now can we can run it until it crashes: continue And here comes the magic: reverse-step allows us to step from the crash to the last valid instruction Again, the command: lay next allow us to display disassembly/code After a few steps in asan, we are back into our code. We land around here: void av_freep(void *arg){ void *val; memcpy(&val, arg, sizeof(val)); memcpy(arg, &(void *) { NULL }, sizeof(val)); av_free(val); } By running the following command: $ print val $1 = (void *) 0xbebebebebebebebe Stepping instructions with nexti until we reach av_free (ptr=0xbebebebebebebebe) at libavutil/mem.c By reversing we can see that av_freep is called with &entry->value.ptr as argument. We can print its value: $print &entry->value.ptr $2 = (void **) 0x51a0000106f8 We could think that the issue might have been free(val) which tries to free a variable that was not mallocated. But let's investigate what &entry->value.ptr is actually. Looking at exif.h code: struct AVExifEntry { // ...SKIPPED... union { // ...SKIPPED... void *ptr, } value } Let's print the value of the *arg passed to av_freep (rr) print arg $1 = (void *) 0x51a0000d06f8 (rr) print 0x51a0000d06f8 $2 = 89747637470968 My intuition tells me that here lies the issue, the *arg is passed as memcopy(&val, arg) which transform val into a heap allocated variable. However, a lack of sanitizer during a step that assigns a value to the value.ptr allow our fuzzing input (random data!) to pass an invalid address as value! Therefore when free(val) is executed free tries to release a non-valid pointer and the program segfault! Let's reverse step a bit more: (rr) reverse-step exif_free_entry (entry=0x51a0000d06e0) at libavcoded/exif.c:605 (rr) print &entry->value.ptr $3 = (void **) 0x51a0000d06f8 If we keep reverse-step until we find where entry comes from, we find the void av_exif_free(AVExifMetadata *idf) void av_exif_free(AVExifMetadata *ifd) { if (!ifd) return; if (!ifd->entries) { ifd->count = 0; ifd->size = 0; return; } for (size_t i = 0; i < ifd->count; i++) { AVExifEntry *entry = &ifd->entries[i]; exif_free_entry(entry); } av_freep(&ifd->entries); ifd->count = 0; ifd->size = 0; } So the AVExifEntry structure is populated with the values of the AVExifMetadata ! But our metadata are garbage at this point and the values passed is not properly sanitized. (rr) print entry $6 ( AVExifEntry *) 0x51a000d06b8 The fix FFmpeg maintainers confirmed the issue and patched it in this commit