- PVSM.RU - https://www.pvsm.ru -

Дефекты безопасности, которые устранила команда PVS-Studio на этой неделе: выпуск N3

Правим потенциальные уязвимости
Мы решили в меру своих сил регулярно искать и устранять потенциальные уязвимости и баги в различных проектах. Можно назвать это помощью open-source проектам. Можно — разновидностью рекламы или тестированием анализатора. Еще вариант — очередной способ привлечения внимания к вопросам качества и надёжности кода. На самом деле, не важно название, просто нам нравится это делать. Назовём это необычным хобби. Давайте посмотрим, что интересного было обнаружено в коде различных проектов на этой неделе. Мы нашли время сделать исправления и предлагаем вам ознакомиться с ними.

Для тех, кто ещё не знаком с инструментом PVS-Studio

PVS-Studio [1] — это инструмент, который выявляет в коде многие разновидности ошибок и уязвимостей. PVS-Studio выполняет статический анализ кода и рекомендует программисту обратить внимание на участки программы, в которых с большой вероятностью содержатся ошибки. Наилучший эффект достигается тогда, когда статический анализ выполняется регулярно. Идеологически предупреждения анализатора подобны предупреждениям компилятора. Но в отличии от компиляторов, PVS-Studio выполняет более глубокий и разносторонний анализ кода. Это позволяет ему находить ошибки в том числе и в компиляторах: GCC [2]; LLVM 1 [3], 2 [4], 3 [5]; Roslyn [6].

Поддерживается анализ кода на языках C, C++ и C#. Анализатор работает под управлением Windows и Linux. В Windows анализатор может интегрироваться как плагин в Visual Studio.

Для дальнейшего знакомства с анализатором, предлагаем изучить следующие материалы:

Потенциальные уязвимости (weaknesses)

В этом разделе приведены дефекты, которые попадают под классификацию CWE и, по сути, являются потенциальными уязвимостями. Конечно, не в каждом проекте дефекты безопасности создают какую-то практическую угрозу, но хочется продемонстрировать, что мы умеем находить подобные ситуации.

1. MSBuild. CWE-476 (NULL Pointer Dereference)

  • V3095 The 'searchLocation' object was used before it was verified against null. Check lines: 170, 178. Microsoft.Build.Tasks Resolver.cs 170
  • V3095 The 'searchLocation' object was used before it was verified against null. Check lines: 249, 264. Microsoft.Build.Tasks Resolver.cs 249
  • V3095 The 'assemblyName' object was used before it was verified against null. Check lines: 176, 194. Microsoft.Build.Tasks Resolver.cs 176

protected bool FileMatchesAssemblyName
(
  AssemblyNameExtension assemblyName,
  ....
  ResolutionSearchLocation searchLocation
)
{
  searchLocation.FileNameAttempted =  // <=
    pathToCandidateAssembly;
  ....
  if (String.Compare(assemblyName.Name, ....) != 0)  // <=
  {
    ....
  }
  ....
  if (searchLocation != null)
  {
    ....
  }
  ....
  bool isSimpleAssemblyName = assemblyName == null ? 
    false : assemblyName.IsSimpleName;
  ....
  searchLocation.Reason =  // <=
    NoMatchReason.ProcessorArchitectureDoesNotMatch;
  ....
  if (searchLocation != null)
  {
    ....
  }
  ....
}

Report: https://github.com/Microsoft/msbuild/pull/1891 [11]

2. MSBuild. CWE-476 (NULL Pointer Dereference)

V3095 [12] The 'e' object was used before it was verified against null. Check lines: 165, 170. MSBuild InitializationException.cs 165

internal static void Throw(string messageResourceName,
  string invalidSwitch, Exception e, bool showStackTrace)
{
  ....
  if (showStackTrace)
  {
    errorMessage += Environment.NewLine + e.ToString();  // <=
  }
  else
  {
    errorMessage = ResourceUtilities.FormatString(errorMessage, 
      ((e == null) ? String.Empty : e.Message));
  }
  ....
}

Report: https://github.com/Microsoft/msbuild/pull/1891 [11]

3. Entity Framework. CWE-670 (Always-Incorrect Control Flow Implementation)

V3014 [13] It is likely that a wrong variable is being incremented inside the 'for' operator. Consider reviewing 'i'. EFCore ExpressionEqualityComparer.cs 214

V3015 [14] It is likely that a wrong variable is being compared inside the 'for' operator. Consider reviewing 'i' EFCore ExpressionEqualityComparer.cs 214

var memberInitExpression = (MemberInitExpression)obj;
....
for (var i = 0; i < memberInitExpression.Bindings.Count; i++)
{
  var memberBinding = memberInitExpression.Bindings[i];
  .... 
  switch (memberBinding.BindingType)
  {
    case ....
    case MemberBindingType.ListBinding:
      var memberListBinding = (MemberListBinding)memberBinding;
      for(var j=0; 
              i < memberListBinding.Initializers.Count;    // <=
              i++)                                         // <=
      {
        hashCode += (hashCode * 397) ^
        GetHashCode(memberListBinding.Initializers[j].Arguments);
      }
      break;
    ....
   }
}

Report: https://github.com/aspnet/EntityFramework/pull/7909 [15]

4. Entity Framework. CWE-670 (Always-Incorrect Control Flow Implementation)

V3081 [16] The 'j' counter is not used inside a nested loop. Consider inspecting usage of 'i' counter. EFCore.Specification.Tests ComplexNavigationsQueryTestBase.cs 2393

for (var i = 0; i < result.Count; i++)
{
  var expectedElement = expected
    .Single(e => e.Name == result[i].Name);
    
  var expectedInnerNames = expectedElement
    .OneToMany_Optional.Select(e => e.Name)
    .ToList();
    
  for (var j = 0; j < expectedInnerNames.Count; j++)    // <=
  {
    Assert.True
    (
      result[i]
      .OneToMany_Optional.Select(e => e.Name)
      .Contains(expectedInnerNames[i])                  // <=
    );
  }
}

Report: https://github.com/aspnet/EntityFramework/pull/7909 [15]

5. CoreCLR. CWE-188 (Reliance on Data/Memory Layout)

V557 [17] Array overrun is possible. The value of 'dwCode — 1' index could reach 8. cordbdi rsmain.cpp 67

const char * GetDebugCodeName(DWORD dwCode)
{
  if (dwCode < 1 || dwCode > 9)
  {
    return "!Invalid Debug Event Code!";
  }

  static const char * const szNames[] = {
    "(1) EXCEPTION_DEBUG_EVENT",
    "(2) CREATE_THREAD_DEBUG_EVENT",
    ....
    "(8) OUTPUT_DEBUG_STRING_EVENT"         // <=
    "(9) RIP_EVENT",
  };

  return szNames[dwCode - 1];
}

Report: https://github.com/dotnet/coreclr/pull/10417 [18]

6. FreeBSD. CWE-561 (Unreachable code detected)

V779 [19] Unreachable code detected. It is possible that an error is present. mps.c 1306

static int
mps_alloc_requests(struct mps_softc *sc)
{
  ....
    else {
      panic("failed to allocate command %dn", i);
      sc->num_reqs = i;
      break;
    }
  ....
}

Report: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218002 [20]

7. FreeBSD. CWE-561 (Unreachable code detected)

V779 [19] Unreachable code detected. It is possible that an error is present. efx_mcdi.c 910

void
efx_mcdi_ev_death(
  __in    efx_nic_t *enp,
  __in    int rc)
{
  ....
  efx_mcdi_raise_exception(enp, emrp, rc);

  if (emrp != NULL && ev_cpl)
   emtp->emt_ev_cpl(emtp->emt_context);
}

Report: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218004 [21]

8. FreeBSD. CWE-561 (Unreachable code detected)

V779 [19] Unreachable code detected. It is possible that an error is present. sctp_pcb.c 183

struct sctp_vrf *
sctp_allocate_vrf(int vrf_id)
{
  ....
  if (vrf->vrf_addr_hash == NULL) {
    /* No memory */
#ifdef INVARIANTS
    panic("No memory for VRF:%d", vrf_id);
#endif
    SCTP_FREE(vrf, SCTP_M_VRF);
    return (NULL);
  }
  ....
}

Report: bugs.freebsd.org/bugzilla/show_bug.cgi?id=218005 [22]

10. FreeBSD. CWE-570 (Expression is Always False)

V547 [23] Expression 'value < 0' is always false. Unsigned type value is never < 0. ar9300_xmit.c 450

HAL_BOOL
ar9300_reset_tx_queue(struct ath_hal *ah, u_int q)
{
  u_int32_t cw_min, chan_cw_min, value;
  ....
  value = (ahp->ah_beaconInterval * 50 / 100)
    - ah->ah_config.ah_additional_swba_backoff
    - ah->ah_config.ah_sw_beacon_response_time
    + ah->ah_config.ah_dma_beacon_response_time;
  if (value < 10)
    value = 10;
  if (value < 0)
    value = 10;
  ....
}

Report: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218007 [24]

11. FreeBSD. CWE-571 (Expression is Always True)

V617 [25] Consider inspecting the condition. The '0x00000080' argument of the '|' bitwise operation contains a non-zero value. mac_bsdextended.c 128

#define  MBO_TYPE_DEFINED 0x00000080

static int
ugidfw_rule_valid(struct mac_bsdextended_rule *rule)
{
  ....
  if ((rule->mbr_object.mbo_neg | MBO_TYPE_DEFINED) &&      // <=
      (rule->mbr_object.mbo_type | MBO_ALL_TYPE) != MBO_ALL_TYPE)
    return (EINVAL);
  if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
    return (EINVAL);
  return (0);
}

Report: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218039 [26]

Прочие ошибки

1. FreeBSD

V646 [27] Consider inspecting the application's logic. It's possible that 'else' keyword is missing. if_em.c 1944

static int
em_if_msix_intr_assign(if_ctx_t ctx, int msix) 
{
  ....
  if (adapter->hw.mac.type < igb_mac_min) {
    tx_que->eims = 1 << (22 + i);
    adapter->ims |= tx_que->eims;
    adapter->ivars |= (8 | tx_que->msix) << (8 + (i * 4));
  } if (adapter->hw.mac.type == e1000_82575)                // <=
    tx_que->eims =
      E1000_EICR_TX_QUEUE0 << (i %  adapter->tx_num_queues);
  else
    tx_que->eims = 1 << (i %  adapter->tx_num_queues);
  ....
}

Report: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218041 [28]

2. CoreCLR

V534 [29] It is likely that a wrong variable is being compared inside the 'for' operator. Consider reviewing 'i'. ildasm mdinfo.cpp 1421

void MDInfo::DisplayFields(mdTypeDef inTypeDef,
                           COR_FIELD_OFFSET *rFieldOffset,
                           ULONG cFieldOffset)
 {
  ....
  for (ULONG i = 0; i < count; i++, totalCount++)
  {
    ....
    for (ULONG iLayout = 0; i < cFieldOffset; ++iLayout)  // <=
    {
      if (RidFromToken(rFieldOffset[iLayout].ridOfField) ==
          RidFromToken(fields[i]))
      {
        ....
      }
    }
  }
  ....
}

Report: https://github.com/dotnet/coreclr/pull/10414 [30]

Заключение

Предлагаем скачать анализатор PVS-Studio и попробовать проверить ваш проект:

Для снятия ограничения [33] демонстрационной версии, вы можете написать [34] нам, и мы отправим вам временный ключ.

Для быстрого знакомства с анализатором, вы можете воспользоваться утилитами, отслеживающими запуски компилятора и собирающие для проверки всю необходимую информацию. См. описание утилиты CLMonitoring [35] и pvs-studio-analyzer [36]. Если вы работаете с классическим типом проекта в Visual Studio, то всё ещё проще: достаточно выбрать в меню PVS-Studio команду «Check Solution».

Автор: PVS-Studio

Источник [37]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/c-2/250708

Ссылки в тексте:

[1] PVS-Studio: https://www.viva64.com/ru/pvs-studio/

[2] GCC: https://www.viva64.com/ru/b/0425/

[3] 1: https://www.viva64.com/ru/b/0108/

[4] 2: https://www.viva64.com/ru/b/0155/

[5] 3: https://www.viva64.com/ru/b/0446/

[6] Roslyn: https://www.viva64.com/ru/b/0363/

[7] презентация: https://www.slideshare.net/Andrey_Karpov/pvsstudio-static-code-analyzer-windowslinux-ccc-2017

[8] видео: https://www.youtube.com/watch?v=kmqF130pQW8&amp;feature=youtu.be

[9] Статьи: https://www.viva64.com/ru/inspections/

[10] PVS-Studio: поиск дефектов безопасности: https://www.viva64.com/ru/b/0486/

[11] https://github.com/Microsoft/msbuild/pull/1891: https://github.com/Microsoft/msbuild/pull/1891

[12] V3095: http://www.viva64.com/ru/w/v3095/

[13] V3014: http://www.viva64.com/ru/w/v3014/

[14] V3015: http://www.viva64.com/ru/w/v3015/

[15] https://github.com/aspnet/EntityFramework/pull/7909: https://github.com/aspnet/EntityFramework/pull/7909

[16] V3081: http://www.viva64.com/ru/w/v3081/

[17] V557: http://www.viva64.com/ru/w/v557/

[18] https://github.com/dotnet/coreclr/pull/10417: https://github.com/dotnet/coreclr/pull/10417

[19] V779: http://www.viva64.com/ru/w/v779/

[20] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218002: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218002

[21] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218004: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218004

[22] bugs.freebsd.org/bugzilla/show_bug.cgi?id=218005: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218005

[23] V547: http://www.viva64.com/ru/w/v547/

[24] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218007: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218007

[25] V617: http://www.viva64.com/ru/w/v617/

[26] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218039: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218039

[27] V646: http://www.viva64.com/ru/w/v646/

[28] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218041: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=218041

[29] V534: http://www.viva64.com/ru/w/v534/

[30] https://github.com/dotnet/coreclr/pull/10414: https://github.com/dotnet/coreclr/pull/10414

[31] PVS-Studio для Windows: https://www.viva64.com/ru/pvs-studio-download/

[32] PVS-Studio для Linux: https://www.viva64.com/ru/pvs-studio-download-linux/

[33] ограничения: https://www.viva64.com/ru/m/0009/

[34] написать: https://www.viva64.com/ru/about-feedback/

[35] CLMonitoring: https://www.viva64.com/ru/m/0031/

[36] pvs-studio-analyzer: https://www.viva64.com/ru/m/0036/

[37] Источник: https://habrahabr.ru/post/324802/