If swap.state gets corrupted, a single entry with bogus size value will screw
up Squid idea of the current cache size. A newly added StoreSwapLogData sane()
method attempts to minimize the chance of corruption by ignoring log entries
with obviously bogus values.
However, without expensive size checks (-S or "Does the log entry matches the
actual cache file size?"), it is not possible to reliably detect all bogus log
entries.
If Squid gets a wrong idea of the current cache size, it may either cache too
much (and possibly run out of space) OR delete everything.
memset (key, '\0', sizeof(key));
}
+bool
+StoreSwapLogData::sane() const
+{
+ // TODO: These checks are rather weak. A corrupted swap.state may still
+ // cause havoc (e.g., cur_size may become astronomical). Add checksums?
+
+ // Check what we safely can; for some fields any value might be valid
+ return SWAP_LOG_NOP < op && op < SWAP_LOG_MAX &&
+ swap_filen >= 0 &&
+ timestamp >= -1 && // in case some code is using -1 to mean "n/a"
+ lastref >= -1 &&
+ expires >= -1 &&
+ lastmod >= -1 &&
+ swap_file_sz > 0; // because swap headers ought to consume space
+}
+
StoreSwapLogHeader::StoreSwapLogHeader():op(SWAP_LOG_VERSION), version(1)
{
record_size = sizeof(StoreSwapLogData);
MEMPROXY_CLASS(StoreSwapLogData);
StoreSwapLogData();
+ /// consistency self-check: whether the data appears to make sense
+ bool sane() const;
+
/**
* Either SWAP_LOG_ADD when an object is added to the disk storage,
* or SWAP_LOG_DEL when an object is deleted.
while (fread(&s, sizeof(s), 1, file) == 1) {
count++;
idx->scanned_count++;
- /* if (s.op <= SWAP_LOG_NOP || s.op >= SWAP_LOG_MAX)
+ /* if (!s.sane())
* continue; */
if (s.op == SWAP_LOG_ADD) {
n_read++;
- if (swapData.op <= SWAP_LOG_NOP)
- return;
-
- if (swapData.op >= SWAP_LOG_MAX)
+ if (!swapData.sane()) {
+ counts.invalid++;
return;
+ }
/*
* BC: during 2.4 development, we changed the way swap file