ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° rdesktop ΠΈ xrdp с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° PVS-Studio

ο»ΏΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° rdesktop ΠΈ xrdp с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° PVS-Studio
Π­Ρ‚ΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΉ ΠΎΠ±Π·ΠΎΡ€ ΠΈΠ· Ρ†ΠΈΠΊΠ»Π° статСй ΠΎ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ΅ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹Ρ… ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»ΠΎΠΌ RDP. Π’ Π½Π΅ΠΉ ΠΌΡ‹ рассмотрим ΠΊΠ»ΠΈΠ΅Π½Ρ‚ rdesktop ΠΈ сСрвСр xrdp.

Π’ качСствС инструмСнта для выявлСния ошибок использовался PVS-Studio. Π­Ρ‚ΠΎ статичСский Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€ ΠΊΠΎΠ΄Π° для языков C, C++, C# ΠΈ Java, доступный Π½Π° ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ… Windows, Linux ΠΈ macOS.

Π’ ΡΡ‚Π°Ρ‚ΡŒΠ΅ прСдставлСны лишь Ρ‚Π΅ ошибки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ показались ΠΌΠ½Π΅ интСрСсными. Π’ΠΏΡ€ΠΎΡ‡Π΅ΠΌ, ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹ малСнькиС, поэтому ΠΈ ошибок Π±Ρ‹Π»ΠΎ ΠΌΠ°Π»ΠΎ :).

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅. ΠŸΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΡƒΡŽ ΡΡ‚Π°Ρ‚ΡŒΡŽ ΠΎ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° FreeRDP ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ здСсь.

rdesktop

rdesktop β€” свободная рСализация ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° RDP для UNIX-based систСм. Π•Π³ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΠΏΠΎΠ΄ Windows, Ссли ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΏΠΎΠ΄ Cygwin. Π›ΠΈΡ†Π΅Π½Π·ΠΈΡ€ΠΎΠ²Π°Π½ ΠΏΠΎΠ΄ GPLv3.

Π­Ρ‚ΠΎΡ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΠΈΠΌΠ΅Π΅Ρ‚ Π±ΠΎΠ»ΡŒΡˆΡƒΡŽ ΠΏΠΎΠΏΡƒΠ»ΡΡ€Π½ΠΎΡΡ‚ΡŒ β€” ΠΎΠ½ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π² ReactOS, Ρ‚Π°ΠΊΠΆΠ΅ для Π½Π΅Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ сторонниС графичСскиС front-end’Ρ‹. Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, ΠΎΠ½ довольно стар: ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Ρ€Π΅Π»ΠΈΠ· состоялся 4 апрСля 2001 Π³ΠΎΠ΄Π° β€” Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ‚ написания ΡΡ‚Π°Ρ‚ΡŒΠΈ Π΅Π³ΠΎ возраст составляСт 17 Π»Π΅Ρ‚.

Как я ΡƒΠΆΠ΅ ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΠ» Ρ€Π°Π½Π΅Π΅, ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ совсСм малСнький. Он содСрТит ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ 30 тысяч строк ΠΊΠΎΠ΄Π°, Ρ‡Ρ‚ΠΎ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ странно, учитывая Π΅Π³ΠΎ возраст. Для сравнСния, FreeRDP содСрТит Π² сСбС 320 тысяч строк. Π’ΠΎΡ‚ Π²Ρ‹Π²ΠΎΠ΄ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Cloc:

ο»ΏΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° rdesktop ΠΈ xrdp с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° PVS-Studio

НСдостиТимый ΠΊΠΎΠ΄

V779 Unreachable code detected. It is possible that an error is present. 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);
}

Ошибка нас встрСчаСт сразу ΠΆΠ΅ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ main: ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠΎΠ΄, ΠΈΠ΄ΡƒΡ‰ΠΈΠΉ послС ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° return β€” этот Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ осущСствляСт очистку памяти. Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, ошибка Π½Π΅ прСдставляСт ΡƒΠ³Ρ€ΠΎΠ·Ρ‹: вся выдСлСнная ΠΏΠ°ΠΌΡΡ‚ΡŒ вычистится ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмой послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹.

ΠžΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ошибок

V557 Array underrun is possible. The value of ‘n’ index could reach -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);
  }
  ....
}

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ ΠΊΠΎΠ΄Π° Π² этом случаС осущСствляСт Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ ΠΈΠ· Ρ„Π°ΠΉΠ»Π° Π² Π±ΡƒΡ„Π΅Ρ€ Π΄ΠΎ Ρ‚Π΅Ρ… ΠΏΠΎΡ€, ΠΏΠΎΠΊΠ° Ρ„Π°ΠΉΠ» Π½Π΅ закончится. Однако ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок здСсь отсутствуСт: Ссли Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ ΠΏΠΎΠΉΠ΄Π΅Ρ‚ Π½Π΅ Ρ‚Π°ΠΊ, Ρ‚ΠΎ read Π²Π΅Ρ€Π½Π΅Ρ‚ -1, ΠΈ Ρ‚ΠΎΠ³Π΄Π° ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΠ΄Π΅Ρ‚ Π²Ρ‹Ρ…ΠΎΠ΄ Π·Π° Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ массива output.

ИспользованиС EOF Π² Ρ‚ΠΈΠΏΠ΅ char

V739 EOF should not be compared with a value of the ‘char’ type. The ‘(c = fgetc(fp))’ should be of the ‘int’ type. 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++;
  }
  ....
}

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ Π½Π΅ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΡƒΡŽ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ достиТСния ΠΊΠΎΠ½Ρ†Π° Ρ„Π°ΠΉΠ»Π°: Ссли fgetc Π²Π΅Ρ€Π½Π΅Ρ‚ символ, ΠΊΠΎΠ΄ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Ρ€Π°Π²Π΅Π½ 0xFF, Ρ‚ΠΎ ΠΎΠ½ Π±ΡƒΠ΄Π΅Ρ‚ воспринят ΠΊΠ°ΠΊ ΠΊΠΎΠ½Π΅Ρ† Ρ„Π°ΠΉΠ»Π° (EOF).

EOF это константа, опрСдСлСнная ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΊΠ°ΠΊ -1. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Π² ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²ΠΊΠ΅ CP1251 послСдняя Π±ΡƒΠΊΠ²Π° русского Π°Π»Ρ„Π°Π²ΠΈΡ‚Π° ΠΈΠΌΠ΅Π΅Ρ‚ ΠΊΠΎΠ΄ 0xFF, Ρ‡Ρ‚ΠΎ соотвСтствуСт числу -1, Ссли ΠΌΡ‹ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΏΡ€ΠΎ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Ρ‚ΠΈΠΏΠ° char. ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ΡΡ, Ρ‡Ρ‚ΠΎ символ 0xFF, ΠΊΠ°ΠΊ ΠΈ EOF (-1) воспринимаСтся ΠΊΠ°ΠΊ ΠΊΠΎΠ½Π΅Ρ† Ρ„Π°ΠΉΠ»Π°. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹Ρ… ошибок Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ fgetc слСдуСт Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Ρ‚ΠΈΠΏΠ° int.

ΠžΠΏΠ΅Ρ‡Π°Ρ‚ΠΊΠΈ

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 1

V547 Expression ‘write_time’ is always false. 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; // <=
  ....
}

Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Π°Π²Ρ‚ΠΎΡ€ этого ΠΊΠΎΠ΄Π° ΠΏΠ΅Ρ€Π΅ΠΏΡƒΡ‚Π°Π» || ΠΈ && Π² условии. Рассмотрим Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹Π΅ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ write_time ΠΈ change_time:

  • ОбС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Ρ€Π°Π²Π½Ρ‹ 0: Π² этом случаС ΠΌΡ‹ ΠΏΠΎΠΏΠ°Π΄Π΅ΠΌ Π² Π²Π΅Ρ‚ΠΊΡƒ else: пСрСмСнная mod_time всСгда Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π²Π½Π° 0 нСзависимо ΠΎΡ‚ ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ условия.
  • Одна ΠΈΠ· ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Ρ€Π°Π²Π½Π° 0: mod_time Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π²Π½ΠΎ 0 (ΠΏΡ€ΠΈ условии, Ρ‡Ρ‚ΠΎ другая пСрСмСнная ΠΈΠΌΠ΅Π΅Ρ‚ Π½Π΅ΠΎΡ‚Ρ€ΠΈΡ†Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅), Ρ‚. ΠΊ. MIN Π²Ρ‹Π±Π΅Ρ€Π΅Ρ‚ наимСньший ΠΈΠ· Π΄Π²ΡƒΡ… Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ².
  • ОбС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Π½Π΅ Ρ€Π°Π²Π½Ρ‹ 0: Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ минимальноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

ΠŸΡ€ΠΈ Π·Π°ΠΌΠ΅Π½Π΅ условия Π½Π° write_time && change_time ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ станСт Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½Ρ‹ΠΌ:

  • Одна ΠΈΠ»ΠΈ ΠΎΠ±Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Π½Π΅ Ρ€Π°Π²Π½Ρ‹ 0: Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ Π½Π΅Π½ΡƒΠ»Π΅Π²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
  • ОбС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Π½Π΅ Ρ€Π°Π²Π½Ρ‹ 0: Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ минимальноС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 2

V547 Expression is always true. Probably the ‘&&’ operator should be used here. 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;
  ....
}

Π’ΠΈΠ΄ΠΈΠΌΠΎ, здСсь Ρ‚ΠΎΠΆΠ΅ ΠΏΠ΅Ρ€Π΅ΠΏΡƒΡ‚Π°Π½Ρ‹ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Ρ‹ || ΠΈ &&, Π»ΠΈΠ±ΠΎ == ΠΈ !=: пСрСмСнная Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ 20 ΠΈ 9.

НСограничСнноС ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ строки

V512 A call of the ‘sprintf’ function will lead to overflow of the buffer ‘fullpath’. 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);
  ....
}

ΠŸΡ€ΠΈ рассмотрСнии Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ станСт понятно, Ρ‡Ρ‚ΠΎ этот ΠΊΠΎΠ΄ Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ. Однако ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡƒΡ‚ΡŒ Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ: ΠΎΠ΄Π½ΠΎ нСостороТноС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅, ΠΈ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΠΏΠ΅Ρ€Π΅ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π±ΡƒΡ„Π΅Ρ€Π° β€” sprintf Π½ΠΈΡ‡Π΅ΠΌ Π½Π΅ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½, поэтому ΠΏΡ€ΠΈ ΠΊΠΎΠ½ΠΊΠ°Ρ‚Π΅Π½Π°Ρ†ΠΈΠΈ ΠΏΡƒΡ‚Π΅ΠΉ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π²Ρ‹ΠΉΡ‚ΠΈ Π·Π° Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ массива. РСкомСндуСтся Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ этот Π²Ρ‹Π·ΠΎΠ² Π½Π° snprintf(fullpath, PATH_MAX, ….).

Π˜Π·Π±Ρ‹Ρ‚ΠΎΡ‡Π½ΠΎΠ΅ условиС

V560 A part of conditional expression is always true: add > 0. scard.c 507

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

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° add > 0 здСсь Π½ΠΈ ΠΊ Ρ‡Π΅ΠΌΡƒ: пСрСмСнная всСгда Π±ΡƒΠ΄Π΅Ρ‚ большС нуля, Ρ‚. ΠΊ. read % 4 Π²Π΅Ρ€Π½Π΅Ρ‚ остаток ΠΎΡ‚ дСлСния, Π° ΠΎΠ½ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π²Π΅Π½ 4.

xrdp

xrdp β€” рСализация RDP сСрвСра с ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ исходным ΠΊΠΎΠ΄ΠΎΠΌ. ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ Π½Π° 2 части:

  • xrdp β€” рСализация ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Π°. РаспространяСтся ΠΏΠΎΠ΄ Π»ΠΈΡ†Π΅Π½Π·ΠΈΠ΅ΠΉ Apache 2.0.
  • xorgxrdp β€” Π½Π°Π±ΠΎΡ€ Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€ΠΎΠ² Xorg для использования с xrdp. ЛицСнзия β€” X11 (ΠΊΠ°ΠΊ MIT, Π½ΠΎ Π·Π°ΠΏΡ€Π΅Ρ‰Π°Π΅Ρ‚ использованиС Π² Ρ€Π΅ΠΊΠ»Π°ΠΌΠ΅)

Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° базируСтся Π½Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°Ρ… rdesktop ΠΈ FreeRDP. Π˜Π·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠΉ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΠ»ΠΎΡΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ VNC сСрвСр, Π»ΠΈΠ±ΠΎ ΠΆΠ΅ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ сСрвСр X11 с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ RDP β€” X11rdp, ΠΎΠ΄Π½Π°ΠΊΠΎ с появлСниСм xorgxrdp Π½ΡƒΠΆΠ΄Π° Π² Π½ΠΈΡ… ΠΎΡ‚ΠΏΠ°Π»Π°.

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ Π½Π΅ Π±ΡƒΠ΄Π΅ΠΌ Π·Π°Ρ‚Ρ€Π°Π³ΠΈΠ²Π°Ρ‚ΡŒ xorgxrdp.

ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ xrdp, ΠΊΠ°ΠΊ ΠΈ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ, совсСм нСбольшой ΠΈ содСрТит ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ 80 тысяч строк.

ο»ΏΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° rdesktop ΠΈ xrdp с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° PVS-Studio

Π•Ρ‰Π΅ ΠΎΠΏΠ΅Ρ‡Π°Ρ‚ΠΊΠΈ

V525 The code contains the collection of similar blocks. Check items ‘r’, ‘g’, ‘r’ in lines 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++;
      }
      ....
  }
  ....
}

Π­Ρ‚ΠΎΡ‚ ΠΊΠΎΠ΄ Π±Ρ‹Π» взят ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ librfxcodec, Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΡŽΡ‰Π΅ΠΉ ΠΊΠΎΠ΄Π΅ΠΊ jpeg2000 для Ρ€Π°Π±ΠΎΡ‚Ρ‹ RemoteFX. Π—Π΄Π΅ΡΡŒ, ΠΏΠΎ всСй видимости, ΠΏΠ΅Ρ€Π΅ΠΏΡƒΡ‚Π°Π½Ρ‹ ΠΊΠ°Π½Π°Π»Ρ‹ графичСских Π΄Π°Π½Π½Ρ‹Ρ… β€” вмСсто «синСго» Ρ†Π²Π΅Ρ‚Π° записываСтся «красный». Вакая ошибка, скорСС всСго, появилась Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ copy-paste.

Π­Ρ‚Π° ΠΆΠ΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° ΠΏΠΎΠΏΠ°Π»Π° ΠΈ Π² ΡΡ…ΠΎΠΆΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ rfx_encode_format_argb, ΠΎ Ρ‡Π΅ΠΌ Π½Π°ΠΌ Ρ‚ΠΎΠΆΠ΅ сообщил Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€:

V525 The code contains the collection of similar blocks. Check items ‘a’, ‘r’, ‘g’, ‘r’ in lines 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++;
}

ОбъявлСниС массива

V557 Array overrun is possible. The value of ‘i β€” 8’ index could reach 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];
    ....
  }
  ....
}

ОбъявлСниС ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ массива Π² этих Π΄Π²ΡƒΡ… Ρ„Π°ΠΉΠ»Π°Ρ… нСсовмСстимо β€” Ρ€Π°Π·ΠΌΠ΅Ρ€ отличаСтся Π½Π° 1. Однако Π½ΠΈΠΊΠ°ΠΊΠΈΡ… ошибок Π½Π΅ происходит β€” Π² Ρ„Π°ΠΉΠ»Π΅ evdev-map.c ΡƒΠΊΠ°Π·Π°Π½ Π²Π΅Ρ€Π½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€, поэтому Π²Ρ‹Ρ…ΠΎΠ΄Π° Π·Π° Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ Π½Π΅Ρ‚. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ это просто Π½Π΅Π΄ΠΎΡ‡Π΅Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π»Π΅Π³ΠΊΠΎ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ.

НСкоррСктноС сравнСниС

V560 A part of conditional expression is always false: (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))
  {
    ....
  }
  ....
}

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ происходит Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Ρ‚ΠΈΠΏΠ° unsigned short Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Ρ‚ΠΈΠΏΠ° int. ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° здСсь Π½Π΅ Π½ΡƒΠΆΠ½Π°, Ρ‚. ΠΊ. ΠΌΡ‹ считываСм ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ Π±Π΅Π·Π·Π½Π°ΠΊΠΎΠ²ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° ΠΈ присваиваСм Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ большСго Ρ€Π°Π·ΠΌΠ΅Ρ€Π°, поэтому пСрСмСнная Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ ΠΎΡ‚Ρ€ΠΈΡ†Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

НСнуТныС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ

V560 A part of conditional expression is always true: (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;
  }
  ....
}

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π° нСравСнство здСсь Π½Π΅ ΠΈΠΌΠ΅ΡŽΡ‚ смысла, Ρ‚. ΠΊ. Ρƒ нас ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ сравнСниС Π² Π½Π°Ρ‡Π°Π»Π΅. Π’ΠΏΠΎΠ»Π½Π΅ вСроятно, Ρ‡Ρ‚ΠΎ это ΠΎΠΏΠ΅Ρ‡Π°Ρ‚ΠΊΠ° ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Ρ…ΠΎΡ‚Π΅Π» ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ || Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΡ‚Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π΅Π²Π΅Ρ€Π½Ρ‹Π΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

Π’ Ρ…ΠΎΠ΄Π΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π΅ Π±Ρ‹Π»ΠΎ выявлСно ΡΠ΅Ρ€ΡŒΠ΅Π·Π½Ρ‹Ρ… ошибок, Π½ΠΎ нашлось ΠΌΠ½ΠΎΠ³ΠΎ Π½Π΅Π΄ΠΎΡ‡Π΅Ρ‚ΠΎΠ². Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, эти ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Π²ΠΎ ΠΌΠ½ΠΎΠ³ΠΈΡ… систСмах, ΠΏΡƒΡΡ‚ΡŒ ΠΈ ΠΌΠ°Π»Ρ‹ ΠΏΠΎ своСму ΠΎΠ±ΡŠΠ΅ΠΌΡƒ. Π’ нСбольшом ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ Π½Π΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ ΠΌΠ½ΠΎΠ³ΠΎ ошибок, поэтому Π½Π΅ стоит ΡΡƒΠ΄ΠΈΡ‚ΡŒ ΠΎ Ρ€Π°Π±ΠΎΡ‚Π΅ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° ΠΌΠ°Π»Ρ‹Ρ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°Ρ…. ΠŸΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ ΠΎΠ± этом ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΎΡ‡Π΅ΡΡ‚ΡŒ Π² ΡΡ‚Π°Ρ‚ΡŒΠ΅ «ΠžΡ‰ΡƒΡ‰Π΅Π½ΠΈΡ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΠ»ΠΈΡΡŒ числами«.

Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΊΠ°Ρ‡Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Π½ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ PVS-Studio Ρƒ нас Π½Π° сайтС.

ο»ΏΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° rdesktop ΠΈ xrdp с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° PVS-Studio

Если Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ΠΉ с англоязычной Π°ΡƒΠ΄ΠΈΡ‚ΠΎΡ€ΠΈΠ΅ΠΉ, Ρ‚ΠΎ ΠΏΡ€ΠΎΡˆΡƒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ссылку Π½Π° ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄: Sergey Larin. Checking rdesktop and xrdp with PVS-Studio

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com