Priksa rdesktop lan xrdp nggunakake analyzer PVS-Studio

Priksa rdesktop lan xrdp nggunakake analisa PVS-Studio
Iki minangka review kapindho ing seri artikel babagan nguji program open source kanggo nggarap protokol RDP. Ing kita bakal katon ing klien rdesktop lan server xrdp.

Digunakake minangka alat kanggo ngenali kesalahan PVS Studio. Iki minangka penganalisa kode statis kanggo basa C, C ++, C # lan Java, kasedhiya ing platform Windows, Linux lan macOS.

Artikel kasebut mung nuduhake kesalahan sing katon menarik kanggo aku. Nanging, proyek kasebut cilik, mula ana sawetara kesalahan :).

komentar. Artikel sadurunge babagan verifikasi proyek FreeRDP bisa ditemokake kene.

rdesktop

rdesktop - implementasi gratis saka klien RDP kanggo sistem basis UNIX. Uga bisa digunakake ing Windows yen sampeyan mbangun proyek ing Cygwin. Dilisensi ing GPLv3.

Klien iki populer banget - digunakake minangka standar ing ReactOS, lan sampeyan uga bisa nemokake ngarep grafis pihak katelu. Nanging, dheweke wis cukup tuwa: release pisanan ing April 4, 2001 - ing wektu nulis, iku 17 taun.

Kaya sing dakkandhakake sadurunge, proyek kasebut cilik banget. Isine kira-kira 30 ewu baris kode, sing rada aneh amarga umure. Kanggo mbandhingake, FreeRDP ngemot 320 ewu baris. Iki minangka output saka program Cloc:

Priksa rdesktop lan xrdp nggunakake analisa PVS-Studio

Kode sing ora bisa digayuh

V779 Kode ora kasedhiya dideteksi. Bisa uga ana kesalahan. 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);
}

Kesalahan ketemu kita langsung ing fungsi utama: kita ndeleng kode teka sawise operator bali - pecahan iki nindakake reresik memori. Nanging, kesalahan ora nyebabake ancaman: kabeh memori sing diparengake bakal dibusak dening sistem operasi sawise program metu.

Ora ana kesalahan penanganan

V557 Array underrun bisa. Nilai indeks 'n' bisa tekan -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);
  }
  ....
}

Potongan kode ing kasus iki diwaca saka file menyang buffer nganti file rampung. Nanging, ora ana kesalahan nangani ing kene: yen ana sing salah, banjur maca bakal bali -1, lan banjur Uploaded bakal overrun Output.

Nggunakake EOF ing jinis char

V739 EOF ngirim ora dibandhingake karo nilai saka jinis 'char'. '(c = fgetc(fp))' kudu saka jinis '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++;
  }
  ....
}

Ing kene kita ndeleng penanganan sing salah kanggo nggayuh pungkasan file: yen fgetc ngasilake karakter sing kode 0xFF, bakal diinterpretasikake minangka pungkasan file (EOF).

EOF iku pancet, biasane ditetepake minangka -1. Contone, ing enkoding CP1251, huruf pungkasan alfabet Rusia duwe kode 0xFF, sing cocog karo nomer -1 yen kita ngomong babagan variabel kaya char. Pranyata metu sing simbol 0xFF, kaya EOF (-1) diinterpretasikake minangka pungkasan file. Kanggo ngindhari kesalahan kasebut, asil saka fungsi kasebut fgetc kudu disimpen ing variabel kaya int.

Salah ketik

Fragmen 1

V547 Ekspresi 'write_time' tansah palsu. 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; // <=
  ....
}

Mungkin penulis kode iki salah || ΠΈ && ing kahanan. Ayo nimbang opsi sing bisa ditrapake kanggo nilai nulis_wektu ΠΈ ganti_wektu:

  • Loro-lorone variabel padha karo 0: ing kasus iki kita bakal mungkasi ing cabang liya: variabel wektu_mod bakal tansah 0 preduli saka kondisi sakteruse.
  • Salah sawijining variabel yaiku 0: wektu_mod bakal padha karo 0 (yen variabel liyane nduweni nilai non-negatif), amarga MIN bakal milih sing luwih cilik saka rong pilihan.
  • Loro-lorone variabel ora padha karo 0: pilih nilai minimal.

Nalika ngganti kondisi karo write_time && change_time prilaku bakal katon bener:

  • Siji utawa loro variabel ora padha karo 0: pilih nilai non-nol.
  • Loro-lorone variabel ora padha karo 0: pilih nilai minimal.

Fragmen 2

V547 Ekspresi tansah bener. Mbokmenawa operator '&&' kudu digunakake ing kene. 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;
  ....
}

Pranyata operator uga campur ing kene || ΠΈ &&, utawa == ΠΈ !=: Variabel ora bisa duwe nilai 20 lan 9 ing wektu sing padha.

Nyalin baris tanpa wates

V512 Telpon fungsi 'sprintf' bakal nyebabake kebanjiran 'fullpath' buffer. 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);
  ....
}

Nalika katon ing fungsi lengkap, bakal dadi cetha yen kode iki ora nimbulakΓ© masalah. Nanging, bisa uga ana ing mangsa ngarep: siji owah-owahan sing sembrono lan kita bakal entuk kebanjiran buffer - sprint ora winates dening apa, supaya nalika concatenating path kita bisa ngluwihi wates saka Uploaded. Disaranake kanggo sok dong mirsani telpon iki ing snprintf(fullpath, PATH_MAX, ….).

Kondisi keluwih

V560 Bagean saka ekspresi kondisional mesthi bener: tambah > 0. scard.c 507

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

pengawasan tambah > 0 ana ora perlu kene: variabel bakal tansah luwih saka nul, amarga maca% 4 bakal ngasilake sisa bagean, nanging ora bakal padha karo 4.

xrdp

xrdp - implementasi server RDP open source. Proyek kasebut dipΓ©rang dadi 2 bagean:

  • xrdp - implementasi protokol. Didistribusikake miturut lisensi Apache 2.0.
  • xorgxrdp - A set driver Xorg kanggo nggunakake xrdp. Lisensi - X11 (kaya MIT, nanging nglarang panggunaan ing pariwara)

Pangembangan proyek kasebut adhedhasar asil rdesktop lan FreeRDP. Kaping pisanan, kanggo nggarap grafis, sampeyan kudu nggunakake server VNC sing kapisah, utawa server X11 khusus kanthi dhukungan RDP - X11rdp, nanging kanthi kedadeyan xorgxrdp, kabutuhan kasebut ilang.

Ing artikel iki kita ora bakal nutupi xorgxrdp.

Proyek xrdp, kaya sing sadurunge, cilik banget lan ngemot kira-kira 80 ewu baris.

Priksa rdesktop lan xrdp nggunakake analisa PVS-Studio

Typo liyane

V525 Kode kasebut ngemot koleksi blok sing padha. Priksa item 'r', 'g', 'r' ing baris 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++;
      }
      ....
  }
  ....
}

Kode iki dijupuk saka perpustakaan librfxcodec, sing ngleksanakake codec jpeg2000 kanggo RemoteFX. Ing kene, ketoke, saluran data grafis dicampur - tinimbang warna "biru", "abang" direkam. Kesalahan iki umume muncul amarga nyalin-tempel.

Masalah sing padha dumadi ing fungsi sing padha rfx_encode_format_argb, sing analisa uga ngandhani:

V525 Kode kasebut ngemot koleksi blok sing padha. Priksa item 'a', 'r', 'g', 'r' ing baris 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++;
}

Deklarasi Array

V557 Array overrun bisa. Nilai indeks 'i β€” 8' bisa tekan 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];
    ....
  }
  ....
}

Pranyatan lan definisi Uploaded ing loro file iki ora kompatibel - ukuran beda-beda 1. Nanging, ora ana kasalahan - ukuran bener kasebut ing file evdev-map.c, supaya ora ana metu saka wates. Dadi iki mung bug sing bisa didandani kanthi gampang.

Bandhingan sing salah

V560 BagΓ©yan saka ekspresi kondisional tansah palsu: (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))
  {
    ....
  }
  ....
}

Fungsi kasebut maca variabel jinis unsigned cendhak dadi variabel kaya int. Priksa ora dibutuhake ing kene amarga kita maca variabel sing ora ditandatangani lan menehi asil menyang variabel sing luwih gedhe, mula variabel kasebut ora bisa njupuk nilai negatif.

Priksa sing ora perlu

V560 Bagean saka ekspresi kondisional tansah bener: (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;
  }
  ....
}

Priksa ketimpangan ora ana gunane amarga kita wis duwe perbandingan ing wiwitan. Kemungkinan iki salah ketik lan pangembang pengin nggunakake operator kasebut || kanggo nyaring argumen sing ora sah.

kesimpulan

Sajrone audit, ora ana kesalahan serius sing diidentifikasi, nanging akeh kekurangan sing ditemokake. Nanging, desain kasebut digunakake ing pirang-pirang sistem, sanajan ukurane cilik. Proyek cilik ora kudu akeh kesalahan, mula sampeyan ora kudu ngadili kinerja penganalisa mung ing proyek cilik. Sampeyan bisa maca liyane babagan iki ing artikel "Perasaan sing dikonfirmasi dening nomer".

Sampeyan bisa ngundhuh versi nyoba PVS-Studio saka kita situs.

Priksa rdesktop lan xrdp nggunakake analisa PVS-Studio

Yen sampeyan pengin nuduhake artikel iki karo pamirsa sing nganggo basa Inggris, gunakake tautan terjemahan: Sergey Larin. Priksa rdesktop lan xrdp karo PVS-Studio

Source: www.habr.com

Add a comment