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

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


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

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

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

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


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

1. Clang. CWE-571 (Expression is Always True)

V768 The enumeration constant 'S_MOVRELS_B64' is used as a variable of a Boolean-type. gcnhazardrecognizer.cpp 75

namespace AMDGPU {
  enum {
    ....
    S_MOVRELS_B64 = 4043,
    ....
  };
}

static bool isSMovRel(unsigned Opcode) {
  return
    Opcode == AMDGPU::S_MOVRELS_B32 || AMDGPU::S_MOVRELS_B64 ||
    Opcode == AMDGPU::S_MOVRELD_B32 || AMDGPU::S_MOVRELD_B64;
}

Pull Request: https://bugs.llvm.org/show_bug.cgi?id=32248

2. Clang. CWE-457 (Use of Uninitialized Variable)

V573 Uninitialized variable 'BytesToDrop' was used. The variable was used to initialize itself. typerecordmapping.cpp 73

static Error mapNameAndUniqueName(....) {
  ....
  size_t BytesLeft = IO.maxFieldLength();
  if (HasUniqueName) {
    .....
    if (BytesNeeded > BytesLeft) {
      size_t BytesToDrop = (BytesNeeded - BytesLeft);
      size_t DropN = std::min(N.size(), BytesToDrop / 2);
      size_t DropU = std::min(U.size(), BytesToDrop - DropN);
      ....
    }
  } else {
    size_t BytesNeeded = Name.size() + 1;
    StringRef N = Name;
    if (BytesNeeded > BytesLeft) {
      size_t BytesToDrop = std::min(N.size(), BytesToDrop); // <=
      N = N.drop_back(BytesToDrop);
    }
    error(IO.mapStringZ(N));
  }
  ....
}

Pull Request: https://bugs.llvm.org/show_bug.cgi?id=32249

3. Clang. CWE-570 Expression is Always False

V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 416, 418. iteratorpastendchecker.cpp 416

bool IteratorPastEndChecker::evalCall(const CallExpr *CE,
                                      CheckerContext &C) const {
  ....
  if (FD->getIdentifier() == II_find) {
    return evalFind(C, CE);
  } else if (FD->getIdentifier() == II_find_end) {
    return evalFindEnd(C, CE);
  } else if (FD->getIdentifier() == II_find_first_of) {
    return evalFindFirstOf(C, CE);
  } else if (FD->getIdentifier() == II_find_if) {         // <=
    return evalFindIf(C, CE);
  } else if (FD->getIdentifier() == II_find_if) {         // <=
    return evalFindIf(C, CE);
  } else if (FD->getIdentifier() == II_find_if_not) {
    return evalFindIfNot(C, CE);
  } else if (FD->getIdentifier() == II_upper_bound) {
    return evalUpperBound(C, CE);
  } else if (FD->getIdentifier() == II_lower_bound) {
    return evalLowerBound(C, CE);
  } else if (FD->getIdentifier() == II_search) {
    return evalSearch(C, CE);
  } else if (FD->getIdentifier() == II_search_n) {
    return evalSearchN(C, CE);
  }
  ....
}

Pull Request: https://bugs.llvm.org/show_bug.cgi?id=32250

4. GCC. CWE-476 (NULL Pointer Dereference)

V595 The 'm->component' pointer was utilized before it was verified against nullptr. Check lines: 399, 407. genmodes.c 399

static void complete_mode (struct mode_data *m)
{
  ....
  if (   m->cl == MODE_COMPLEX_INT 
      || m->cl == MODE_COMPLEX_FLOAT)
    alignment = m->component->bytesize;        // <=
  else
    alignment = m->bytesize;

  m->alignment = alignment & (~alignment + 1);

  if (m->component)                            // <=
  {
    m->next_cont = m->component->contained;
    m->component->contained = m;
  }
}

Pull Request: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80049

5. GCC. CWE-570 (Expression is Always False)

V625 Consider inspecting the 'for' operator. Initial and final values of the iterator are the same. sese.c 201

void free_sese_info (sese_info_p region)
{
  region->params.release ();
  region->loop_nest.release ();

  for (rename_map_t::iterator it = region->rename_map->begin();
       it != region->rename_map->begin (); ++it) // <=
    (*it).second.release();
  ....
}

Pull Request: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80048

6. GCC. CWE-571 (Expression is Always True)

V501 There are identical sub-expressions '!strcmp(a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)' to the left and to the right of the '&&' operator. dwarf2out.c 1434

static bool dw_val_equal_p (dw_val_node *a, dw_val_node *b)
{
  ....
  switch (a->val_class)
  {
    ....
  case dw_val_class_vms_delta:
    return (   !strcmp (a->v.val_vms_delta.lbl1,
                        b->v.val_vms_delta.lbl1)
            && !strcmp (a->v.val_vms_delta.lbl1, 
                        b->v.val_vms_delta.lbl1));
    ....
  }
  ....
}

Pull Request: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80051

7. GCC. CWE-483 (Incorrect Block Delimitation)

V640 The code's operational logic does not correspond with its formatting. The second statement will always be executed. It is possible that curly brackets are missing. asan.c 2582

void initialize_sanitizer_builtins (void)
{
  ....
  #define DEF_SANITIZER_BUILTIN(ENUM, NAME, TYPE, ATTRS)   decl = add_builtin_function ("__builtin_" NAME, TYPE, ENUM,              BUILT_IN_NORMAL, NAME, NULL_TREE);    set_call_expr_flags (decl, ATTRS);            set_builtin_decl (ENUM, decl, true);

  #include "sanitizer.def"

  if ((flag_sanitize & SANITIZE_OBJECT_SIZE)
      && !builtin_decl_implicit_p (BUILT_IN_OBJECT_SIZE))
    DEF_SANITIZER_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size",
         BT_FN_SIZE_CONST_PTR_INT,
         ATTR_PURE_NOTHROW_LEAF_LIST)
  ....
}

Pull Request: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80063

8. FreeBSD. CWE-467: (Use of sizeof() on a Pointer Type)

V512 A call of the 'memset' function will lead to underflow of the buffer 'plog'. nat64lsn.c 218

struct pfloghdr {
  u_int8_t  length;
  sa_family_t  af;
  u_int8_t  action;
  u_int8_t  reason;
  char    ifname[IFNAMSIZ];
  char    ruleset[PFLOG_RULESET_NAME_SIZE];
  u_int32_t  rulenr;
  u_int32_t  subrulenr;
  uid_t    uid;
  pid_t    pid;
  uid_t    rule_uid;
  pid_t    rule_pid;
  u_int8_t  dir;
  u_int8_t  pad[3];
};

static void
nat64lsn_log(struct pfloghdr *plog, ....)
{
  memset(plog, 0, sizeof(plog));        // <=
  plog->length = PFLOG_REAL_HDRLEN;
  plog->af = family;
  plog->action = PF_NAT;
  plog->dir = PF_IN;
  plog->rulenr = htonl(n);
  plog->subrulenr = htonl(sn);
  plog->ruleset[0] = '\0';
  strlcpy(plog->ifname, "NAT64LSN", sizeof(plog->ifname));
  ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217738

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

V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 102, 109. dtrace_debug.c 102

static void
dtrace_debug_output(void)
{
  ....
  if (d->first < d->next) {
    char *p1 = dtrace_debug_bufr;
    count = (uintptr_t) d->next - (uintptr_t) d->first;
    for (p = d->first; p < d->next; p++)
      *p1++ = *p;
  } else if (d->next > d->first) {
    char *p1 = dtrace_debug_bufr;
    count = (uintptr_t) d->last - (uintptr_t) d->first;
    for (p = d->first; p < d->last; p++)
      *p1++ = *p;
    count += (uintptr_t) d->next - (uintptr_t) d->bufr;
    for (p = d->bufr; p < d->next; p++)
      *p1++ = *p;
  }
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217739

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

V547 Expression 'cfgflags >= 0 || cfgflags <= 3' is always true. hwpmc_piv.c 812

V547 Expression 'cfgflags >= 0 || cfgflags <= 3' is always true. hwpmc_piv.c 838

static int
p4_config_pmc(int cpu, int ri, struct pmc *pm)
{
  ....
  int cfgflags, cpuflag;
  ....
  KASSERT(cfgflags >= 0 || cfgflags <= 3,
      ("[p4,%d] illegal cfgflags cfg=%d on cpu=%d ri=%d",
    __LINE__, cfgflags, cpu, ri));
  ....
  KASSERT(cfgflags >= 0 || cfgflags <= 3,
      ("[p4,%d] illegal runcount cfg=%d on cpu=%d ri=%d",
    __LINE__, cfgflags, cpu, ri));
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217741

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

V547 Expression is always false. scif_sas_controller.c 531

....
U16  max_ncq_depth;
....
SCI_STATUS scif_user_parameters_set(
   SCI_CONTROLLER_HANDLE_T   controller,
   SCIF_USER_PARAMETERS_T  * scif_parms
)
{
  ....
   if (scif_parms->sas.max_ncq_depth < 1 &&
       scif_parms->sas.max_ncq_depth > 32)
     return SCI_FAILURE_INVALID_PARAMETER_VALUE;
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217742

12. FreeBSD. CWE-571: (Expression is Always True)

V547 Expression 'cdb[0] != 0x28 || cdb[0] != 0x2A' is always true. Probably the '&&' operator should be used here. mfi_tbolt.c 1110

int
mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
{
  ....
  uint8_t *cdb;
  ....
  /* check for inquiry commands coming from CLI */
  if (cdb[0] != 0x28 || cdb[0] != 0x2A) {
    if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) {
      device_printf(sc->mfi_dev, "Mapping from MFI "
                                 "to MPT Failed \n");
      return 1;
    }
  }
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217743

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

V560 A part of conditional expression is always true: 0x2002. sampirsp.c 7224

#define OSSA_MPI_ENC_ERR_ILLEGAL_DEK_PARAM            0x2001
#define OSSA_MPI_ERR_DEK_MANAGEMENT_DEK_UNWRAP_FAIL   0x2002

GLOBAL bit32 mpiDekManagementRsp(
  agsaRoot_t               *agRoot,
  agsaDekManagementRsp_t   *pIomb
  )
{
  ....
  if (status == OSSA_MPI_ENC_ERR_ILLEGAL_DEK_PARAM ||
      OSSA_MPI_ERR_DEK_MANAGEMENT_DEK_UNWRAP_FAIL)
  {
    agEvent.eq = errorQualifier;
  }
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217745

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

V560 A part of conditional expression is always true: 0x7dac. t4_main.c 8001

#define A_TP_KEEP_INTVL 0x7dac

static int
sysctl_tp_timer(SYSCTL_HANDLER_ARGS)
{
  struct adapter *sc = arg1;
  int reg = arg2;
  u_int tre;
  u_long tp_tick_us, v;
  u_int cclk_ps = 1000000000 / sc->params.vpd.cclk;

  MPASS(reg == A_TP_RXT_MIN || reg == A_TP_RXT_MAX ||
      reg == A_TP_PERS_MIN || reg == A_TP_PERS_MAX ||
      reg == A_TP_KEEP_IDLE || A_TP_KEEP_INTVL ||
      reg == A_TP_INIT_SRTT || reg == A_TP_FINWAIT2_TIMER);
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217746

15. FreeBSD. CWE-476 (NULL Pointer Dereference)

V595 The 'mc' pointer was utilized before it was verified against nullptr. Check lines: 2954, 2955. mly.c 2954

static int
mly_user_command(struct mly_softc *sc, struct mly_user_command *uc)
{
  struct mly_command  *mc;
  ....
  if (mc->mc_data != NULL)           // <=
    free(mc->mc_data, M_DEVBUF);     // <=
  if (mc != NULL) {                  // <=
    MLY_LOCK(sc);
    mly_release_command(mc);
    MLY_UNLOCK(sc);
  }
  return(error);
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217747

16. FreeBSD. CWE-563 (Assignment to Variable without Use ('Unused Variable'))

V519 The 'vf->flags' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 5992, 5994. if_ix.c 5994

static int
ixgbe_add_vf(device_t dev, u16 vfnum, const nvlist_t *config)
{
  ....
  if (nvlist_exists_binary(config, "mac-addr")) {
    mac = nvlist_get_binary(config, "mac-addr", NULL);
    bcopy(mac, vf->ether_addr, ETHER_ADDR_LEN);
    if (nvlist_get_bool(config, "allow-set-mac"))
      vf->flags |= IXGBE_VF_CAP_MAC;
  } else
    /*
     * If the administrator has not specified a MAC address then
     * we must allow the VF to choose one.
     */
    vf->flags |= IXGBE_VF_CAP_MAC;

  vf->flags = IXGBE_VF_ACTIVE;
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217748

17. FreeBSD. CWE-563 (Assignment to Variable without Use ('Unused Variable'))

V519 The 'pmuctrl' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 2025, 2026. bhnd_pmu_subr.c 2026

static void
bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
{
  uint32_t pmuctrl;
  ....
  /* Write XtalFreq. Set the divisor also. */
  pmuctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
  pmuctrl = ~(BHND_PMU_CTRL_ILP_DIV_MASK |
              BHND_PMU_CTRL_XTALFREQ_MASK);
  pmuctrl |= BHND_PMU_SET_BITS(((xt->fref + 127) / 128) - 1,
             BHND_PMU_CTRL_ILP_DIV);
  pmuctrl |= BHND_PMU_SET_BITS(xt->xf, BHND_PMU_CTRL_XTALFREQ);
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217782

18. FreeBSD. CWE-561 (Dead Code)

V779 Unreachable code detected. It is possible that an error is present. if_wi_pci.c 258

static int
wi_pci_resume(device_t dev)
{
  struct wi_softc  *sc = device_get_softc(dev);
  struct ieee80211com *ic = &sc->sc_ic;

  WI_LOCK(sc);
  if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) {
    return (0);                                 // <=
    WI_UNLOCK(sc);                              // <=
  }
  if (ic->ic_nrunning > 0)
    wi_init(sc);
  WI_UNLOCK(sc);
  return (0);
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217784

19. FreeBSD. CWE-561 (Dead Code)

V779 Unreachable code detected. It is possible that an error is present. mpr.c 1329

void panic(const char *a) __dead2;

static int
mpr_alloc_requests(struct mpr_softc *sc)
{
  ....
  else {
    panic("failed to allocate command %d\n", i);
    sc->num_reqs = i;
    break;
  }
  ....
}

Pull Request: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217785

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


1. GCC

V590 Consider inspecting this expression. The expression is excessive or contains a misprint. genmatch.c 3829
const cpp_token * parser::next ()
{
  const cpp_token *token;
  do
  {
    token = cpp_get_token (r);
  }
  while (   token->type == CPP_PADDING
         && token->type != CPP_EOF);    // <=
  return token;
}

Pull Request: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80050

2. Clang

V501 There are identical sub-expressions 'RA.getSubReg() != 0' to the left and to the right of the '||' operator. hexagonearlyifconv.cpp 485

unsigned HexagonEarlyIfConversion::computePhiCost(....) const {
  ....
  const MachineOperand &RA = MI.getOperand(1);
  const MachineOperand &RB = MI.getOperand(3);
  assert(RA.isReg() && RB.isReg());
  // Must have a MUX if the phi uses a subregister.
  if (RA.getSubReg() != 0 || RA.getSubReg() != 0) {
    Cost++;
    continue;
  }
  ....
}

Pull Request: https://bugs.llvm.org/show_bug.cgi?id=32265

Заключение


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


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

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



Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. Weaknesses detected by PVS-Studio this week: episode N2

Прочитали статью и есть вопрос?
Часто к нашим статьям задают одни и те же вопросы. Ответы на них мы собрали здесь: Ответы на вопросы читателей статей про PVS-Studio, версия 2015. Пожалуйста, ознакомьтесь со списком.
Поделиться с друзьями
-->

Комментарии (25)


  1. datacompboy
    17.03.2017 16:13
    +4

    Блин, ну это, уведомили авторов?
    Тьфу, А что так МАЛО?

    А проверяли версией под линукс или виндовой?

    Вообще, у вас кто-нибудь внутри линуксовую использует, или она только для галочки?


    1. EvgeniyRyzhkov
      17.03.2017 16:18
      +5

      Вообще, у вас кто-нибудь внутри линуксовую использует, или она только для галочки?


      И внутри, и снаружи.

      Будем рады, если присоединитесь к числу пользователей.


    1. lany
      18.03.2017 08:04
      +5

      Очень немало, учитывая, что на каждую багу прилагается pull-request с вменяемым исправлением. Много вы пулл-реквестов в оперсорс засабмитили на прошлой неделе? :-)


      1. datacompboy
        18.03.2017 22:57
        -2

        мне почти не платят за опенсорс в последнее время :(


  1. SvyatoslavMC
    17.03.2017 16:38
    +4

    А проверяли версией под линукс или виндовой?

    Даже под FreeBSD.

    Сейчас мы можем проверять любые проекты, поэтому просто выбираем удобную платформу для сборки для каждого конкретного проекта.


    1. DjPhoeniX
      17.03.2017 17:29

      Под MacOS сборку не готовите?


      1. SvyatoslavMC
        17.03.2017 19:15

        Пока нет.


  1. CodeRush
    17.03.2017 17:35

    СиПроВер, пожалуйста, не путайте CWE и CVE, хоть оба списка и ведет одна и таже MITRE, но именно к настоящим проблемам безопасности первый список имеет весьма опосредованное отношение.
    Для того, чтобы ошибка в программе стала настоящей проблемой безопасности, она должна быть эксплуатируема, т.е. для нее должно быть найден способ использования в целях, которые ставит перед собой атакующий. И пока такой способ не найден, все эти вышеописанные вещи так и остаются «слабостями», а не проблемами безопасности. Широко известный в узких кругах журнал PoC||GTFO не зря называется именно так. ;)
    Если вы действительно хотите помочь пометить серьезные проблемы, связанные с безопасностью, начните предупреждать громче, чем обычно (т.е. с приоритетом 0 вместо 1 и красным цветом) хотя бы о следующих вещах:

    • use-after-free, в прямых руках это практически гарантированный WWW с последующии грабежом, убийством и надругательством над гусями
    • проблемах с потоком управления (goto fail)
    • чтении неинициализированных переменных и областей памяти (Heartbleed/Cloudbleed) и записи за границы массивов (слишком длинный список примеров, чтобы его тут приводить)


    1. CodeRush
      17.03.2017 17:41
      +3

      В общем, я про то, что лучше добавлять слово «потенциальные» ко всем вашим «дефектам безопасности», пока к каждому из них не написан PoC-эксплоит.


      1. Andrey2008
        17.03.2017 17:57
        +5

        Мне кажется, Вы путаетесь. То, что мы ищем, и есть дефект безопасности (CWE). Ошибка в коде (дефект) может стать причиной уязвимости. Поэтому есть смысл писать «потенциальная уязвимость», что мы и делаем.

        Но нет смысла писать «потенциальны дефект» (какой-же он потенциальный, когда вот она ошибка!).


        1. CodeRush
          17.03.2017 18:37
          +7

          Вы пишете слово «vulnerability» на своих КДПВ, хотя речь идет о «weakness». Первое — это то, что на русский язык переводится словом «уязвимость», она же немного слабее «security issue», т.е. «проблема безопасности». Второе — это то, что вы переводите как «дефект», а я — как «слабость» или «недостаток». Словосочетание «дефект безопасности», в которое превратилось «weakness» — оно очень странное, и я действительно путаюсь в нем. «Дефект», мне кажется — намного более сильное слово, чем «слабость» или «недостаток», но я могу ошибаться. «Потенциальная проблема безопасности» — вот что такое «weakness», на мой взгляд.


          1. Andrey2008
            18.03.2017 23:30
            +3

            Но останавливаем то мы именно уязвимости. :) Метод — найти и предотвратить их заранее.


            1. CodeRush
              19.03.2017 02:03
              +5

              Нельзя называть уязвимостью то, что не участвует в атаке. Критерий — наличие PoC, если а PoC нет, это слабое место, недостаток (а не «дефект безопасности», чтобы не значил этот странный термин), что угодно, только не уязвимость.
              Я понимаю, что вы хотите сказать, и даже понимаю, зачем именно, но называть любую обнаруженную «weakness» словом «vulnerability» — это буллшит чистой воды, потому что это максимум «potential security issue».
              Мужики, у вас отличный продукт без дураков, и хорошая рекламная стратегия (была, по крайней мере) со всеми этими статьями, но не скатывайтесь, прошу вас, в рекламу змеинного масла.
              PVS-Studio находит не «уязвимости», а «слабые места в коде, которые могут привести (или не привести) к уязвимости». По настоящему с уязвимостями борятся технологии предотвращения эксплуатации вроде VBS, CFG, RAP, и т.п. Вот слайды с недавнего доклада специалистов из Microsoft о них.


      1. ATwn
        19.03.2017 10:05
        +2

        Даже если речь идет о «потенциальных» дефектах безопасности, обнаружение таковых при помощи статического анализа в автоматическом режиме на ранних стадиях все же лучше чем ждать пока кто-нибудь напишет PoC-эксплойт, а потом применит этот PoC на практике. ИМХО.


        1. CodeRush
          19.03.2017 10:55

          С этим я не спорю, это правильное применение статического анализатора и я тоже применяю его для тех же целей. Спорю я с использованием в рекламных материалах слова «vulnerability», которое слишком сильное в данном случае. Плюс еще с тем, что «дефект безопасности» — это хороший термин для CWE. Дефект, на самом деле, не безопасности, а ПО, и ищет анализатор дефекты/недостатки/изъяны/слабости именно в коде, а не в «безопасности».
          Я на одной стороне с разработчиками, но считаю, что продавать статический анализатор с лозунгом «stop vulnerabilities», и использовать это очень сильное слово в статьях и пулл-реквестах — хороший способ создать о себе негативное впечатление продавцов воздуха.


          1. Andrey2008
            19.03.2017 16:18

            Я всё понимаю и согласен, но тут уместна фраза: «Скромность красит человека в невзрачный серенький цвет».

            Дело в том, что я вижу в разных местах борьбу с уязвимостями и считаю разумным принять участия. Странно говорить про себя скромно, что мы умеем искать жалкие «слабые места в коде, которые могут привести (или не привести) к уязвимости». В то время, как кругом «ищут уязвимости».

            В качестве примера, первое что попало под руку:

            • Этой статьей мы открываем серию публикаций, посвященных обнаружению ошибок и уязвимостей в open-source проектах с помощью статического анализатора кода AppChecker. [1]
            • Настоящей статьей мы продолжаем серию обзоров, посвященных обнаружению уязвимостей в open-source проектах с помощью статического анализатора кода AppChecker. [2]


            1. CodeRush
              19.03.2017 19:57

              Дело ваше, но эта «война буллшитов» всегда заканчивается одинаково — на рынке не остается нормальных продуктов, т.к. все вообще начинают декларировать 100% защиту от всего, интеграцию со всем, встроенную кофе-машину и кнопку «сделай мне зашибись!». Как с антивирусами сейчас.

              Если вы будете писать «мы устранили уязвимости в открытом ПО», не удивляйтесь, что от вас отвернутся и те, кто действительно ищет и устраняет уязвимости, и те, кто разрабатывает открытое ПО. Буллшит рекламный не любит никто, и даже если конкуренты уже вовсю обмазываются им — присоединяться, на мой взгляд, не стоит.


    1. Andrey2008
      17.03.2017 17:54
      +3

      Гм… Казалось бы, мы и не путаем CWE и CVE и как раз я вчера про это рассуждал в статье "PVS-Studio: поиск дефектов безопасности". И я везде и пишу о потенциальных уязвимостях (они-же дефекты безопасности, т.е. CWE).

      Что касается перечисленных вами проблем, то мы их ищем, что не раз демонстрировалось в различных статьях.


      1. CodeRush
        17.03.2017 18:39

        Я не о том, что вы их не ищите, а о том, чтобы маркировать их сильнее в списке ошибок, потому что их потенциальный вред сильнее. Хотя бы не по умолчанию, а в качестве настройки.


  1. maaGames
    18.03.2017 07:14

    А вот можно как-то уточнить определение ошибки V730 (поле класса не инициализировано в конструкторе), чтобы оно не выдавалось для типов, у которых есть конструктор по умолчанию и прописывать его в списке инициализации конструктора не обязательно, т.к. всё равно конструктор вызовется. Просто выдаётся масса этих предупреждений, среди которых могут затеряться те, в которых реально следовало делать инициализацию.


    1. Andrey2008
      18.03.2017 11:21
      +2

      Если честно, не понятна о какой ситуации идёт речь. Есть подозрение, что с кодом всё-таки что-то не так. Прошу привести конкретный синтетический пример, на котором выдаётся ложное срабатывание, и мы обсудим его.


      1. maaGames
        18.03.2017 13:00
        +1

        V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: _fileTree, _actorTree

        _fileTree и _actorTree это класс, содержащий std::list и объект класса, в котором std::vector. Ни у кого из них вообще конструктор не реализован, используется по умолчанию. Так же там есть булевый флаг, вида: bool _flag = false; Т.е. инициализация по месту объявления, а не в конструкторе. Возможно, что из-за этого объект подозревается в неинициализированности.
        Не сразу заметил, что V730 обозначает и точно недоинициализированный объект и тот, который только подозревается в недоинициализированности.


        1. Andrey2008
          18.03.2017 14:56
          +2

          Если честно, не понятна о какой ситуации идёт речь. Есть подозрение, что с кодом всё-таки что-то не так. Прошу привести конкретный синтетический пример, на котором выдаётся ложное срабатывание, и мы обсудим его.


          1. maaGames
            19.03.2017 06:47
            +4

            Полюбил PVS-Studio ещё больше, хотя не думал, что такое возможно!
            Ещё раз прошерстил интерфейс класса и нашёл отладочно-костыльный флаг, аналогичный тому, про который говорил выше, но не инициализированный. Так что PVS абсолютно правильно подозревал.
            Только жаль, что в предупреждении выводились имена объектов, в которых была не инициализированная переменная, а не имя переменной в классе этих объектов, как это происходит с этим же предупреждением, но когда строгая уверенность в недоинициализированности.


            1. Andrey2008
              19.03.2017 10:04
              +2

              Вот и славно. :)