Rdesktop eta xrdp egiaztatzea PVS-Studio analizatzailea erabiliz

Rdesktop eta xrdp egiaztatzea PVS-Studio analizatzailea erabiliz
Hau RDP protokoloarekin lan egiteko kode irekiko programak probatzeari buruzko artikulu batzuen bigarren berrikuspena da. Bertan rdesktop bezeroa eta xrdp zerbitzaria aztertuko ditugu.

Akatsak identifikatzeko tresna gisa erabiltzen da PVS-Studioa. C, C++, C# eta Java lengoaietarako kode estatikoko analizatzaile bat da, Windows, Linux eta macOS plataformetan eskuragarri.

Artikuluak interesgarriak iruditu zaizkidan akatsak baino ez ditu aurkezten. Hala ere, proiektuak txikiak dira, beraz, akats gutxi egon ziren :).

Kontuan izan. FreeRDP proiektuaren egiaztapenari buruzko aurreko artikulu bat aurki daiteke Hemen.

rdesktop

rdesktop — RDP bezero baten doako inplementazioa UNIX-en oinarritutako sistemetarako. Windows-en ere erabil daiteke proiektua Cygwin-en eraikitzen baduzu. GPLv3 lizentziapean.

Bezero hau oso ezaguna da - lehenespenez ReactOSen erabiltzen da, eta hirugarrenen frontend grafikoak ere aurki ditzakezu horretarako. Hala ere, nahiko zaharra da: bere lehen kaleratzea 4eko apirilaren 2001an izan zen - idazteko unean, 17 urte zituen.

Lehen esan dudan bezala, proiektua nahiko txikia da. Gutxi gorabehera 30 mila kode lerro ditu, eta hori arraro samarra da bere adina kontuan hartuta. Konparazio baterako, FreeRDP-k 320 mila lerro ditu. Hona hemen Cloc programaren irteera:

Rdesktop eta xrdp egiaztatzea PVS-Studio analizatzailea erabiliz

Eskuratu ezinezko kodea

V779 Kode erabilgarririk detektatu da. Baliteke erroreren bat egotea. 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);
}

Erroreak berehala egiten du topo funtzioan nagusia: operadorearen atzetik datorren kodea ikusten dugu bueltan — zati honek memoria garbiketa egiten du. Hala ere, erroreak ez du mehatxurik sortzen: esleitutako memoria guztia sistema eragileak garbituko du programa irten ondoren.

Akatsen kudeaketarik ez

V557 Array underrun posible da. 'n' indizearen balioa -1era iritsi daiteke. 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);
  }
  ....
}

Kode zatia kasu honetan fitxategitik buffer batean irakurtzen da fitxategia amaitu arte. Hala ere, hemen ez dago errore-kudeaketarik: zerbait gaizki ateratzen bada, orduan irakurri -1 itzuliko du, eta gero array gainezkatuko da irteera.

EOF erabiltzen char motan

V739 EOF ez da 'char' motako balio batekin alderatu behar. '(c = fgetc(fp))' 'int' motakoa izan behar du. 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++;
  }
  ....
}

Hemen fitxategiaren amaierara iristearen kudeaketa okerra ikusten dugu: bada fgetc 0xFF kodea duen karaktere bat itzultzen du, fitxategiaren amaiera gisa interpretatuko da (EOF).

EOF konstante bat da, normalean -1 gisa definitua. Adibidez, CP1251 kodetzean, errusiar alfabetoaren azken letrak 0xFF kodea du, hau da, -1 zenbakiari dagokion aldagai bati buruz ari bagara. depositua. Bihurtzen da 0xFF ikurra dela, atsegin EOF (-1) fitxategiaren amaiera gisa interpretatzen da. Horrelako akatsak saihesteko, funtzioaren emaitza da fgetc bezalako aldagai batean gorde behar da int.

Akatsak

1. zatia

V547 'Write_time' adierazpena beti da faltsua. diskoa.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; // <=
  ....
}

Beharbada, kode honen egileak gaizki ulertu du || и && egoeran. Azter ditzagun balioen aukera posibleak idatzi_denbora и aldatu_ordua:

  • Bi aldagaiak 0 berdinak dira: kasu honetan adar batean amaituko dugu bestela: aldakorra mod_time 0 izango da beti ondorengo baldintza edozein dela ere.
  • Aldagaietako bat 0 da: mod_time 0ren berdina izango da (betiere beste aldagaiak balio ez-negatiboa badu), zeren MIN bi aukeren artean txikiena aukeratuko du.
  • Bi aldagaiak ez dira 0ren berdinak: aukeratu gutxieneko balioa.

Baldintzarekin ordezkatzean idatzi_ordua && aldatu_ordua portaera zuzena izango da:

  • Aldagai bat edo biak ez dira 0ren berdinak: aukeratu nulua ez den balio bat.
  • Bi aldagaiak ez dira 0ren berdinak: aukeratu gutxieneko balioa.

2. zatia

V547 Adierazpena beti da egia. Ziurrenik hemen '&&' operadorea erabili beharko litzateke. diskoa.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;
  ....
}

Antza denez, hemen ere operadoreak nahasten dira || и &&Edo == и !=: Aldagai batek ezin du 20 eta 9 balioa izan aldi berean.

Lerro kopia mugagabea

V512 'sprintf' funtzioaren deiak 'fullpath' buffer-a gainezkatzea ekarriko du. diskoa.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);
  ....
}

Funtzioa oso-osorik ikusten duzunean, argi geratuko da kode honek ez duela arazorik sortzen. Hala ere, etorkizunean sor daitezke: aldaketa arduragabe bat eta buffer gainezka egingo dugu - esprinta ez dago ezer mugatzen, beraz, bideak kateatzen ditugunean arrayaren mugetatik haratago joan gaitezke. Gomendagarria da deialdi honetan ohartzea snprintf (bide osoa, PATH_MAX, ….).

Baldintza erredundantea

V560 Baldintza adierazpenaren zati bat egia da beti: gehitu > 0. scard.c 507

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

ikuskatzeko gehitu > 0 hemen ez dago beharrik: aldagaia beti izango da zero baino handiagoa, zeren irakurri % 4 zatiketaren gainerakoa itzuliko du, baina inoiz ez da 4ren berdina izango.

xrdp

xrdp — kode irekiko RDP zerbitzari bat ezartzea. Proiektua 2 zatitan banatzen da:

  • xrdp - protokoloaren ezarpena. Apache 2.0 lizentziapean banatuta.
  • xorgxrdp - Xorg kontrolatzaile multzoa xrdp-rekin erabiltzeko. Lizentzia - X11 (MIT bezala, baina iragarkietan erabiltzea debekatzen du)

Proiektuaren garapena rdesktop eta FreeRDPren emaitzetan oinarritzen da. Hasieran, grafikoekin lan egiteko, aparteko VNC zerbitzari bat edo RDP euskarria duen X11 zerbitzari berezi bat erabili behar zenuten - X11rdp, baina xorgxrdp-ren agerpenarekin, horien beharra desagertu egin zen.

Artikulu honetan ez dugu xorgxrdp landuko.

xrdp proiektua, aurrekoa bezala, oso txikia da eta gutxi gorabehera 80 mila lerro ditu.

Rdesktop eta xrdp egiaztatzea PVS-Studio analizatzailea erabiliz

Akats ortografiko gehiago

V525 Kodeak antzeko blokeen bilduma dauka. Egiaztatu 'r', 'g', 'r' elementuak 87, 88, 89 lerroetan. 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++;
      }
      ....
  }
  ....
}

Kode hau RemoteFX-rako jpeg2000 kodeka inplementatzen duen librfxcodec liburutegitik hartu da. Hemen, itxuraz, datu grafikoen kanalak nahasten dira - kolore "urdinaren" ordez, "gorria" grabatzen da. Errore hau kopiatu-itsatsiaren ondorioz agertu da ziurrenik.

Arazo bera gertatu da antzeko funtzio batean rfx_encode_format_argb, analizatzaileak ere esan diguna:

V525 Kodeak antzeko blokeen bilduma dauka. Egiaztatu 'a', 'r', 'g', 'r' elementuak 260, 261, 262, 263 lerroetan. rfxencode_rgb_to_yuv.c 260

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

Array Adierazpena

V557 Array gainditzea posible da. 'i — 8' indizearen balioa 129ra iritsi daiteke. 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];
    ....
  }
  ....
}

Bi fitxategi hauetako array-aren deklarazioa eta definizioa bateraezinak dira - tamaina 1eko desberdina da. Hala ere, ez da akatsik gertatzen - tamaina zuzena evdev-map.c fitxategian zehazten da, beraz, ez dago mugaz kanpo. Beraz, hau erraz konpondu daitekeen akats bat besterik ez da.

Konparaketa okerra

V560 Baldintza adierazpenaren zati bat beti da faltsua: (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))
  {
    ....
  }
  ....
}

Funtzioak mota aldagai bat irakurtzen du sinatu gabeko laburra bezalako aldagai batean int. Hemen ez da egiaztatzea behar sinatu gabeko aldagai bat irakurtzen ari garelako eta emaitza aldagai handiago bati esleitzen diogulako, beraz, aldagaiak ezin du balio negatiborik hartu.

Alferrikako egiaztapenak

V560 Baldintza adierazpenaren zati bat egia da beti: (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;
  }
  ....
}

Desberdintasunen egiaztapenek ez dute zentzurik hemen hasieran konparaketa bat daukagunez. Litekeena da akatsa izatea eta garatzaileak operadorea erabili nahi izatea || argumentu baliogabeak iragazteko.

Ondorioa

Ikuskaritzan, ez da akats larririk antzeman, baina gabezia asko aurkitu dira. Hala ere, diseinu hauek sistema askotan erabiltzen dira, nahiz eta esparru txikia izan. Proiektu txiki batek ez du zertan akats asko izan, beraz, ez zenuke analizatzailearen errendimendua proiektu txikietan soilik epaitu behar. Honi buruz gehiago irakur dezakezu artikuluan "Zenbakiek baieztatu zituzten sentimenduak".

PVS-Studio-ren probako bertsioa deskarga dezakezu guregandik Online.

Rdesktop eta xrdp egiaztatzea PVS-Studio analizatzailea erabiliz

Artikulu hau ingelesez hitz egiten duen publiko batekin partekatu nahi baduzu, mesedez, erabili itzulpen esteka: Sergey Larin. Rdesktop eta xrdp egiaztatzen PVS-Studio-rekin

Iturria: www.habr.com

Gehitu iruzkin berria