PVS-Studio تجزیہ کار کا استعمال کرتے ہوئے rdesktop اور xrdp کو چیک کرنا

PVS-Studio تجزیہ کار کا استعمال کرتے ہوئے rdesktop اور xrdp کو چیک کرنا
RDP پروٹوکول کے ساتھ کام کرنے کے لیے اوپن سورس پروگراموں کی جانچ کے بارے میں مضامین کی ایک سیریز میں یہ دوسرا جائزہ ہے۔ اس میں ہم rdesktop کلائنٹ اور xrdp سرور کو دیکھیں گے۔

غلطیوں کی شناخت کے لیے ایک ٹول کے طور پر استعمال کیا جاتا ہے۔ PVS- اسٹوڈیو. یہ C، C++، C# اور Java زبانوں کے لیے ایک جامد کوڈ تجزیہ کار ہے، جو Windows، Linux اور macOS پلیٹ فارمز پر دستیاب ہے۔

مضمون میں صرف وہی غلطیاں پیش کی گئی ہیں جو مجھے دلچسپ لگیں۔ تاہم، منصوبے چھوٹے ہیں، اس لیے کچھ غلطیاں تھیں :)۔

نوٹ. FreeRDP پروجیکٹ کی تصدیق کے بارے میں ایک پچھلا مضمون پایا جا سکتا ہے۔ یہاں.

rdesktop

rdesktop - UNIX پر مبنی سسٹمز کے لیے RDP کلائنٹ کا مفت نفاذ۔ اگر آپ سائگ وین کے تحت پروجیکٹ بناتے ہیں تو اسے ونڈوز کے تحت بھی استعمال کیا جاسکتا ہے۔ GPLv3 کے تحت لائسنس یافتہ۔

یہ کلائنٹ بہت مشہور ہے - یہ ReactOS میں بطور ڈیفالٹ استعمال ہوتا ہے، اور آپ اس کے لیے تھرڈ پارٹی گرافیکل فرنٹ اینڈز بھی تلاش کر سکتے ہیں۔ تاہم، وہ کافی بوڑھا ہے: اس کی پہلی ریلیز 4 اپریل 2001 کو ہوئی تھی - لکھنے کے وقت اس کی عمر 17 سال تھی۔

جیسا کہ میں نے پہلے ذکر کیا، یہ منصوبہ بہت چھوٹا ہے۔ اس میں کوڈ کی تقریباً 30 ہزار لائنیں ہیں، جو اس کی عمر کو دیکھتے ہوئے قدرے عجیب ہے۔ مقابلے کے لیے، FreeRDP 320 ہزار لائنوں پر مشتمل ہے۔ یہاں کلاک پروگرام کا آؤٹ پٹ ہے:

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 سرنی انڈررن ممکن ہے۔ '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 کے برابر ہوگا (بشرطیکہ دوسرے متغیر کی غیر منفی قدر ہو)، کیونکہ MIN دو اختیارات میں سے چھوٹے کا انتخاب کریں گے۔
  • دونوں متغیرات 0 کے برابر نہیں ہیں: کم از کم قدر منتخب کریں۔

کے ساتھ شرط کو تبدیل کرتے وقت write_time && change_time سلوک درست نظر آئے گا:

  • ایک یا دونوں متغیرات 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' فنکشن کی کال بفر 'فل پاتھ' کے اوور فلو کا باعث بنے گی۔ 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 - پروٹوکول کا نفاذ۔ اپاچی 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++;
      }
      ....
  }
  ....
}

یہ کوڈ 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))
  {
    ....
  }
  ....
}

فنکشن ایک قسم کے متغیر کو پڑھتا ہے۔ دستخط شدہ مختصر جیسے متغیر میں 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

نیا تبصرہ شامل کریں