All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH v3 6/9] index-helper: add --strict
Date: Mon, 28 Jul 2014 19:03:12 +0700	[thread overview]
Message-ID: <1406548995-28549-7-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1406548995-28549-1-git-send-email-pclouds@gmail.com>

There's are "holes" in the index-helper approach because the shared
memory is not verified again by git. If $USER is compromised, shared
memory could be modified. But then they can already modify
$GIT_DIR/index. A more realistic risk is some bugs in index-helper
produce corrupt shared memory. --strict is added to avoid that

Strictly speaking there's still a very small gap where corrupt shared
memory could still be read by git: after we write the trailing SHA-1 in
the shared memory (thus signaling "this shm is ready") and before
verify_shm() detects an error.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-index-helper.txt |  9 ++++++++
 cache.h                            |  1 +
 index-helper.c                     | 47 ++++++++++++++++++++++++++++++++++++++
 read-cache.c                       |  9 +++++---
 4 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-index-helper.txt b/Documentation/git-index-helper.txt
index da41c4d..406856d 100644
--- a/Documentation/git-index-helper.txt
+++ b/Documentation/git-index-helper.txt
@@ -22,6 +22,15 @@ OPTIONS
 	Exit if the cached index is not accessed for `<n>`
 	minutes. Specify 0 to wait forever. Default is 10.
 
+--strict::
+--no-strict::
+	Strict mode makes index-helper verify the shared memory after
+	it's created. If the result does not match what's read from
+	$GIT_DIR/index, the shared memory is destroyed. This makes
+	index-helper take more than double the amount of time required
+	for reading an index, but because it will happen in the
+	background, it's not noticable. `--strict` is enabled by default.
+
 NOTES
 -----
 On UNIX-like systems, $GIT_DIR/index-helper.pid contains the process
diff --git a/cache.h b/cache.h
index 4266771..0f515e5 100644
--- a/cache.h
+++ b/cache.h
@@ -307,6 +307,7 @@ struct index_state {
 	struct cache_time timestamp;
 	unsigned name_hash_initialized : 1,
 		 keep_mmap : 1,
+		 always_verify_trailing_sha1 : 1,
 		 initialized : 1;
 	struct hashmap name_hash;
 	struct hashmap dir_hash;
diff --git a/index-helper.c b/index-helper.c
index 8fa0af9..c82d307 100644
--- a/index-helper.c
+++ b/index-helper.c
@@ -13,6 +13,7 @@ struct index_shm {
 
 static struct index_shm shm_index;
 static struct index_shm shm_base_index;
+static int to_verify = 1;
 
 static void free_index_shm(struct index_shm *is)
 {
@@ -68,6 +69,48 @@ static void share_index(struct index_state *istate, struct index_shm *is)
 	hashcpy((unsigned char *)new_mmap + istate->mmap_size - 20, is->sha1);
 }
 
+static int verify_shm(void)
+{
+	int i;
+	struct index_state istate;
+	memset(&istate, 0, sizeof(istate));
+	istate.always_verify_trailing_sha1 = 1;
+	i = read_index(&istate);
+	if (i != the_index.cache_nr)
+		goto done;
+	for (; i < the_index.cache_nr; i++) {
+		struct cache_entry *base, *ce;
+		/* namelen is checked separately */
+		const unsigned int ondisk_flags =
+			CE_STAGEMASK | CE_VALID | CE_EXTENDED_FLAGS;
+		unsigned int ce_flags, base_flags, ret;
+		base = the_index.cache[i];
+		ce = istate.cache[i];
+		if (ce->ce_namelen != base->ce_namelen ||
+		    strcmp(ce->name, base->name)) {
+			warning("mismatch at entry %d", i);
+			break;
+		}
+		ce_flags = ce->ce_flags;
+		base_flags = base->ce_flags;
+		/* only on-disk flags matter */
+		ce->ce_flags   &= ondisk_flags;
+		base->ce_flags &= ondisk_flags;
+		ret = memcmp(&ce->ce_stat_data, &base->ce_stat_data,
+			     offsetof(struct cache_entry, name) -
+			     offsetof(struct cache_entry, ce_stat_data));
+		ce->ce_flags = ce_flags;
+		base->ce_flags = base_flags;
+		if (ret) {
+			warning("mismatch at entry %d", i);
+			break;
+		}
+	}
+done:
+	discard_index(&istate);
+	return i == the_index.cache_nr;
+}
+
 static void refresh(int sig)
 {
 	the_index.keep_mmap = 1;
@@ -76,6 +119,8 @@ static void refresh(int sig)
 	if (the_index.split_index && the_index.split_index->base)
 		share_index(the_index.split_index->base, &shm_base_index);
 	share_index(&the_index, &shm_index);
+	if (to_verify && !verify_shm())
+		cleanup_shm();
 	discard_index(&the_index);
 }
 
@@ -123,6 +168,8 @@ int main(int argc, char **argv)
 	struct option options[] = {
 		OPT_INTEGER(0, "exit-after", &idle_in_minutes,
 			    N_("exit if not used after some minutes")),
+		OPT_BOOL(0, "strict", &to_verify,
+			 "verify shared memory after creating"),
 		OPT_END()
 	};
 
diff --git a/read-cache.c b/read-cache.c
index 4bd2abe..d6eb17f 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1568,9 +1568,12 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
 
 	istate->mmap = mmap;
 	istate->mmap_size = mmap_size;
-	if (try_shm(istate) &&
-	    verify_hdr(istate->mmap, istate->mmap_size) < 0)
-		goto unmap;
+	if (try_shm(istate)) {
+		if (verify_hdr(istate->mmap, istate->mmap_size) < 0)
+			goto unmap;
+	} else if (istate->always_verify_trailing_sha1 &&
+		   verify_hdr(istate->mmap, istate->mmap_size) < 0)
+			goto unmap;
 	hdr = mmap = istate->mmap;
 	mmap_size = istate->mmap_size;
 	if (!istate->keep_mmap)
-- 
2.1.0.rc0.66.gb9187ad

  parent reply	other threads:[~2014-07-28 12:04 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-07-28 12:03 [PATCH v3 0/9] Speed up cache loading time Nguyễn Thái Ngọc Duy
2014-07-28 12:03 ` [PATCH v3 1/9] trace.c: add GIT_TRACE_PACK_STATS for pack usage statistics Nguyễn Thái Ngọc Duy
2014-07-28 12:03 ` [PATCH v3 2/9] read-cache.c: fix constness of verify_hdr() Nguyễn Thái Ngọc Duy
2014-07-28 12:03 ` [PATCH v3 3/9] read-cache: allow to keep mmap'd memory after reading Nguyễn Thái Ngọc Duy
2014-07-28 12:03 ` [PATCH v3 4/9] index-helper: new daemon for caching index and related stuff Nguyễn Thái Ngọc Duy
2014-07-30  8:08   ` Eric Sunshine
2014-07-30 10:39     ` Duy Nguyen
2014-07-31  2:41   ` David Turner
2014-07-28 12:03 ` [PATCH v3 5/9] trace.c: add GIT_TRACE_INDEX_STATS for index statistics Nguyễn Thái Ngọc Duy
2014-07-28 12:03 ` Nguyễn Thái Ngọc Duy [this message]
2014-07-28 12:03 ` [PATCH v3 7/9] daemonize(): set a flag before exiting the main process Nguyễn Thái Ngọc Duy
2014-07-28 12:03 ` [PATCH v3 8/9] index-helper: add --detach Nguyễn Thái Ngọc Duy
2014-07-28 12:03 ` [PATCH v3 9/9] index-helper: add Windows support Nguyễn Thái Ngọc Duy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1406548995-28549-7-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.