Kontrolkirina rdesktop û xrdp bi karanîna analyzera PVS-Studio

Rdesktop û xrdp bi karanîna analîzera PVS-Studio kontrol bikin
Ev nirxandina duyemîn e di rêze gotaran de li ser ceribandina bernameyên çavkaniya vekirî ji bo xebata bi protokola RDP re. Di wê de em ê li muwekîlê rdesktop û servera xrdp binêrin.

Ji bo tespîtkirina xeletiyan wekî amûrek tê bikar anîn PVS Studio. Ew ji bo zimanên C, C++, C# û Java analîzkerek kodê statîk e, li ser platformên Windows, Linux û macOS-ê peyda dibe.

Gotar tenê wan xeletiyên ku ji min re balkêş xuya bûn pêşkêşî dike. Lêbelê, proje piçûk in, ji ber vê yekê kêm xeletî hebûn :).

bingotin. Gotarek berê di derbarê verastkirina projeya FreeRDP de dikare were dîtin vir.

rdesktop

rdesktop - pêkanîna belaş a xerîdarek RDP ji bo pergalên UNIX-ê. Ger hûn projeyê di bin Cygwin de ava bikin ew dikare di bin Windows-ê de jî were bikar anîn. License de di bin GPLv3.

Ev xerîdar pir populer e - ew ji hêla xwerû ve di ReactOS-ê de tê bikar anîn, û hûn dikarin ji bo wê pêşiyên grafîkî yên sêyemîn jî bibînin. Lêbelê, ew pir pîr e: serbestberdana wî ya yekem di 4ê Avrêl, 2001 de pêk hat - di dema nivîsandinê de, ew 17 salî ye.

Wekî ku min berê jî diyar kir, proje pir piçûk e. Nêzîkî 30 hezar rêzikên kodê dihewîne, ku ji ber temenê wê hinekî ecêb e. Ji bo berhevdanê, FreeRDP 320 hezar rêzan dihewîne. Li vir encama bernameya Clocê ye:

Rdesktop û xrdp bi karanîna analîzera PVS-Studio kontrol bikin

Koda ku nayê gihîştin

V779 Koda ne berdest hat tespîtkirin. Dibe ku xeletiyek hebe. 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);
}

Çewtî yekser di fonksiyonê de rastî me tê dest: em dibînin ku koda piştî operatorê tê vegera - ev perçe paqijkirina bîranînê dike. Lêbelê, xeletî tehdîd nake: hemî bîranîna veqetandî dê piştî ku bername derkeve ji hêla pergala xebitandinê ve were paqij kirin.

Desthilatdariya xeletiyê tune

V557 Binpêkirina Array gengaz e. Nirxa 'n' index dikare bigihîje -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);
  }
  ....
}

Di vê rewşê de pişka kodê ji pelê di nav tamponek de dixwîne heya ku pel biqede. Lêbelê, li vir guheztina xeletiyek tune: heke tiştek xelet derkeve, wê hingê xwendin dê vegere -1, û dûv re array dê biqede karûabr.

Bikaranîna EOF di celebê char de

V739 Divê EOF bi nirxek celebê 'char' re neyê berhev kirin. Divê '(c = fgetc(fp))' ji cureya 'int' be. 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++;
  }
  ....
}

Li vir em destwerdana nerast a gihîştina dawiya pelê dibînin: eger fgetc Karaktera ku koda wê 0xFF ye vedigerîne, ew ê wekî dawiya pelê were şîrove kirin (EOF).

EOF ew domdar e, bi gelemperî wekî -1 tê pênase kirin. Mînakî, di şîfrekirina CP1251 de, tîpa paşîn a alfabeya rûsî koda 0xFF heye, ku bi hejmara -1 re têkildar e heke em qala guhêrbarek mîna char. Derket holê ku sembola 0xFF, mîna EOF (-1) wekî dawiya pelê tê şîrove kirin. Ji bo ku ji xeletiyên weha dûr nekevin, encama fonksiyonê ye fgetc divê di guhêrbarek mîna de were hilanîn int.

Çewtiya tîpan

Parçeya 1

V547 Gotina 'write_time' her gav xelet e. dîsk.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; // <=
  ....
}

Dibe ku nivîskarê vê kodê ew xelet kiriye || и && di rewşê de. Werin em vebijarkên gengaz ên ji bo nirxan bifikirin nivîsandin_dem и change_time:

  • Her du guhêrbar jî 0-yê ne: Di vê rewşê de em ê bikevin şaxekê wekîdi: guherbar mod_time dê her dem 0 be bêyî ku şertê paşerojê hebe.
  • Yek ji guherbaran 0 ye: mod_time dê bibe 0 (bi şertê ku guhêrbarek din xwedî nirxek ne-neyînî be), ji ber MIN dê ji her du vebijarkên piçûktir hilbijêrin.
  • Her du guhêrbar ne wekhev in 0: nirxa herî kêm hilbijêrin.

Dema ku şertê bi şûna dema_nivîsandinê && dema_guhertinê tevger dê rast xuya bike:

  • Yek an herdu guhêrbar ne wekhev in 0: nirxek ne-sifir hilbijêrin.
  • Her du guhêrbar ne wekhev in 0: nirxa herî kêm hilbijêrin.

Parçeya 2

V547 Îfade her tim rast e. Dibe ku operatorê '&&' li vir were bikar anîn. dîsk.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;
  ....
}

Xuya ye operator li vir jî tevlihev bûne || и &&an jî == и !=: Guherbarek nikare di heman demê de nirxa 20 û 9 hebe.

Kopîkirina xeta bêsînor

V512 Bangek fonksiyona 'sprintf' dê rê li ber zêdekirina tampon 'tevahî' bigire. dîsk.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);
  ....
}

Dema ku hûn li fonksiyonê bi tevahî mêze bikin, dê diyar bibe ku ev kod nabe sedema pirsgirêkan. Lêbelê, ew dikarin di pêşerojê de çêbibin: Guhertinek bêhiş û em ê zerarek tampon bistînin - sprint ji hêla tiştek ve ne sînorkirî ye, ji ber vê yekê dema ku riyan bi hev ve girêdidin em dikarin ji sînorên rêzê derbas bibin. Tête pêşniyar kirin ku li ser vê bangê hişyar bikin snprintf (tevahî rê, PATH_MAX,….).

Rewşa zêde

V560 Parçeyek bêjeya şertî her dem rast e: lê zêde bike > 0. scard.c 507

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

Kontrola lê zêde bike > 0 li vir ne hewce ye: guhêrbar dê her dem ji sifirê mezintir be, ji ber % 4 bixwînin dê beşa mayî ya dabeşkirinê vegerîne, lê ew ê qet nebe 4.

xrdp

xrdp - pêkanîna serverek RDP bi koda çavkaniya vekirî. Proje ji 2 beşan pêk tê:

  • xrdp - pêkanîna protokolê. Di bin lîsansa Apache 2.0 de belav kirin.
  • xorgxrdp - Komek ajokarên Xorg ji bo karanîna bi xrdp. Lîsans - X11 (mîna MIT, lê di reklamê de karanîna qedexe dike)

Pêşveçûna projeyê li ser encamên rdesktop û FreeRDP-ê ye. Di destpêkê de, ji bo ku hûn bi grafîkê re bixebitin, pêdivî bû ku hûn serverek VNC-ya veqetandî, an serverek X11-a taybetî ya bi piştgiriya RDP - X11rdp bikar bînin, lê bi hatina xorgxrdp re, hewcedariya wan winda bû.

Di vê gotarê de em ê xorgxrdp negirin.

Projeya xrdp, wek ya berê, pir piçûk e û bi qasî 80 hezar rêzan tê de ye.

Rdesktop û xrdp bi karanîna analîzera PVS-Studio kontrol bikin

Zêdetir xeletiyên tîpan

V525 Kod berhevoka blokên wekhev dihewîne. Di rêzên 87, 88, 89 de tiştên 'r', 'g', 'r' binihêrin. 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++;
      }
      ....
  }
  ....
}

Ev kod ji pirtûkxaneya librfxcodec, ku kodek jpeg2000 ji bo RemoteFX bicîh tîne, hate girtin. Li vir, xuya ye, kanalên daneya grafîkî tevlihev dibin - li şûna rengê "şîn", "sor" tê tomar kirin. Ev xeletî bi îhtîmaleke mezin di encama kopî-paste de derket.

Heman pirsgirêk di fonksiyonek wekhev de çêbû rfx_encode_format_argb, ku analîzer jî ji me re got:

V525 Kod berhevoka blokên wekhev dihewîne. Di rêzên 260, 261, 262, 263 de tiştên 'a', 'r', 'g', 'r' binihêrin. rfxencode_rgb_to_yuv.c 260

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

Daxuyaniya Array

V557 Zêdekirina array gengaz e. Nirxa 'i — 8' dikare bigihîje 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];
    ....
  }
  ....
}

Di van her du pelan de danasîn û pênaseya rêzê li hev nayên - mezinahî bi 1-ê cûda ye. Lêbelê, xeletiyek çênabe - mezinahiya rast di pelê evdev-map.c de hatî destnîşan kirin, ji ber vê yekê ji sînoran dernakeve. Ji ber vê yekê ev tenê xeletiyek e ku bi hêsanî dikare were rast kirin.

Berawirdkirina çewt

V560 Beşek îfadeya şertî her dem xelet e: (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))
  {
    ....
  }
  ....
}

Fonksiyon guhêrbarek tîpek dixwîne bê îmze kurt nav guherbareke wek int. Kontrolkirin li vir ne hewce ye ji ber ku em guhêrbarek nenîşankirî dixwînin û encamê ji guhêrbarek mezintir re destnîşan dikin, ji ber vê yekê guhêrbar nikare nirxek neyînî bigire.

Kontrolên nepêwist

V560 Parçeyek bêjeya şertî her dem rast e: (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;
  }
  ....
}

Kontrolên newekheviyê li vir wate nadin ji ber ku di destpêkê de berhevokek me heye. Ihtîmal e ku ev xeletiyek tîpî ye û pêşdebir dixwest ku operator bikar bîne || ji bo fîlterkirina argumanên nederbasdar.

encamê

Di dema kontrolê de xeletiyên cidî nehatin dîtin, lê gelek kêmasî hatin dîtin. Lêbelê, ev sêwiran di gelek pergalan de têne bikar anîn, her çend di çarçoveyek piçûk de bin. Projeyek piçûk ne hewce ye ku gelek xeletî hebe, ji ber vê yekê divê hûn performansa analîzer tenê li ser projeyên piçûk dadbar nekin. Hûn dikarin li ser vê gotarê bêtir bixwînin "Hestên ku bi hejmaran hatine pejirandin".

Hûn dikarin guhertoyek ceribandinê ya PVS-Studio ji me dakêşin malperê.

Rdesktop û xrdp bi karanîna analîzera PVS-Studio kontrol bikin

Heke hûn dixwazin vê gotarê bi temaşevanên îngilîzîaxêv re parve bikin, ji kerema xwe lînka wergerê bikar bînin: Sergey Larin. Kontrolkirina rdesktop û xrdp bi PVS-Studio

Source: www.habr.com

Add a comment