PVS-Studio பகுப்பாய்வியைப் பயன்படுத்தி rdesktop மற்றும் xrdp ஐச் சரிபார்க்கிறது

PVS-Studio பகுப்பாய்வியைப் பயன்படுத்தி rdesktop மற்றும் xrdp ஐச் சரிபார்க்கிறது
RDP நெறிமுறையுடன் பணிபுரியும் திறந்த மூல நிரல்களை சோதிப்பது பற்றிய கட்டுரைகளின் தொடரில் இது இரண்டாவது மதிப்பாய்வு ஆகும். அதில் நாம் rdesktop கிளையன்ட் மற்றும் xrdp சர்வர் ஆகியவற்றைப் பார்ப்போம்.

பிழைகளைக் கண்டறியும் கருவியாகப் பயன்படுகிறது பி.வி.எஸ்-ஸ்டுடியோ. இது C, C++, C# மற்றும் Java மொழிகளுக்கான நிலையான குறியீடு பகுப்பாய்வி ஆகும், இது Windows, Linux மற்றும் macOS இயங்குதளங்களில் கிடைக்கிறது.

கட்டுரை எனக்கு சுவாரஸ்யமாகத் தோன்றிய பிழைகளை மட்டுமே வழங்குகிறது. இருப்பினும், திட்டங்கள் சிறியவை, எனவே சில தவறுகள் இருந்தன :).

கருத்து. FreeRDP திட்டச் சரிபார்ப்பு பற்றிய முந்தைய கட்டுரையைக் காணலாம் இங்கே.

rdesktop

rdesktop - UNIX-அடிப்படையிலான அமைப்புகளுக்கான RDP கிளையண்டின் இலவச செயலாக்கம். நீங்கள் Cygwin இன் கீழ் திட்டத்தை உருவாக்கினால், விண்டோஸின் கீழும் இதைப் பயன்படுத்தலாம். GPLv3 இன் கீழ் உரிமம் பெற்றது.

இந்த கிளையன்ட் மிகவும் பிரபலமானது - இது ReactOS இல் இயல்பாகப் பயன்படுத்தப்படுகிறது, மேலும் அதற்கான மூன்றாம் தரப்பு வரைகலை முன் முனைகளையும் நீங்கள் காணலாம். இருப்பினும், அவர் மிகவும் வயதானவர்: அவரது முதல் வெளியீடு ஏப்ரல் 4, 2001 அன்று நடந்தது - எழுதும் நேரத்தில், அவருக்கு 17 வயது.

நான் ஏற்கனவே குறிப்பிட்டுள்ளபடி, திட்டம் மிகவும் சிறியது. இது தோராயமாக 30 ஆயிரம் வரிகளைக் கொண்டுள்ளது, இது அதன் வயதைக் கருத்தில் கொண்டு சற்று விசித்திரமானது. ஒப்பிடுகையில், FreeRDP 320 ஆயிரம் வரிகளைக் கொண்டுள்ளது. Clock நிரலின் வெளியீடு இங்கே:

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 ஐ 'சார்' வகையின் மதிப்புடன் ஒப்பிடக்கூடாது. '(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 போன்ற ஒரு மாறியில் சேமிக்கப்பட வேண்டும் எண்ணாக.

எழுத்துப் பிழைகள்

துண்டு 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க்கு சமமாக இல்லை: குறைந்தபட்ச மதிப்பைத் தேர்ந்தெடுக்கவும்.

நிபந்தனையை மாற்றும் போது எழுதும் நேரம் && நேரம்_மாற்றம் நடத்தை சரியாக இருக்கும்:

  • ஒன்று அல்லது இரண்டு மாறிகள் 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 - திறந்த மூலக் குறியீட்டைக் கொண்ட RDP சேவையகத்தை செயல்படுத்துதல். திட்டம் 2 பகுதிகளாக பிரிக்கப்பட்டுள்ளது:

  • xrdp - நெறிமுறை செயல்படுத்தல். Apache 2.0 உரிமத்தின் கீழ் விநியோகிக்கப்பட்டது.
  • xorgxrdp - xrdp உடன் பயன்படுத்த Xorg இயக்கிகளின் தொகுப்பு. உரிமம் - X11 (எம்ஐடி போன்றது, ஆனால் விளம்பரத்தில் பயன்படுத்துவதை தடை செய்கிறது)

திட்டத்தின் வளர்ச்சி 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))
  {
    ....
  }
  ....
}

செயல்பாடு ஒரு வகை மாறியைப் படிக்கிறது கையொப்பமிடாத குறுகிய போன்ற ஒரு மாறியில் எண்ணாக. கையொப்பமிடாத மாறியைப் படித்து அதன் முடிவை ஒரு பெரிய மாறிக்கு ஒதுக்குவதால் சரிபார்ப்பு இங்கு தேவையில்லை, எனவே மாறி எதிர்மறை மதிப்பை எடுக்க முடியாது.

தேவையற்ற சோதனைகள்

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 ஐச் சரிபார்க்கிறது

இந்தக் கட்டுரையை ஆங்கிலம் பேசும் பார்வையாளர்களுடன் பகிர்ந்து கொள்ள விரும்பினால், மொழிபெயர்ப்பு இணைப்பைப் பயன்படுத்தவும்: செர்ஜி லாரின். PVS-Studio மூலம் rdesktop மற்றும் xrdp ஐ சரிபார்க்கிறது

ஆதாரம்: www.habr.com

கருத்தைச் சேர்