Ag seiceáil rdesktop agus xrdp ag baint úsáide as an anailíseoir PVS-Studio

rdesktop agus xrdp a sheiceáil ag baint úsáide as an anailíseoir PVS-Studio
Is é seo an dara léirmheas i sraith alt faoi thástáil cláir foinse oscailte chun oibriú leis an bprótacal RDP. In sé féachfaimid ar an gcliant rdesktop agus ar an bhfreastalaí xrdp.

Úsáidte mar uirlis chun earráidí a aithint Stiúideo PVS. Is anailísí cód statach é le haghaidh teangacha C, C++, C# agus Java, atá ar fáil ar ardáin Windows, Linux agus macOS.

Ní chuireann an t-alt i láthair ach na hearráidí sin a bhí suimiúil domsa. Mar sin féin, tá na tionscadail beag, mar sin ní raibh mórán botúin :).

Tabhair faoi deara. Is féidir alt roimhe seo faoi fhíorú tionscadail FreeRDP a fháil anseo.

deasc

deasc — cur i bhfeidhm saor in aisce ar chliant RDP do chórais bunaithe ar UNIX. Is féidir é a úsáid freisin faoi Windows má thógann tú an tionscadal faoi Cygwin. Ceadúnaithe faoi GPLv3.

Tá an-tóir ar an gcliant seo - úsáidtear é de réir réamhshocraithe in ReactOS, agus is féidir foircinn ghrafacha tríú páirtí a fháil dó freisin. Mar sin féin, tá sé sách sean: tharla a chéad scaoileadh ar 4 Aibreán, 2001 - ag an am seo a scríobh, tá sé 17 mbliana d'aois.

Mar a thug mé faoi deara níos luaithe, tá an tionscadal an-bheag. Tá thart ar 30 míle líne de chód ann, rud atá beagán aisteach ag cur san áireamh a aois. Chun comparáid a dhéanamh, tá 320 míle líne ag FreeRDP. Seo é aschur an chláir Cloc:

rdesktop agus xrdp a sheiceáil ag baint úsáide as an anailíseoir PVS-Studio

Cód nach féidir a bhaint amach

V779 Cód nach raibh ar fáil braite. Is féidir go bhfuil earráid i láthair. desktop.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);
}

Tagann an earráid linn láithreach san fheidhm príomh-: feicimid an cód ag teacht i ndiaidh an oibreora ar ais — déanann an blúire seo glanadh cuimhne. Ní bagairt í an earráid, áfach: glanfaidh an córas oibriúcháin gach cuimhne leithdháilte tar éis don chlár imeacht.

Gan láimhseáil earráide

V557 Is féidir fo-rith Eagar. D’fhéadfadh luach innéacs ‘n’ ná -1 a shroicheadh. desktop.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);
  }
  ....
}

Léann an blúire cód sa chás seo ón gcomhad isteach i maolán go dtí go gcríochnaíonn an comhad. Mar sin féin, níl aon láimhseáil earráide anseo: má théann rud éigin mícheart, ansin léamh Beidh ar ais -1, agus ansin beidh an eagar a shárú aschur.

Ag baint úsáide as EOF i gcineál rua

V739 Níor cheart EOF a chur i gcomparáid le luach den chineál ‘char’. Ba cheart go mbeadh an ‘(c = fgetc(fp))’ den chineál ‘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++;
  }
  ....
}

Anseo feicimid láimhseáil mícheart ar bhaint amach deireadh an chomhaid: má fgetc cuireann sé carachtar ar ais arb é 0xFF a chód, léirmhíneofar é mar dheireadh an chomhaid (EOF).

EOF tairiseach é, a shainmhínítear de ghnáth mar -1. Mar shampla, san ionchódú CP1251, tá an cód 0xFF ag an litir dheireanach den aibítir Rúiseach, a fhreagraíonn don uimhir -1 má táimid ag caint faoi athróg cosúil le chariot. Tharlaíonn sé go raibh an tsiombail 0xFF, cosúil EOF (-1) a léirmhíniú mar dheireadh an chomhaid. Chun earráidí den sórt sin a sheachaint, is é toradh na feidhme fgetc chóir a stóráil i athróg cosúil int.

Clóscríbhinní

Mír 1

V547 Bíonn an abairt ‘write_time’ bréagach i gcónaí. diosca.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; // <=
  ....
}

B'fhéidir go bhfuair údar an chóid seo mícheart é || и && i riocht. Déanaimis roghanna féideartha le haghaidh luachanna a mheas scríobh_am и athrú_am:

  • Tá an dá athróg comhionann le 0: sa chás seo beidh muid ag deireadh suas i brainse eile: athróg mod_am beidh sé i gcónaí 0 beag beann ar an riocht ina dhiaidh sin.
  • Is é 0 ceann de na hathróga: mod_am cothrom le 0 (ar choinníoll go bhfuil luach neamhdhiúltach ag an athróg eile), mar gheall ar MIN roghnóidh sé an ceann is lú den dá rogha.
  • Níl an dá athróg cothrom le 0: roghnaigh an luach íosta.

Nuair a athsholáthar an coinníoll le scríobh_am && change_time beidh cuma cheart ar an iompar:

  • Níl athróg amháin nó an dá athróg cothrom le 0: roghnaigh luach neamh-nialais.
  • Níl an dá athróg cothrom le 0: roghnaigh an luach íosta.

Mír 2

V547 Tá an abairt fíor i gcónaí. Is dócha gur cheart an t-oibreoir ‘&&’ a úsáid anseo. diosca.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;
  ....
}

Is cosúil go bhfuil na hoibreoirí measctha suas anseo freisin || и &&== и !=: Ní féidir le luach 20 agus 9 a bheith ag athróg ag an am céanna.

Cóipeáil líne gan teorainn

V512 Má dhéantar glaoch ar an bhfeidhm ‘sprintf’, beidh an ‘lánchosán’ maolánach ag dul thar maoil. diosca.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);
  ....
}

Nuair a fhéachann tú ar an bhfeidhm ina hiomláine, beidh sé soiléir nach bhfuil an cód seo ina chúis le fadhbanna. Mar sin féin, féadfaidh siad teacht chun cinn sa todhchaí: athrú míchúramach amháin agus gheobhaidh muid maolán thar maoil - sprint nach bhfuil teoranta ag rud ar bith, mar sin nuair a concatenating cosáin is féidir linn dul thar theorainneacha an eagar. Moltar an glao seo a thabhairt faoi deara ar snprintf(lánchosán, PATH_MAX, ….).

Coinníoll iomarcach

V560 Bíonn cuid de shloinneadh coinníollach fíor i gcónaí: cuir > 0. scard.c 507

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

Проверка cuir > 0 leis níl aon ghá anseo: beidh an athróg níos mó ná nialas i gcónaí, mar gheall ar léigh % 4 tabharfaidh sé ar ais an chuid eile den roinn, ach ní bheidh sé cothrom le 4 go deo.

xrdp

xrdp — freastalaí RDP le cód foinse oscailte a chur i bhfeidhm. Tá an tionscadal roinnte ina 2 chuid:

  • xrdp - cur i bhfeidhm prótacail. Dáilte faoi cheadúnas Apache 2.0.
  • xorgxrdp - Sraith de thiománaithe Xorg le húsáid le xrdp. Ceadúnas - X11 (cosúil le MIT, ach cosc ​​ar úsáid i bhfógraíocht)

Tá forbairt an tionscadail bunaithe ar thorthaí rdesktop agus FreeRDP. Ar dtús, chun oibriú le grafaicí, bhí ort freastalaí VNC ar leith a úsáid, nó freastalaí X11 speisialta le tacaíocht RDP - X11rdp, ach le teacht xorgxrdp, d'imigh an gá leo.

San Airteagal seo ní bheidh muid ag clúdach xorgxrdp.

Tá an tionscadal xrdp, cosúil leis an gceann roimhe seo, an-bheag agus tá thart ar 80 míle líne ann.

rdesktop agus xrdp a sheiceáil ag baint úsáide as an anailíseoir PVS-Studio

Tuilleadh typos

V525 Tá bailiúchán bloic den chineál céanna sa chód. Seiceáil míreanna 'r', 'g', 'r' i línte 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++;
      }
      ....
  }
  ....
}

Tógadh an cód seo ón leabharlann librfxcodec, a chuireann an CODEC jpeg2000 do RemoteFX i bhfeidhm. Anseo, de réir dealraimh, measctar na bealaí grafacha sonraí - in ionad an dath “gorm”, déantar “dearg” a thaifeadadh. Is dócha gur tharla an earráid seo mar thoradh ar chóipghreamú.

Tharla an fhadhb chéanna i bhfeidhm den chineál céanna rfx_ionchódú_format_argb, a d'inis an anailíseoir dúinn freisin:

V525 Tá bailiúchán bloic den chineál céanna sa chód. Seiceáil míreanna 'a', 'r', 'g', 'r' i línte 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++;
}

Dearbhú Array

V557 Is féidir róchaiteachas Eagar. D’fhéadfadh luach innéacs ‘i — 8’ 129 a shroicheadh. 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];
    ....
  }
  ....
}

Níl an dearbhú agus an sainmhíniú ar an eagar sa dá chomhad seo comhoiriúnach - tá difríocht idir an méid faoi 1. Mar sin féin, ní tharlaíonn aon earráidí - sonraítear an méid ceart sa chomhad evdev-map.c, agus mar sin níl aon teorainneacha amuigh. Mar sin níl anseo ach fabht is féidir a shocrú go héasca.

Comparáid mhícheart

V560 Bíonn cuid den léiriú coinníollach bréagach i gcónaí: (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))
  {
    ....
  }
  ....
}

Léann an fheidhm athróg cineáil gearr gan síniú isteach i athróg cosúil int. Ní gá seiceáil a dhéanamh anseo toisc go bhfuil athróg neamhshínithe á léamh againn agus an toradh á shannadh d'athróg níos mó, mar sin ní féidir leis an athróg luach diúltach a ghlacadh.

Seiceálacha gan ghá

V560 Bíonn cuid de léiriú coinníollach fíor i gcónaí: (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;
  }
  ....
}

Ní dhéanann seiceálacha éagothroime ciall anseo mar tá comparáid againn cheana féin ag an tús. Is dócha gur clóscríobh é seo agus bhí an forbróir ag iarraidh an t-oibreoir a úsáid || chun argóintí neamhbhailí a scagadh.

Conclúid

Le linn an iniúchta, níor aithníodh aon earráidí tromchúiseacha, ach fuarthas go leor easnaimh. Mar sin féin, úsáidtear na dearaí seo i go leor córas, cé go bhfuil raon feidhme beag acu. Ní gá go mbeadh go leor earráidí i dtionscadal beag, mar sin níor cheart duit feidhmíocht an anailíseora a mheas ach ar thionscadail bheaga. Is féidir leat tuilleadh a léamh faoi seo san alt “Mothúcháin a bhí deimhnithe ag uimhreacha".

Is féidir leat leagan trialach de PVS-Studio a íoslódáil uainn Líne.

rdesktop agus xrdp a sheiceáil ag baint úsáide as an anailíseoir PVS-Studio

Más mian leat an t-alt seo a roinnt le lucht féachana Béarla, bain úsáid as an nasc aistriúcháin: Sergey Larin. Ag seiceáil rdesktop agus xrdp le PVS-Studio

Foinse: will.com

Add a comment