PVS-Studio විශ්ලේෂකය භාවිතයෙන් rdesktop සහ xrdp පරීක්ෂා කිරීම

PVS-Studio විශ්ලේෂකය භාවිතයෙන් rdesktop සහ xrdp පරීක්ෂා කිරීම
RDP ප්‍රොටෝකෝලය සමඟ වැඩ කිරීම සඳහා විවෘත මූලාශ්‍ර වැඩසටහන් පරීක්ෂා කිරීම පිළිබඳ ලිපි මාලාවක දෙවන සමාලෝචනය මෙයයි. එහි අපි rdesktop සේවාදායකයා සහ xrdp සේවාදායකය දෙස බලමු.

දෝෂ හඳුනාගැනීමේ මෙවලමක් ලෙස භාවිතා කරයි පීවීඑස්-ස්ටුඩියෝ. එය Windows, Linux සහ macOS වේදිකාවල ලබා ගත හැකි C, C++, C# සහ Java භාෂා සඳහා ස්ථිතික කේත විශ්ලේෂකයකි.

ලිපිය ඉදිරිපත් කරන්නේ මට සිත්ගන්නාසුළු යැයි පෙනෙන වැරදි පමණි. කෙසේ වෙතත්, ව්යාපෘති කුඩා බැවින්, වැරදි කිහිපයක් සිදු විය :).

අදහස් දැක්වීම්. FreeRDP ව්‍යාපෘති සත්‍යාපනය පිළිබඳ පෙර ලිපියක් සොයාගත හැකිය මෙහි.

rdesktop

rdesktop - UNIX මත පදනම් වූ පද්ධති සඳහා RDP සේවාලාභියෙකු නොමිලේ ක්‍රියාත්මක කිරීම. ඔබ Cygwin යටතේ ව්‍යාපෘතිය ගොඩනඟන්නේ නම් එය වින්ඩෝස් යටතේද භාවිතා කළ හැක. GPLv3 යටතේ බලපත්‍ර ලබා ඇත.

මෙම සේවාලාභියා ඉතා ජනප්‍රියයි - එය ReactOS හි පෙරනිමියෙන් භාවිතා වන අතර, ඔබට ඒ සඳහා තෙවන පාර්ශවීය චිත්‍රක ඉදිරිපස අන්තයන් ද සොයාගත හැකිය. කෙසේ වෙතත්, ඔහු තරමක් වයසයි: ඔහුගේ පළමු නිකුතුව 4 අප්රේල් 2001 වන දින සිදු විය - ලියන අවස්ථාව වන විට ඔහුගේ වයස අවුරුදු 17 කි.

මම කලින් සඳහන් කළ පරිදි, ව්යාපෘතිය තරමක් කුඩා ය. එහි ආසන්න වශයෙන් කේත රේඛා 30 ක් පමණ අඩංගු වන අතර එය එහි වයස අනුව ටිකක් අමුතුයි. සංසන්දනය කිරීම සඳහා, FreeRDP රේඛා 320 දහසක් අඩංගු වේ. මෙන්න Cloc වැඩසටහනේ ප්‍රතිදානය:

PVS-Studio විශ්ලේෂකය භාවිතයෙන් rdesktop සහ xrdp පරීක්ෂා කිරීම

ළඟා විය නොහැකි කේතය

V779 ලබා ගත නොහැකි කේතය අනාවරණය විය. දෝෂයක් ඇති විය හැකිය. rdesktop.c 1502

int
main(int argc, char *argv[])
{
  ....
  return handle_disconnect_reason(deactivated, ext_disc_reason);

  if (g_redirect_username)
    xfree(g_redirect_username);

  xfree(g_username);
}

දෝෂය ක්‍රියාකාරීත්වයේදී වහාම අපට හමුවෙයි ප්රධාන: ක්‍රියාකරුට පසුව එන කේතය අපි දකිමු ආපසු - මෙම කොටස මතක පිරිසිදු කිරීම සිදු කරයි. කෙසේ වෙතත්, දෝෂය තර්ජනයක් නොවේ: වැඩසටහනෙන් පිටවීමෙන් පසු සියලුම වෙන් කළ මතකය මෙහෙයුම් පද්ධතිය විසින් ඉවත් කරනු ලැබේ.

දෝෂ හැසිරවීම නැත

V557 Array underrun හැකි ය. 'n' දර්ශකයේ අගය -1 දක්වා ළඟා විය හැක. rdesktop.c 1872

RD_BOOL
subprocess(char *const argv[], str_handle_lines_t linehandler, void *data)
{
  int n = 1;
  char output[256];
  ....
  while (n > 0)
  {
    n = read(fd[0], output, 255);
    output[n] = ' '; // <=
    str_handle_lines(output, &rest, linehandler, data);
  }
  ....
}

මෙම නඩුවේ කේත කොටස ගොනුව අවසන් වන තෙක් ගොනුවේ සිට බෆරයකට කියවයි. කෙසේ වෙතත්, මෙහි දෝෂ හැසිරවීමක් නොමැත: යමක් වැරදී ගියහොත්, එසේ නම් කියවන්න -1 නැවත පැමිණෙනු ඇත, පසුව අරාව ඉක්මවා යනු ඇත නිමැවුමකි.

අකුරු ආකාරයේ EOF භාවිතා කිරීම

V739 EOF 'char' වර්ගයේ අගයක් සමඟ සංසන්දනය නොකළ යුතුය. '(c = fgetc(fp))' 'int' වර්ගයේ විය යුතුය. ctrl.c 500


int
ctrl_send_command(const char *cmd, const char *arg)
{
  char result[CTRL_RESULT_SIZE], c, *escaped;
  ....
  while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != 'n')
  {
    result[index] = c;
    index++;
  }
  ....
}

ගොනුවේ අවසානයට ළඟා වීමේදී වැරදි ලෙස හැසිරවීම මෙහිදී අපට පෙනේ: if fgetc කේතය 0xFF වන අක්ෂරයක් ලබා දෙයි, එය ගොනුවේ අවසානය ලෙස අර්ථ දැක්වේ (EOF).

EOF එය නියතයකි, සාමාන්‍යයෙන් -1 ලෙස අර්ථ දැක්වේ. උදාහරණයක් ලෙස, CP1251 කේතීකරණයේදී, රුසියානු හෝඩියේ අවසාන අකුරේ 0xFF කේතය ඇත, එය අපි විචල්‍යයක් ගැන කතා කරන්නේ නම් -1 අංකයට අනුරූප වේ. අඟුරු. 0xFF සංකේතය වැනි බව පෙනේ EOF (-1) ගොනුවේ අවසානය ලෙස අර්ථ දැක්වේ. එවැනි දෝෂ වළක්වා ගැනීම සඳහා, කාර්යයේ ප්රතිඵලය වේ fgetc වැනි විචල්‍යයක ගබඩා කළ යුතුය int.

අකුරු වැරදි

ඛණ්ඩය 1

V547 'write_time' යන ප්‍රකාශනය සැමවිටම අසත්‍ය වේ. disk.c 805

RD_NTSTATUS
disk_set_information(....)
{
  time_t write_time, change_time, access_time, mod_time;
  ....
  if (write_time || change_time)
    mod_time = MIN(write_time, change_time);
  else
    mod_time = write_time ? write_time : change_time; // <=
  ....
}

සමහර විට මෙම කේතයේ කතුවරයා එය වැරදියට තේරුම් ගෙන ඇත || и && තත්ත්වයෙන්. අගයන් සඳහා හැකි විකල්ප සලකා බලමු ලියන_කාලය и වෙනස්_කාලය:

  • විචල්‍ය දෙකම 0 ට සමාන වේ: මෙම අවස්ථාවේදී අපි ශාඛාවකින් අවසන් වනු ඇත වෙන: විචල්ය mod_time පසුකාලීන තත්ත්වය කුමක් වුවත් සෑම විටම 0 වනු ඇත.
  • විචල්‍ය වලින් එකක් වන්නේ 0: mod_time 0 ට සමාන වනු ඇත (අනෙක් විචල්‍යයට සෘණ නොවන අගයක් තිබේ නම්), මන්ද මිනි විකල්ප දෙකෙන් කුඩා දේ තෝරා ගනු ඇත.
  • විචල්‍ය දෙකම 0 ට සමාන නොවේ: අවම අගය තෝරන්න.

සමඟ කොන්දේසිය ප්රතිස්ථාපනය කරන විට ලියන_කාලය && වෙනස්_කාලය හැසිරීම නිවැරදි ලෙස පෙනෙනු ඇත:

  • විචල්‍ය එකක් හෝ දෙකම 0 ට සමාන නොවේ: ශුන්‍ය නොවන අගයක් තෝරන්න.
  • විචල්‍ය දෙකම 0 ට සමාන නොවේ: අවම අගය තෝරන්න.

ඛණ්ඩය 2

V547 ප්රකාශනය සැමවිටම සත්ය වේ. බොහෝ විට මෙහි '&&' ක්‍රියාකරු භාවිතා කළ යුතුය. disk.c 1419

static RD_NTSTATUS
disk_device_control(RD_NTHANDLE handle, uint32 request, STREAM in,
      STREAM out)
{
  ....
  if (((request >> 16) != 20) || ((request >> 16) != 9))
    return RD_STATUS_INVALID_PARAMETER;
  ....
}

පෙනෙන විදිහට මෙහි ක්‍රියාකරුවන් ද මිශ්‍ර වී ඇත || и &&, හෝ == и !=: විචල්‍යයකට එකවර 20 සහ 9 අගය තිබිය නොහැක.

අසීමිත රේඛා පිටපත් කිරීම

V512 'sprintf' ශ්‍රිතයේ ඇමතුමක් 'fullpath' බෆරය පිටාර ගැලීමට හේතු වේ. disk.c 1257

RD_NTSTATUS
disk_query_directory(....)
{
  ....
  char *dirname, fullpath[PATH_MAX];
  ....
  /* Get information for directory entry */
  sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
  ....
}

ඔබ කාර්යය සම්පූර්ණයෙන්ම දෙස බලන විට, මෙම කේතය ගැටළු ඇති නොකරන බව පැහැදිලි වනු ඇත. කෙසේ වෙතත්, අනාගතයේදී ඒවා මතු විය හැකිය: එක් නොසැලකිලිමත් වෙනසක් සහ අපට බෆර පිටාර ගැලීමක් ලැබෙනු ඇත - ස්ප්රින්ට් එය කිසිවකින් සීමා නොවේ, එබැවින් මාර්ග සංයුක්ත කිරීමේදී අපට අරාවේ සීමාවෙන් ඔබ්බට යා හැකිය. මෙම ඇමතුම ගැන අවධානය යොමු කිරීම රෙකමදාරු කරනු ලැබේ snprintf(fullpath, PATH_MAX, ....).

අතිරික්ත තත්ත්වය

V560 කොන්දේසි සහිත ප්‍රකාශනයේ කොටසක් සැමවිටම සත්‍ය වේ: එකතු කරන්න > 0. scard.c 507

static void
inRepos(STREAM in, unsigned int read)
{
  SERVER_DWORD add = 4 - read % 4;
  if (add < 4 && add > 0)
  {
    ....
  }
}

පරීක්ෂා > 0 එකතු කරන්න මෙහි අවශ්‍යතාවයක් නැත: විචල්‍යය සෑම විටම ශුන්‍යයට වඩා වැඩි වනු ඇත, මන්ද % 4 කියවන්න බෙදීමේ ඉතිරි කොටස ආපසු ලබා දෙනු ඇත, නමුත් එය කිසි විටෙකත් 4 ට සමාන නොවේ.

xrdp

xrdp - විවෘත කේත කේතය සහිත RDP සේවාදායකයක් ක්රියාත්මක කිරීම. ව්යාපෘතිය කොටස් 2 කට බෙදා ඇත:

  • xrdp - ප්රොටෝකෝලය ක්රියාත්මක කිරීම. Apache 2.0 බලපත්‍රය යටතේ බෙදා හරිනු ලැබේ.
  • xorgxrdp - xrdp සමඟ භාවිතා කිරීම සඳහා Xorg ධාවක කට්ටලයක්. බලපත්‍රය - X11 (MIT වැනි, නමුත් ප්‍රචාරණයේදී භාවිතා කිරීම තහනම්)

ව්යාපෘතියේ සංවර්ධනය rdesktop සහ FreeRDP හි ප්රතිඵල මත පදනම් වේ. මුලදී, ග්‍රැෆික්ස් සමඟ වැඩ කිරීමට, ඔබට වෙනම VNC සේවාදායකයක් හෝ RDP සහාය ඇති විශේෂ X11 සේවාදායකයක් භාවිතා කිරීමට සිදු විය - X11rdp, නමුත් xorgxrdp පැමිණීමත් සමඟ ඒවායේ අවශ්‍යතාවය අතුරුදහන් විය.

මෙම ලිපියෙන් අපි xorgxrdp ආවරණය නොකරමු.

xrdp ව්‍යාපෘතිය, පෙර ව්‍යාපෘතිය මෙන් ඉතා කුඩා වන අතර දළ වශයෙන් රේඛා 80 ක් පමණ අඩංගු වේ.

PVS-Studio විශ්ලේෂකය භාවිතයෙන් rdesktop සහ xrdp පරීක්ෂා කිරීම

තවත් අකුරු වැරදි

V525 කේතය සමාන කුට්ටි එකතුවක් අඩංගු වේ. 87, 88, 89 පේළිවල 'r', 'g', 'r' අයිතම පරීක්ෂා කරන්න. rfxencode_rgb_to_yuv.c 87

static int
rfx_encode_format_rgb(const char *rgb_data, int width, int height,
                      int stride_bytes, int pixel_format,
                      uint8 *r_buf, uint8 *g_buf, uint8 *b_buf)
{
  ....
  switch (pixel_format)
  {
    case RFX_FORMAT_BGRA:
      ....
      while (x < 64)
      {
          *lr_buf++ = r;
          *lg_buf++ = g;
          *lb_buf++ = r; // <=
          x++;
      }
      ....
  }
  ....
}

මෙම කේතය RemoteFX සඳහා jpeg2000 codec ක්‍රියාත්මක කරන librfxcodec පුස්තකාලයෙන් ලබාගෙන ඇත. මෙන්න, පෙනෙන විදිහට, ග්‍රැෆික් දත්ත නාලිකා මිශ්‍ර වී ඇත - “නිල්” වර්ණය වෙනුවට “රතු” සටහන් වේ. මෙම දෝෂය බොහෝ විට පිටපත් ඇලවීමේ ප්‍රතිඵලයක් ලෙස දිස් විය.

සමාන කාර්යයක් තුළ එකම ගැටළුවක් ඇති විය rfx_encode_format_argb, විශ්ලේෂකය ද අපට පැවසුවේ:

V525 කේතය සමාන කුට්ටි එකතුවක් අඩංගු වේ. 260, 261, 262, 263 පේළිවල 'a', 'r', 'g', 'r' අයිතම පරීක්ෂා කරන්න. rfxencode_rgb_to_yuv.c 260

while (x < 64)
{
    *la_buf++ = a;
    *lr_buf++ = r;
    *lg_buf++ = g;
    *lb_buf++ = r;
    x++;
}

අරා ප්‍රකාශය

V557 Array overrun හැකි ය. 'i — 8' දර්ශකයේ අගය 129 දක්වා ළඟා විය හැක. genkeymap.c 142

// evdev-map.c
int xfree86_to_evdev[137-8+1] = {
  ....
};

// genkeymap.c
extern int xfree86_to_evdev[137-8];

int main(int argc, char **argv)
{
  ....
  for (i = 8; i <= 137; i++) /* Keycodes */
  {
    if (is_evdev)
        e.keycode = xfree86_to_evdev[i-8];
    ....
  }
  ....
}

මෙම ගොනු දෙකෙහි ඇති අරාවේ ප්‍රකාශය සහ නිර්වචනය නොගැලපේ - ප්‍රමාණය 1 න් වෙනස් වේ. කෙසේ වෙතත්, කිසිදු දෝෂයක් සිදු නොවේ - නිවැරදි ප්‍රමාණය evdev-map.c ගොනුවේ දක්වා ඇත, එබැවින් සීමාවෙන් පිටත නොමැත. එබැවින් මෙය පහසුවෙන් නිවැරදි කළ හැකි දෝෂයක් පමණි.

වැරදි සංසන්දනය

V560 කොන්දේසි සහිත ප්‍රකාශනයේ කොටසක් සෑම විටම අසත්‍ය වේ: (cap_len <0). xrdp_caps.c 616

// common/parse.h
#if defined(B_ENDIAN) || defined(NEED_ALIGN)
#define in_uint16_le(s, v) do 
....
#else
#define in_uint16_le(s, v) do 
{ 
    (v) = *((unsigned short*)((s)->p)); 
    (s)->p += 2; 
} while (0)
#endif

int
xrdp_caps_process_confirm_active(struct xrdp_rdp *self, struct stream *s)
{
  int cap_len;
  ....
  in_uint16_le(s, cap_len);
  ....
  if ((cap_len < 0) || (cap_len > 1024 * 1024))
  {
    ....
  }
  ....
}

ශ්‍රිතය වර්ගය විචල්‍යයක් කියවයි අත්සන් නොකළ කෙටි වැනි විචල්‍යයකට int. අපි අත්සන් නොකළ විචල්‍යයක් කියවා ප්‍රතිඵලය විශාල විචල්‍යයකට පවරන නිසා මෙහි පරීක්ෂා කිරීම අවශ්‍ය නොවේ, එබැවින් විචල්‍යයට සෘණ අගයක් ගත නොහැක.

අනවශ්ය චෙක්පත්

V560 කොන්දේසි සහිත ප්‍රකාශනයේ කොටසක් සැමවිටම සත්‍ය වේ: (bpp != 16). libxrdp.c 704

int EXPORT_CC
libxrdp_send_pointer(struct xrdp_session *session, int cache_idx,
                     char *data, char *mask, int x, int y, int bpp)
{
  ....
  if ((bpp == 15) && (bpp != 16) && (bpp != 24) && (bpp != 32))
  {
      g_writeln("libxrdp_send_pointer: error");
      return 1;
  }
  ....
}

ආරම්භයේ දී අපට දැනටමත් සැසඳීමක් ඇති බැවින් අසමානතා පරීක්ෂා කිරීම මෙහි තේරුමක් නැත. මෙය මුද්‍රණ දෝෂයක් විය හැකි අතර සංවර්ධකයාට ක්‍රියාකරු භාවිතා කිරීමට අවශ්‍ය විය || වලංගු නොවන තර්ක පෙරීමට.

නිගමනය

විගණනය අතරතුර, බරපතල දෝෂ හඳුනාගෙන නැත, නමුත් බොහෝ අඩුපාඩු සොයා ගන්නා ලදී. කෙසේ වෙතත්, මෙම සැලසුම් විෂය පථයෙන් කුඩා වුවද බොහෝ පද්ධතිවල භාවිතා වේ. කුඩා ව්‍යාපෘතියක අවශ්‍යයෙන්ම බොහෝ දෝෂ නොමැත, එබැවින් ඔබ කුඩා ව්‍යාපෘති මත පමණක් විශ්ලේෂකයේ ක්‍රියාකාරිත්වය විනිශ්චය නොකළ යුතුය. ඔබට මේ ගැන වැඩි විස්තර ලිපියෙන් කියවිය හැකිය "ඉලක්කම් වලින් තහවුරු වූ හැඟීම්«.

ඔබට PVS-Studio හි අත්හදා බැලීමේ අනුවාදයක් අපෙන් බාගත හැකිය වෙබ් අඩවිය.

PVS-Studio විශ්ලේෂකය භාවිතයෙන් rdesktop සහ xrdp පරීක්ෂා කිරීම

ඔබට මෙම ලිපිය ඉංග්‍රීසි කතා කරන ප්‍රේක්ෂකයින් සමඟ බෙදා ගැනීමට අවශ්‍ය නම්, කරුණාකර පරිවර්තන සබැඳිය භාවිතා කරන්න: Sergey Larin. PVS-Studio සමඟ rdesktop සහ xrdp පරීක්ෂා කිරීම

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න