@matheusbsbs / matheus-bagliano / commits / abeb40e5aa
Fork 0

improve reliability of fixup_pack_header_footer()

Currently, this function has the potential to read corrupted pack data from disk and give it a valid SHA1 checksum. Let's add the ability to validate SHA1 checksum of existing data along the way, including before and after any arbitrary point in the pack. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nicolas Pitre committed Aug 29, 2008 at 16:07 UTC abeb40e5aa5b4a39799ae1caad241c8c7708053a
5 files changed +66 -16
builtin-pack-objects.c
+2 -1
@@ -493,7 +493,8 @@ static void write_pack_file(void)
493 sha1close(f, sha1, CSUM_FSYNC);
494 } else {
495 int fd = sha1close(f, NULL, 0);
496 - fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written);
496 + fixup_pack_header_footer(fd, sha1, pack_tmp_name,
497 + nr_written, NULL, 0);
498 close(fd);
499 }
500
fast-import.c
+2 -1
@@ -951,7 +951,8 @@ static void end_packfile(void)
951
952 close_pack_windows(pack_data);
953 fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
954 - pack_data->pack_name, object_count);
954 + pack_data->pack_name, object_count,
955 + NULL, 0);
956 close(pack_data->pack_fd);
957 idx_name = keep_pack(create_index());
958
index-pack.c
+2 -1
@@ -982,7 +982,8 @@ int main(int argc, char **argv)
982 nr_objects - nr_objects_initial);
983 stop_progress_msg(&progress, msg);
984 fixup_pack_header_footer(output_fd, sha1,
985 - curr_pack, nr_objects);
985 + curr_pack, nr_objects,
986 + NULL, 0);
987 }
988 if (nr_deltas != nr_resolved_deltas)
989 die("pack has %d unresolved deltas",
pack-write.c
+59 -12
@@ -144,41 +144,88 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects,
144 return index_name;
145 }
146
147 +/*
148 + * Update pack header with object_count and compute new SHA1 for pack data
149 + * associated to pack_fd, and write that SHA1 at the end. That new SHA1
150 + * is also returned in new_pack_sha1.
151 + *
152 + * If partial_pack_sha1 is non null, then the SHA1 of the existing pack
153 + * (without the header update) is computed and validated against the
154 + * one provided in partial_pack_sha1. The validation is performed at
155 + * partial_pack_offset bytes in the pack file. The SHA1 of the remaining
156 + * data (i.e. from partial_pack_offset to the end) is then computed and
157 + * returned in partial_pack_sha1.
158 + *
159 + * Note that new_pack_sha1 is updated last, so both new_pack_sha1 and
160 + * partial_pack_sha1 can refer to the same buffer if the caller is not
161 + * interested in the resulting SHA1 of pack data above partial_pack_offset.
162 + */
163 void fixup_pack_header_footer(int pack_fd,
148 - unsigned char *pack_file_sha1,
164 + unsigned char *new_pack_sha1,
165 const char *pack_name,
150 - uint32_t object_count)
166 + uint32_t object_count,
167 + unsigned char *partial_pack_sha1,
168 + off_t partial_pack_offset)
169 {
170 static const int buf_sz = 128 * 1024;
153 - SHA_CTX c;
171 + SHA_CTX old_sha1_ctx, new_sha1_ctx;
172 struct pack_header hdr;
173 char *buf;
174
175 + SHA1_Init(&old_sha1_ctx);
176 + SHA1_Init(&new_sha1_ctx);
177 +
178 if (lseek(pack_fd, 0, SEEK_SET) != 0)
158 - die("Failed seeking to start: %s", strerror(errno));
179 + die("Failed seeking to start of %s: %s", pack_name, strerror(errno));
180 if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
181 die("Unable to reread header of %s: %s", pack_name, strerror(errno));
182 if (lseek(pack_fd, 0, SEEK_SET) != 0)
162 - die("Failed seeking to start: %s", strerror(errno));
183 + die("Failed seeking to start of %s: %s", pack_name, strerror(errno));
184 + SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr));
185 hdr.hdr_entries = htonl(object_count);
186 + SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr));
187 write_or_die(pack_fd, &hdr, sizeof(hdr));
165 -
166 - SHA1_Init(&c);
167 - SHA1_Update(&c, &hdr, sizeof(hdr));
188 + partial_pack_offset -= sizeof(hdr);
189
190 buf = xmalloc(buf_sz);
191 for (;;) {
171 - ssize_t n = xread(pack_fd, buf, buf_sz);
192 + ssize_t m, n;
193 + m = (partial_pack_sha1 && partial_pack_offset < buf_sz) ?
194 + partial_pack_offset : buf_sz;
195 + n = xread(pack_fd, buf, m);
196 if (!n)
197 break;
198 if (n < 0)
199 die("Failed to checksum %s: %s", pack_name, strerror(errno));
176 - SHA1_Update(&c, buf, n);
200 + SHA1_Update(&new_sha1_ctx, buf, n);
201 +
202 + if (!partial_pack_sha1)
203 + continue;
204 +
205 + SHA1_Update(&old_sha1_ctx, buf, n);
206 + partial_pack_offset -= n;
207 + if (partial_pack_offset == 0) {
208 + unsigned char sha1[20];
209 + SHA1_Final(sha1, &old_sha1_ctx);
210 + if (hashcmp(sha1, partial_pack_sha1) != 0)
211 + die("Unexpected checksum for %s "
212 + "(disk corruption?)", pack_name);
213 + /*
214 + * Now let's compute the SHA1 of the remainder of the
215 + * pack, which also means making partial_pack_offset
216 + * big enough not to matter anymore.
217 + */
218 + SHA1_Init(&old_sha1_ctx);
219 + partial_pack_offset = ~partial_pack_offset;
220 + partial_pack_offset -= MSB(partial_pack_offset, 1);
221 + }
222 }
223 free(buf);
224
180 - SHA1_Final(pack_file_sha1, &c);
181 - write_or_die(pack_fd, pack_file_sha1, 20);
225 + if (partial_pack_sha1)
226 + SHA1_Final(partial_pack_sha1, &old_sha1_ctx);
227 + SHA1_Final(new_pack_sha1, &new_sha1_ctx);
228 + write_or_die(pack_fd, new_pack_sha1, 20);
229 fsync_or_die(pack_fd, pack_name);
230 }
231
pack.h
+1 -1
@@ -58,7 +58,7 @@ struct pack_idx_entry {
58 extern char *write_idx_file(char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
59 extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
60 extern int verify_pack(struct packed_git *);
61 -extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);
61 +extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
62 extern char *index_pack_lockfile(int fd);
63
64 #define PH_ERROR_EOF (-1)