Tcheke rdesktop ak xrdp lè l sèvi avèk analizè PVS-Studio

Tcheke rdesktop ak xrdp lè l sèvi avèk analizè PVS-Studio
Sa a se dezyèm revizyon nan yon seri atik sou tès pwogram sous louvri pou travay ak pwotokòl RDP la. Nan li nou pral gade nan kliyan an rdesktop ak sèvè a xrdp.

Itilize kòm yon zouti pou idantifye erè PVS-estidyoLi se yon analizè kòd estatik pou C, C++, C# ak Java, disponib sou platfòm Windows, Linux и macOS.

Atik la prezante sèlman erè sa yo ki te sanble enteresan pou mwen. Sepandan, pwojè yo piti, kidonk te gen kèk erè :).

Note. Ou ka jwenn yon atik anvan sou tcheke pwojè FreeRDP la isit la.

rdesktop

rdesktop — свободная реализация клиента RDP для UNIX-based систем. Его также можно использовать и под Windows, если собирать проект под Cygwin. Лицензирован под GPLv3.

Kliyan sa a trè popilè - li se itilize pa default nan ReactOS, epi ou ka jwenn tou twazyèm pati grafik front-ends pou li. Sepandan, li se byen fin vye granmoun: premye lage li te fèt sou 4 avril 2001 - nan moman sa a nan ekri a, li gen 17 ane fin vye granmoun.

Kòm mwen te note pi bonè, pwojè a se byen piti. Li gen apeprè 30 mil liy kòd, ki se yon ti jan etranj konsidere laj li. Pou konparezon, FreeRDP gen 320 mil liy. Men pwodiksyon pwogram Cloc la:

Tcheke rdesktop ak xrdp lè l sèvi avèk analizè PVS-Studio

Kòd inaccessible

V779 Kòd ki pa disponib detekte. Li posib ke gen yon erè prezan. 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);
}

Erè a rankontre nou imedyatman nan fonksyon an prensipal: nou wè kòd la ap vini apre operatè a retounen — fragman sa a fè netwayaj memwa. Sepandan, erè a pa reprezante yon menas: tout memwa atribye ba yo pral otorize pa sistèm operasyon an apre pwogram nan sòti.

Pa gen manyen erè

V557 Array underrun posib. Valè 'n' endèks la ka rive nan -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);
  }
  ....
}

Fragman nan kòd nan ka sa a li nan dosye a nan yon tanpon jiskaske dosye a fini. Sepandan, pa gen okenn manyen erè isit la: si yon bagay ale mal, lè sa a li pral retounen -1, ak Lè sa a, etalaj la pral depase pwodiksyon.

Sèvi ak EOF nan kalite char

V739 EOF pa ta dwe konpare ak yon valè nan kalite 'char'. '(c = fgetc(fp))' ta dwe nan kalite '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++;
  }
  ....
}

Isit la nou wè move manyen nan rive nan fen dosye a: si fgetc retounen yon karaktè ki gen kòd se 0xFF, li pral entèprete kòm fen dosye a (EOF).

EOF li se yon konstan, anjeneral defini kòm -1. Pou egzanp, nan kodaj CP1251 la, dènye lèt alfabè Ris la gen kòd 0xFF, ki koresponn ak nimewo a -1 si nou ap pale de yon varyab tankou tank. Li sanble ke senbòl 0xFF a, tankou EOF (-1) entèprete kòm fen dosye a. Pou evite erè sa yo, rezilta a nan fonksyon an se fgetc ta dwe estoke nan yon varyab tankou int.

Typos

Fragman 1

V547 Ekspresyon 'write_time' toujou fo. 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; // <=
  ....
}

Petèt otè kòd sa a te fè l mal || и && nan kondisyon. Ann konsidere opsyon posib pou valè yo ekri_tan и chanje_time:

  • Tou de varyab yo egal a 0: nan ka sa a nou pral fini nan yon branch Lòt Bagay: varyab mod_time ap toujou 0 kèlkeswa kondisyon ki vin apre a.
  • Youn nan varyab yo se 0: mod_time pral egal a 0 (sidi ke lòt varyab la gen yon valè ki pa negatif), paske MIN pral chwazi pi piti a nan de opsyon yo.
  • Tou de varyab yo pa egal a 0: chwazi valè minimòm lan.

Lè ranplase kondisyon an ak write_time && change_time konpòtman an ap gade kòrèk:

  • Youn oswa toude varyab yo pa egal a 0: chwazi yon valè ki pa zewo.
  • Tou de varyab yo pa egal a 0: chwazi valè minimòm lan.

Fragman 2

V547 Ekspresyon se toujou vre. Pwobableman '&&' operatè a ta dwe itilize isit la. 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;
  ....
}

Aparamman operatè yo melanje moute isit la tou || и &&Oswa == и !=: Yon varyab pa ka gen valè 20 ak 9 an menm tan.

Kopi liy san limit

V512 Yon apèl nan 'sprintf' fonksyon an ap mennen nan debòde nan tanpon 'fullpath' la. 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);
  ....
}

Lè ou gade nan fonksyon an konplè, li pral vin klè ke kòd sa a pa lakòz pwoblèm. Sepandan, yo ka leve nan tan kap vini an: yon chanjman neglijan epi nou pral jwenn yon debòde tanpon - sprint pa limite pa anyen, kidonk lè konkatenasyon chemen nou ka ale pi lwen pase limit etalaj la. Li rekòmande pou remake apèl sa a sou snprintf (chemin konplè, PATH_MAX, ....).

Kondisyon redondants

V560 Yon pati nan ekspresyon kondisyonèl toujou vre: ajoute > 0. scard.c 507

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

Проверка ajoute > 0 pa gen okenn bezwen isit la: varyab la ap toujou pi gran pase zewo, paske li % 4 pral retounen rès divizyon an, men li pap janm egal a 4.

xrdp

xrdp — aplikasyon yon sèvè RDP ak kòd sous louvri. Pwojè a divize an 2 pati:

  • xrdp - aplikasyon pwotokòl. Distribiye anba lisans Apache 2.0.
  • xorgxrdp - Yon seri chofè Xorg pou itilize ak xrdp. Lisans - X11 (tankou MIT, men entèdi itilize nan piblisite)

Devlopman pwojè a baze sou rezilta rdesktop ak FreeRDP. Okòmansman, pou travay ak grafik, ou te oblije sèvi ak yon sèvè VNC separe, oswa yon sèvè espesyal X11 ak sipò RDP - X11rdp, men ak avenman xorgxrdp, bezwen pou yo te disparèt.

Nan atik sa a nou pa pral kouvri xorgxrdp.

Pwojè xrdp la, tankou pwojè anvan an, piti anpil e li gen apeprè 80 mil liy.

Tcheke rdesktop ak xrdp lè l sèvi avèk analizè PVS-Studio

Plis fot

V525 Kòd la gen koleksyon blòk menm jan an. Tcheke atik 'r', 'g', 'r' nan liy 87, 88, 89. 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++;
      }
      ....
  }
  ....
}

Kòd sa a te pran nan bibliyotèk librfxcodec, ki aplike codec jpeg2000 pou RemoteFX. Isit la, aparamman, chanèl done grafik yo melanje - olye pou yo koulè "ble" a, "wouj" anrejistre. Erè sa a gen plis chans parèt kòm yon rezilta kopi-kole.

Menm pwoblèm nan te fèt nan yon fonksyon menm jan an rfx_encode_format_argb, ki analizè a te di nou tou:

V525 Kòd la gen koleksyon blòk menm jan an. Tcheke atik 'a', 'r', 'g', 'r' nan liy 260, 261, 262, 263. rfxencode_rgb_to_yuv.c 260

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

Deklarasyon etalaj

V557 Depase etalaj posib. Valè endèks 'i — 8' ka rive nan 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];
    ....
  }
  ....
}

Deklarasyon ak definisyon etalaj la nan de dosye sa yo enkonpatib - gwosè a diferan pa 1. Sepandan, pa gen okenn erè rive - gwosè kòrèk la espesifye nan dosye evdev-map.c, kidonk pa gen okenn limit. Se konsa, sa a se jis yon ensèk ki ka fasil fikse.

Konparezon ki pa kòrèk

V560 Yon pati nan ekspresyon kondisyonèl toujou fo: (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))
  {
    ....
  }
  ....
}

Fonksyon an li yon kalite varyab san siyen kout nan yon varyab tankou int. Tcheke pa nesesè isit la paske nou ap li yon varyab ki pa siyen epi bay rezilta a nan yon varyab ki pi gwo, kidonk varyab la pa ka pran yon valè negatif.

Chèk ki pa nesesè

V560 Yon pati nan ekspresyon kondisyonèl toujou vre: (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;
  }
  ....
}

Chèk inegalite pa fè sans isit la paske nou deja gen yon konparezon nan kòmansman an. Li posib ke sa a se yon typo ak pwomotè a te vle sèvi ak operatè a || pou filtre agiman envalid.

Konklizyon

Pandan odit la, pa gen okenn erè grav yo te idantifye, men anpil enpèfeksyon yo te jwenn. Sepandan, desen sa yo yo te itilize nan anpil sistèm, byenke ti nan dimansyon. Yon ti pwojè pa nesesèman gen anpil erè, kidonk ou pa ta dwe jije pèfòmans analizè a sèlman sou ti pwojè. Ou ka li plis sou sa nan atik la "Santiman ki te konfime pa nimewo".

Ou ka telechaje yon vèsyon jijman PVS-Studio nan men nou Online.

Tcheke rdesktop ak xrdp lè l sèvi avèk analizè PVS-Studio

Si ou vle pataje atik sa a ak yon odyans ki pale angle, tanpri itilize lyen tradiksyon an: Sergey Larin. Tcheke rdesktop ak xrdp ak PVS-Studio

Sous: www.habr.com

Achte hosting serye pou sit ki gen pwoteksyon DDoS, sèvè VPS VDS 🔥 Achte yon hébergement sit entènèt serye ak pwoteksyon DDoS, sèvè VPS VDS | ProHoster