Commit message: None
CVE: CVE-2017-9739
CWE: CWE-125
Vulnerability description: The Ins_JMPR function in base/ttinterp.c in Artifex Ghostscript GhostXPS 9.21 allows remote attackers to cause a denial of service (heap-based buffer over-read and application crash) or possibly have unspecified other impact via a crafted document.

Project: ghostscript
File: ttinterp.c

  static Int  Current_Ppem( EXEC_OP )
  {
    return MulDiv_Round( CUR.metrics.ppem, CURRENT_Ratio(), 0x10000 );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_FLIPPT( INS_ARG )
  {
    Long  point;
    (void)args;

    if ( CUR.top < CUR.GS.loop )
    {
      CUR.error = TT_Err_Too_Few_Arguments;
      return;
    }

    while ( CUR.GS.loop > 0 )
    {
      CUR.args--;

      point = CUR.stack[CUR.args];

      if ( BOUNDS( point, CUR.pts.n_points ) )
      {
        CUR.error = TT_Err_Invalid_Reference;
       return;
      }

      CUR.pts.touch[point] ^= TT_Flag_On_Curve;

      CUR.GS.loop--;
    }

    CUR.GS.loop = 1;
    CUR.new_top = CUR.args;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_GETINFO( INS_ARG )
  {
    Long  K;

    K = 0;

    /* We return then Windows 3.1 version number */
    /* for the font scaler                       */
    if ( (args[0] & 1) != 0 )
      K = 3;

    /* Has the glyph been rotated ? */
    if ( CUR.metrics.rotated )
      K |= 0x80;

    /* Has the glyph been stretched ? */
    if ( CUR.metrics.stretched )
      K |= 0x100;

    args[0] = K;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_JROF( INS_ARG )
  {
    if ( args[1] == 0 )
    {
      CUR.IP      += (Int)(args[0]);
      CUR.step_ins = FALSE;

      /* See JMPR above */
      if(CUR.code[CUR.IP] != 0x2D && CUR.code[CUR.IP - 1] == 0x2D)
        CUR.IP -= 1;
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MDAP( INS_ARG )
  {
    Int         point;
    TT_F26Dot6  cur_dist,
                distance;

    point = (Int)args[0];

    if ( BOUNDS( args[0], CUR.zp0.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    /* XXX: Is there some undocumented feature while in the */
    /*      twilight zone? ?                                */

    if ( (CUR.opcode & 1) != 0 )
    {
      cur_dist = CUR_Func_project( CUR.zp0.cur_x[point],
                                   CUR.zp0.cur_y[point] );
      distance = CUR_Func_round( cur_dist,
                                 CUR.metrics.compensations[0] ) - cur_dist;
    }
    else
      distance = 0;

    CUR_Func_move( &CUR.zp0, point, distance );

    CUR.GS.rp0 = point;
    CUR.GS.rp1 = point;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MUL( INS_ARG )
  { (void)exc;
    args[0] = MulDiv_Round( args[0], args[1], 64L );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_NPUSHB( INS_ARG )
  {
    Int  L, K;

    L = (Int)CUR.code[CUR.IP + 1];

    if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    for ( K = 1; K <= L; K++ )
      { args[K - 1] = CUR.code[CUR.IP + K + 1];
        DBG_PRINT1(" %d", args[K - 1]);
      }

    CUR.new_top += L;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_NROUND( INS_ARG )
  {
    args[0] = Round_None( EXEC_ARGS
                          args[0],
                          CUR.metrics.compensations[CUR.opcode - 0x6C] );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SCANCTRL( INS_ARG )
  {
    Int  A;

    /* Get Threshold */
    A = (Int)(args[0] & 0xFF);

    if ( A == 0xFF )
    {
      CUR.GS.scan_control = TRUE;
      return;
    }
    else if ( A == 0 )
    {
      CUR.GS.scan_control = FALSE;
      return;
    }

    A *= 64;

    if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
      CUR.GS.scan_control = TRUE;

    if ( (args[0] & 0x200) != 0 && CUR.metrics.rotated )
      CUR.GS.scan_control = TRUE;

    if ( (args[0] & 0x400) != 0 && CUR.metrics.stretched )
      CUR.GS.scan_control = TRUE;

    if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
      CUR.GS.scan_control = FALSE;

    if ( (args[0] & 0x1000) != 0 && CUR.metrics.rotated )
      CUR.GS.scan_control = FALSE;

    if ( (args[0] & 0x2000) != 0 && CUR.metrics.stretched )
      CUR.GS.scan_control = FALSE;
}

Project: ghostscript
File: ttinterp.c

  static void  Ins_SDPVTL( INS_ARG )
  {
    Long  A, B, C;
    Long  p1, p2;   /* was Int in pas type ERROR */

    p1 = args[1];
    p2 = args[0];

    if ( BOUNDS( p2, CUR.zp1.n_points ) ||
         BOUNDS( p1, CUR.zp2.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    A = CUR.zp1.org_x[p2] - CUR.zp2.org_x[p1];
    B = CUR.zp1.org_y[p2] - CUR.zp2.org_y[p1];

    if ( (CUR.opcode & 1) != 0 )
    {
      C =  B;   /* CounterClockwise rotation */
      B =  A;
      A = -C;
    }

    if ( NORMalize( A, B, &CUR.GS.dualVector ) == FAILURE )
      return;

    A = CUR.zp1.cur_x[p2] - CUR.zp2.cur_x[p1];
    B = CUR.zp1.cur_y[p2] - CUR.zp2.cur_y[p1];

    if ( (CUR.opcode & 1) != 0 )
    {
      C =  B;   /* CounterClockwise rotation */
      B =  A;
      A = -C;
    }

    if ( NORMalize( A, B, &CUR.GS.projVector ) == FAILURE )
      return;

    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SHPIX( INS_ARG )
  {
    TT_F26Dot6  dx, dy;
    Long        point;

    if ( CUR.top < CUR.GS.loop )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    dx = MulDiv_Round( args[0],
                       (Long)CUR.GS.freeVector.x,
                       0x4000 );
    dy = MulDiv_Round( args[0],
                       (Long)CUR.GS.freeVector.y,
                       0x4000 );

    while ( CUR.GS.loop > 0 )
    {
      CUR.args--;

      point = CUR.stack[CUR.args];

      if ( BOUNDS( point, CUR.zp2.n_points ) )
      {
        CUR.error = TT_Err_Invalid_Reference;
        return;
      }

      MOVE_Zp2_Point( point, dx, dy, TRUE );

      CUR.GS.loop--;
    }

    CUR.GS.loop = 1;
    CUR.new_top = CUR.args;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SRP2( INS_ARG )
  {
    CUR.GS.rp2 = (Int)(args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_WCVTF( INS_ARG )
  {
#ifdef DEBUG
    int ov;
#endif

    if ( BOUNDS( args[0], CUR.cvtSize ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

#ifdef DEBUG
    ov = CUR.cvt[args[0]];
#endif
    CUR.cvt[args[0]] = FUnits_To_Pixels( EXEC_ARGS args[1] );
#ifdef DEBUG
    DBG_PRINT3(" cvt[%d]%d:=%d", args[0], ov, CUR.cvt[args[0]]);
#endif
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Project( EXEC_OPS TT_F26Dot6  Vx, TT_F26Dot6  Vy )
  {
    THROW_PATENTED;
    return 0;
  }