PVS-اسٽوڊيو تجزيه ڪندڙ استعمال ڪندي rdesktop ۽ xrdp چيڪ ڪرڻ

PVS-اسٽوڊيو اينالائيزر استعمال ڪندي rdesktop ۽ xrdp چيڪ ڪريو
آر ڊي پي پروٽوڪول سان ڪم ڪرڻ لاءِ اوپن سورس پروگرامن کي جانچڻ بابت مضمونن جي هڪ سلسلي ۾ هي ٻيو جائزو آهي. ان ۾ اسان ڏسنداسين rdesktop ڪلائنٽ ۽ xrdp سرور.

غلطين کي سڃاڻڻ لاءِ اوزار طور استعمال ڪيو ويو پي وي وي اسٽوڊيو. اهو سي، سي++، سي# ۽ جاوا ٻولين لاءِ هڪ مستحڪم ڪوڊ اينالائيزر آهي، ونڊوز، لينڪس ۽ macOS پليٽ فارمن تي دستياب آهي.

مضمون صرف انهن غلطين کي پيش ڪري ٿو جيڪي مون کي دلچسپ لڳي. بهرحال، منصوبا ننڍا آهن، تنهنڪري ڪجهه غلطيون هيون :).

ويچاري. فري آر ڊي پي پروجيڪٽ جي تصديق بابت اڳوڻو مضمون ڳولي سگھجي ٿو هتي.

rdesktop

rdesktop - UNIX-based سسٽم لاءِ آر ڊي پي ڪلائنٽ جو مفت نفاذ. اهو ونڊوز جي تحت پڻ استعمال ڪري سگهجي ٿو جيڪڏهن توهان سائگون تحت پروجيڪٽ ٺاهي رهيا آهيو. GPLv3 تحت لائسنس يافته.

هي ڪلائنٽ تمام مشهور آهي - اهو ڊفالٽ طور استعمال ڪيو ويندو آهي ReactOS ۾، ۽ توهان پڻ ڳولي سگهو ٿا ٽئين پارٽي جي گرافڪ فرنٽ-اينڊس ان لاءِ. بهرحال، هو ڪافي پراڻو آهي: هن جو پهريون رليز اپريل 4، 2001 تي ٿي ويو - لکڻ جي وقت، هو 17 سالن جي عمر ۾ آهي.

جيئن مون اڳ ۾ نوٽ ڪيو، پروجيڪٽ تمام ننڍڙو آهي. ان ۾ لڳ ڀڳ 30 هزار لائينون ڪوڊ آھن، جيڪي پنھنجي عمر جي لحاظ کان ڪجھ عجيب آھن. مقابلي لاءِ، FreeRDP تي مشتمل آهي 320 هزار لائينون. ھتي آھي Cloc پروگرام جو ٻاھر نڪتو:

PVS-اسٽوڊيو اينالائيزر استعمال ڪندي 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 هيٺيون صفون ممڪن آهي. '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 کي 'چار' قسم جي قيمت سان مقابلو نه ڪيو وڃي. '(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++;
  }
  ....
}

هتي اسان ڏسون ٿا غلط هينڊلنگ فائل جي آخر تائين پهچڻ جي: جيڪڏهن fgetc ھڪڙو ڪردار موٽائي ٿو جنھن جو ڪوڊ آھي 0xFF، اھو سمجھيو ويندو فائل جي آخر جي طور تي (EOF).

EOF اهو هڪ مستقل آهي، عام طور تي بيان ڪيو ويو آهي -1. مثال طور، CP1251 انڪوڊنگ ۾، روسي الفابيٽ جي آخري اکر جو ڪوڊ 0xFF آهي، جيڪو نمبر -1 سان ملندڙ جلندڙ آهي جيڪڏهن اسان هڪ متغير بابت ڳالهائي رهيا آهيون جهڙوڪ چار هزاري. اهو ظاهر ٿئي ٿو ته علامت 0xFF، وانگر EOF (-1) تفسير ڪئي وئي آهي فائيل جي آخر ۾. اهڙين غلطين کان بچڻ لاء، فنڪشن جو نتيجو آهي fgetc هڪ variable ۾ محفوظ ڪيو وڃي جيئن 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 اظهار هميشه سچو آهي. ممڪن آهي ته '&&' آپريٽر هتي استعمال ڪيو وڃي. ڊسڪ سي 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 (مڪمل رستو، 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 - اوپن سورس ڪوڊ سان آر ڊي پي سرور جو نفاذ. پروجيڪٽ 2 حصن ۾ ورهايل آهي:

  • xrdp - پروٽوڪول تي عمل درآمد. Apache 2.0 لائسنس تحت ورهايو ويو.
  • xorgxrdp - xrdp سان استعمال ڪرڻ لاءِ Xorg ڊرائيورن جو هڪ سيٽ. لائسنس - X11 (جهڙوڪ MIT، پر اشتهارن ۾ استعمال کي منع ڪري ٿو)

منصوبي جي ترقي rdesktop ۽ FreeRDP جي نتيجن تي ٻڌل آهي. شروعات ۾، گرافڪس سان ڪم ڪرڻ لاء، توهان کي هڪ الڳ VNC سرور، يا RDP سپورٽ سان هڪ خاص X11 سرور استعمال ڪرڻو پوندو - X11rdp، پر xorgxrdp جي اچڻ سان، انهن جي ضرورت غائب ٿي وئي.

هن آرٽيڪل ۾ اسين xorgxrdp کي ڍڪي نه سگهنداسين.

xrdp پروجيڪٽ، پوئين هڪ وانگر، تمام ننڍو آهي ۽ لڳ ڀڳ 80 هزار لائينون شامل آهن.

PVS-اسٽوڊيو اينالائيزر استعمال ڪندي 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++;
      }
      ....
  }
  ....
}

هي ڪوڊ librfxcodec لائبريري مان ورتو ويو آهي، جيڪو RemoteFX لاءِ jpeg2000 ڪوڊيڪ لاڳو ڪري ٿو. هتي، ظاهري طور تي، گرافڪ ڊيٽا چينلز کي ملايو ويو آهي - "نيري" رنگ جي بدران، "ڳاڙهو" رڪارڊ ڪيو ويو آهي. اها غلطي گهڻو ڪري ڪاپي پيسٽ جي نتيجي ۾ ظاهر ٿي.

ساڳيو مسئلو ساڳئي فنڪشن ۾ ٿيو 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 صفن کي ختم ڪرڻ ممڪن آهي. '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))
  {
    ....
  }
  ....
}

فنڪشن هڪ قسم جي متغير پڙهي ٿو دستخط ٿيل نن shortو هڪ variable وانگر ۾ 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-اسٽوڊيو اينالائيزر استعمال ڪندي rdesktop ۽ xrdp چيڪ ڪريو

جيڪڏهن توهان هن مضمون کي انگريزي ڳالهائيندڙ سامعين سان حصيداري ڪرڻ چاهيو ٿا، مهرباني ڪري ترجمو لنڪ استعمال ڪريو: سرجي لارين. PVS-Studio سان rdesktop ۽ xrdp چيڪ ڪري رهيو آهي

جو ذريعو: www.habr.com

تبصرو شامل ڪريو