Merge branch 'bp/fsmonitor-bufsize-fix'
authorJunio C Hamano <gitster@pobox.com>
Wed, 25 Apr 2018 04:29:03 +0000 (13:29 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 25 Apr 2018 04:29:03 +0000 (13:29 +0900)
Fix an unexploitable (because the oversized contents are not under
attacker's control) buffer overflow.

* bp/fsmonitor-bufsize-fix:
fsmonitor: fix incorrect buffer size when printing version number

1  2 
fsmonitor.c
diff --combined fsmonitor.c
index 6d7bcd5d0ed8f2d3f5abdea2f26c6be72909b657,512615eef5a3a623eda43ba4337c651ba4913b97..eb4e6422562c89686f1bc9666b031a7ce7083a6e
@@@ -26,6 -26,7 +26,6 @@@ int read_fsmonitor_extension(struct ind
        uint32_t hdr_version;
        uint32_t ewah_size;
        struct ewah_bitmap *fsmonitor_dirty;
 -      int i;
        int ret;
  
        if (sz < sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint32_t))
                ewah_free(fsmonitor_dirty);
                return error("failed to parse ewah bitmap reading fsmonitor index extension");
        }
 -
 -      if (git_config_get_fsmonitor()) {
 -              /* Mark all entries valid */
 -              for (i = 0; i < istate->cache_nr; i++)
 -                      istate->cache[i]->ce_flags |= CE_FSMONITOR_VALID;
 -
 -              /* Mark all previously saved entries as dirty */
 -              ewah_each_bit(fsmonitor_dirty, fsmonitor_ewah_callback, istate);
 -
 -              /* Now mark the untracked cache for fsmonitor usage */
 -              if (istate->untracked)
 -                      istate->untracked->use_fsmonitor = 1;
 -      }
 -      ewah_free(fsmonitor_dirty);
 +      istate->fsmonitor_dirty = fsmonitor_dirty;
  
        trace_printf_key(&trace_fsmonitor, "read fsmonitor extension successful");
        return 0;
  }
  
 +void fill_fsmonitor_bitmap(struct index_state *istate)
 +{
 +      int i;
 +      istate->fsmonitor_dirty = ewah_new();
 +      for (i = 0; i < istate->cache_nr; i++)
 +              if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID))
 +                      ewah_set(istate->fsmonitor_dirty, i);
 +}
 +
  void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate)
  {
        uint32_t hdr_version;
        uint64_t tm;
 -      struct ewah_bitmap *bitmap;
 -      int i;
        uint32_t ewah_start;
        uint32_t ewah_size = 0;
        int fixup = 0;
        strbuf_add(sb, &ewah_size, sizeof(uint32_t)); /* we'll fix this up later */
  
        ewah_start = sb->len;
 -      bitmap = ewah_new();
 -      for (i = 0; i < istate->cache_nr; i++)
 -              if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID))
 -                      ewah_set(bitmap, i);
 -      ewah_serialize_strbuf(bitmap, sb);
 -      ewah_free(bitmap);
 +      ewah_serialize_strbuf(istate->fsmonitor_dirty, sb);
 +      ewah_free(istate->fsmonitor_dirty);
 +      istate->fsmonitor_dirty = NULL;
  
        /* fix up size field */
        put_be32(&ewah_size, sb->len - ewah_start);
@@@ -104,14 -114,13 +104,14 @@@ static int query_fsmonitor(int version
        if (!(argv[0] = core_fsmonitor))
                return -1;
  
-       snprintf(ver, sizeof(version), "%d", version);
+       snprintf(ver, sizeof(ver), "%d", version);
        snprintf(date, sizeof(date), "%" PRIuMAX, (uintmax_t)last_update);
        argv[1] = ver;
        argv[2] = date;
        argv[3] = NULL;
        cp.argv = argv;
        cp.use_shell = 1;
 +      cp.dir = get_git_work_tree();
  
        return capture_command(&cp, query_result, 1024);
  }
@@@ -130,7 -139,7 +130,7 @@@ static void fsmonitor_refresh_callback(
         * as it could be a new untracked file.
         */
        trace_printf_key(&trace_fsmonitor, "fsmonitor_refresh_callback '%s'", name);
 -      untracked_cache_invalidate_path(istate, name);
 +      untracked_cache_invalidate_path(istate, name, 0);
  }
  
  void refresh_fsmonitor(struct index_state *istate)
@@@ -229,29 -238,7 +229,29 @@@ void remove_fsmonitor(struct index_stat
  
  void tweak_fsmonitor(struct index_state *istate)
  {
 -      switch (git_config_get_fsmonitor()) {
 +      int i;
 +      int fsmonitor_enabled = git_config_get_fsmonitor();
 +
 +      if (istate->fsmonitor_dirty) {
 +              if (fsmonitor_enabled) {
 +                      /* Mark all entries valid */
 +                      for (i = 0; i < istate->cache_nr; i++) {
 +                              istate->cache[i]->ce_flags |= CE_FSMONITOR_VALID;
 +                      }
 +
 +                      /* Mark all previously saved entries as dirty */
 +                      ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate);
 +
 +                      /* Now mark the untracked cache for fsmonitor usage */
 +                      if (istate->untracked)
 +                              istate->untracked->use_fsmonitor = 1;
 +              }
 +
 +              ewah_free(istate->fsmonitor_dirty);
 +              istate->fsmonitor_dirty = NULL;
 +      }
 +
 +      switch (fsmonitor_enabled) {
        case -1: /* keep: do nothing */
                break;
        case 0: /* false */