rdesktop ja xrdp kontrollimine PVS-Studio analĂŒsaatori abil

rdesktopi ja xrdp kontrollimine PVS-Studio analĂŒsaatori abil
See on teine ĂŒlevaade artiklite sarjast avatud programmide kontrollimise kohta RDP-protokolliga. Selles vaatleme rdesktop kliendi ja xrdp serveri funktsioone.

Vigade avastamiseks kasutati tööriista PVS-Studio. See on staatiline koodianalĂŒsaator C, C++, C# ja Java keelte jaoks, mis on saadaval Windowsi, Linuxi ja macOS-i platvormidel.

Artiklis esitatakse vaid need vead, mis mulle huvitavad tundusid. TÔele au andes on projektid siiski vÀikesed, seega on ka vigu olnud vÀhe :)

MĂ€rkus. Eelmist artiklit FreeRDP projekti kontrollimisest saab leida siit.

rdesktop

rdesktop — tasuta RDP kliendi rakendus UNIX-pĂ”histe sĂŒsteemide jaoks. Seda saab kasutada ka Windowsis, kui projekti Cygwini all koostada. Litsentseeritud GPLv3 alusel.

See klient on saavutanud suure populaarsuse — seda kasutatakse vaikimisi ReactOSis ning sellele on saadaval ka kolmandate osapoolte graafilised front-end’id. Siiski on see ĂŒsna vana: esimene vĂ€ljalase toimus 4. aprillil 2001 — artikli kirjutamise hetkel on see 17 aastat vana.

Nagu juba mainitud, on projekt vÀga vÀike. See sisaldab umbes 30 tuhat rida koodi, mis on veidi kummaline, arvestades selle vanust. VÔrdluseks: FreeRDP sisaldab endas 320 tuhat rida. Siin on Cloci programmi vÀljund:

rdesktopi ja xrdp kontrollimine PVS-Studio analĂŒsaatori abil

KĂ€imata kood

V779 Tuvastatud on ulatuseta kood. VÔimalik, et viga on olemas. 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);
}

Viga ilmneb kohe funktsioonis main: nĂ€eme koodi, mis jĂ€rgneb operaatorile return — see fragment teostab mĂ€lu puhastust. Siiski ei kujuta viga ohtu: kogu eraldatud mĂ€lu puhastab operatsioonisĂŒsteem pĂ€rast programmi lĂ”petamist.

Vigade töötlemise puudumine

V557 Massiivi alarĂŒnnak on vĂ”imalik. VÀÀrtus 'n' indeks vĂ”ib ulatuda -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);
  }
  ....
}

Selles koodifragmendis loetakse faili sisu puhvris seni, kuni fail on otsas. Siiski puudub siin vigade töötlemine: kui midagi lĂ€heb valesti, siis read tagastab -1, ja siis toimub massiivi piiride ĂŒletamine output.

EOF kasutamine char tĂŒĂŒbina

V739 EOF ei tohiks vĂ”rrelda 'char' tĂŒĂŒbi vÀÀrtusega. '(c = fgetc(fp))' peaks olema 'int' tĂŒĂŒbist. 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++;
  }
  ....
}

Siin nĂ€eme vale töötlemise lĂ”puni fail: kui fgetc tagastab sĂŒmboli, mille kood on 0xFF, siis see tĂ”lgendatakse lĂ”puks failina (EOF).

EOF see on konstant, mis on tavaliselt mÀÀratletud kui -1. NĂ€iteks koodimisvormis CP1251 on vene tĂ€hestiku viimane tĂ€ht koodiga 0xFF, mis vastab numbrile -1, kui me rÀÀgime tĂŒĂŒpi char. Tulemuseks on, et sĂŒmbol 0xFF, nagu ka EOF (-1) tĂ”lgendatakse kui lĂ”pp faili. Selliste vigade vĂ€ltimiseks tuleks funktsiooni tulemused hoida tĂŒĂŒpi fgetc muutujas int.

TrĂŒkivead

Fragment 1

V547 VĂ€ljend 'write_time' on alati vale. 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; // <=
  ....
}

VÔib-olla segas selle koodi autor || ja && tingimuses. Vaatame vÔimalikke vÀÀrtusi write_time ja change_time:

  • MĂ”lemad muutujad on vĂ”rdsed 0: sel juhul satume haru muud: muutuja mod_time on alati 0, olenemata jĂ€rgnevast tingimusest.
  • Üks muutujatest on 0: mod_time on olema 0 (eeldusel, et teine muutuja on mitte-negatiivne), sest MIN valib kahest valikust vĂ€iksema.
  • MĂ”lemad muutujad ei ole 0: valime minimaalne vÀÀrtus.

Kui tingimus asendada write_time && change_time kÀitumine nÀeb vÀlja korrektne:

  • Üks vĂ”i mĂ”lemad muutujad ei ole 0: valime mitte-null vÀÀrtuse.
  • MĂ”lemad muutujad ei ole 0: valime minimaalne vÀÀrtus.

Fragment 2

V547 Avaldis on alati tĂ”si. TĂ”enĂ€oliselt tuleks siin kasutada ‘&&’ operaatorit. 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;
  ....
}

Tundub, et siin on ka operaatorid segamini aetud || ja &&, vÔi == ja !=: muutuja ei saa samaaegselt vÔtta vÀÀrtust 20 ja 9.

Piiramatu stringi kopeerimine

V512 Funktsiooni ‘sprintf’ kutsumine viib ‘fullpath’ puhvri ĂŒleujutamiseni. disk.c 1257

RD_NTSTATUS
disk_query_directory(....)
{
  ....
  char *dirname, fullpath[PATH_MAX];
  ....
  /* Saame teabe katalooge kandva faili kohta */
  sprintf(fullpath, "%s/%s", dirname, pdirent->d_name);
  ....
}

Funktsiooni tĂ€ielikku lĂ€bivaatamist arvesse vĂ”ttes on selge, et see kood ei tekita probleeme. Kuid tulevikus vĂ”ivad need tekkida: ĂŒks ettevaatamatu muudatus ja me saame puhvri ĂŒleujutamise — sprintf pole pole on piiratud, seega vĂ”ivad teede kokkupanemisel meie massiivi piiridest vĂ€lja minna. Soovitame seda kutset jĂ€lgida snprintf(fullpath, PATH_MAX, 
.).

Üksikasjalik tingimus

V560 Osa tingimuslikust vÀljendist on alati tÔene: lisa > 0. scard.c 507

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

Kontrollimine add > 0 siin pole mÔtet: muutuja on alati suurem kui null, kuna read % 4 tagastab jÀÀgi jagamisest, kuid see ei ole kunagi vÔrdne 4-ga.

xrdp

xrdp — avatud lĂ€htekoodiga RDP serveri rakendus. Projekt on jagatud kaheks osaks:

  • xrdp — protokolli rakendus. Jagatakse Apache 2.0 litsentsi alusel.
  • xorgxrdp — Xorg draiverite komplekt, mida kasutatakse koos xrdp-ga. Litsents — X11 (nagu MIT, kuid keelab reklaamides kasutamise)

Projekti arendamine pĂ”hineb rdesktopi ja FreeRDP tulemustel. Alguses oli graafikaga töötamiseks vajalik kasutada eraldi VNC serverit vĂ”i spetsiaalset X11 serverit RDP toe jaoks — X11rdp, kuid xorgxrdp ilmumisega kadus vajadus nende jĂ€rele.

Selles artiklis me xorgxrdp-d ei kÀsitle.

Projekt xrdp, nagu eelmine, on vÀga vÀike ja sisaldab umbes 80 000 rida.

rdesktopi ja xrdp kontrollimine PVS-Studio analĂŒsaatori abil

Veel trĂŒkivigu

V525 Kood sisaldab sarnaste plokkide kogumit. Kontrollige elemente 'r', 'g', 'r' ridades 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++;
      }
      ....
  }
  ....
}

See kood on saadud librfxcodec raamatukogust, mis rakendab jpeg2000 koodeki RemoteFX tööks. Siit nÀib, et graafikandmed on segamini lÀinud - 'sinise' aja asemel salvestatakse 'punane'. Selline viga on tÔenÀoliselt tekkinud copy-paste'i tÔttu.

Sama probleem tabas ka sarnast funktsiooni rfx_encode_format_argb, mille teatas meile ka analĂŒsaator:

V525 Kood sisaldab sarnaste plokkide kogumit. Kontrollige elemente 'a', 'r', 'g', 'r' ridades 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++;
}

Massiivi deklareerimine

V557 Massiivi ĂŒletamine on vĂ”imalik. Indeksi vÀÀrtus 'i - 8' vĂ”ib ulatuda kuni 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];
    ....
  }
  ....
}

Nende kahe faili massiivi deklareerimine ja mÀÀramine on mitteĂŒhtlane — suurus erineb ĂŒhe vĂ”rra. Kuid vigu ei esine — failis evdev-map.c on mÀÀratud Ă”ige suurus, seega pole piiridest vĂ€ljumist. Seega on see lihtsalt viga, mille lihtne parandada.

Vale vÔrdlemine

V560 Osa tingimuslikust vÀljendusest on alati vale: (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))
  {
    ....
  }
  ....
}

Funktsioonis toimub muutuja lugemine tĂŒĂŒbist unsigned short muutujasse tĂŒĂŒbist int. Kontroll siin ei ole vajalik, kuna loeme muutuja mittesisemise tĂŒĂŒbist ja mÀÀrame tulemuse suurema suurusega muutujasse, seega ei saa muutuja vĂ”tta negatiivset vÀÀrtust.

TĂŒhjad kontrollid

V560 Osa tingimuslikust vÀljendusest on alati tÔene: (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;
  }
  ....
}

Kasutatav vĂ”rdsus kontroll siin ei ole mĂ”ttekas, kuna meil on juba alguses vĂ”rdlemine. On tĂ€iesti tĂ”enĂ€oline, et see on trĂŒkiviga ja arendaja tahtis kasutada operaatorit || vale argumentide filtreerimiseks.

KokkuvÔte

Kontrollimisel ei leitud tĂ”siseid vigu, kuid mitmeid puudusi tuli siiski esile. Need projektid on kasutusel paljuski sĂŒsteemides, kuigi nende maht on vĂ€ike. VĂ€ikeses projekti ei pea tingimata olema palju vigu, seega ei tasu analĂŒsaatori tööd hinnata ainult vĂ€ikeste projektide pĂ”hjal. Rohkem teavet leiate artiklist «Tunded, mida numbrid kinnitasid«.

VÔite alla laadida PVS-Studio prooviversiooni meie lehelt veebilehel.

rdesktopi ja xrdp kontrollimine PVS-Studio analĂŒsaatori abil

Kui soovite seda artiklit jagada ingliskeelsele publikule, palun kasutage tÔlke linki: Sergey Larin. rdesktopi ja xrdp kontrollimine PVS-Studio abil

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster