vos: Check start-of-dump magic in vos restore

When restoring with a regular file (either with -file or a shell redirect
'<'), vos restore verifies the file ends with the end-of-dump magic
number. This catches cases in which the specified file is obviously not
a dump file, for example the file is empty, truncated, or just not file
created by vos dump.

Currently, no checks are done when restoring from a pipe or fifo, since it
is not possible to check the end of the stream and reset the seek pointer
to before sending the data to the volume server.

Add a check to verify the dump begins with the dump header tag and the
start-of-dump magic number, even when the dump file is not seekable.

In the case the dump file is not seekable, send the start of dump
tag and the start-of-dump magic number directly in SendFile(), since
those values were already read in CheckDumpFile().

This guards against starting a restore from an empty or wrong file when
restoring from a pipeline or a named pipe.

Change-Id: I7aa508bf5f0e81da7d6602856b5242cb6313e9a8
Reviewed-on: https://gerrit.openafs.org/14711
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
This commit is contained in:
Michael Meffie 2022-07-15 13:00:03 -04:00 committed by Andrew Deason
parent 22e8fa88d1
commit 65290ac18b

View File

@ -288,6 +288,9 @@ IsPartValid(afs_int32 partId, afs_uint32 server, afs_int32 *code)
* @param[in] call rx call object
* @param[in] rock usd file handle opened for read
*
* @pre The ufd is positioned after the DUMPBEGINMAGIC
* in the dump stream.
*
* @returns status
* @retval 0 success
* @retval -1 error
@ -300,6 +303,8 @@ SendFile(struct rx_call *call, void *rock)
afs_int32 error;
afs_uint32 nbytes;
long blksize = 0;
char tag = D_DUMPHEADER;
afs_uint32 magic = htonl(DUMPBEGINMAGIC);
error = USD_IOCTL(ufd, USD_IOCTL_GETBLKSIZE, &blksize);
if (error != 0) {
@ -307,12 +312,23 @@ SendFile(struct rx_call *call, void *rock)
return -1;
}
/* Send the header fields already read in CheckDumpFile(). */
nbytes = rx_Write(call, &tag, sizeof(tag));
if (nbytes != sizeof(tag)) {
return -1;
}
nbytes = rx_Write(call, (char *)&magic, sizeof(magic));
if (nbytes != sizeof(magic)) {
return -1;
}
buffer = malloc(blksize);
if (!buffer) {
fprintf(STDERR, "malloc failed\n");
return -1;
}
/* Send the rest of the dump. */
while (!error) {
#if !defined(AFS_NT40_ENV) && !defined(AFS_PTHREAD_ENV)
/* Only for this for non-NT, non-pthread. For NT, we can't select on
@ -349,12 +365,18 @@ SendFile(struct rx_call *call, void *rock)
*
* @param[in] ufd dump file handle
* @retval 0 file appears to contain a volume dump
*
* @post For a valid volume dump, ufd is positioned after the
* DUMPBEGINMAGIC in the dump stream.
*/
static int
CheckDumpFile(usd_handle_t ufd)
{
afs_int32 code;
int is_seekable = 0;
char tag = '\0';
afs_uint32 got = 0;
afs_uint32 magic = 0;
/* Test if we have a valid dump. */
code = USD_IOCTL(ufd, USD_IOCTL_ISSEEKABLE, &is_seekable);
@ -365,8 +387,6 @@ CheckDumpFile(usd_handle_t ufd)
}
if (is_seekable) {
afs_int64 offset = 0;
afs_uint32 magic = 0;
afs_uint32 got = 0;
code = USD_SEEK(ufd, 0, SEEK_END, &offset);
if (code != 0) {
@ -398,6 +418,20 @@ CheckDumpFile(usd_handle_t ufd)
return code;
}
}
code = USD_READ(ufd, &tag, sizeof(tag), &got);
if (code != 0 || got != sizeof(tag) || tag != D_DUMPHEADER) {
fprintf(STDERR, "Start tag not found in '%s'.\n",
ufd->fullPathName);
return VOLSERBADOP;
}
code = USD_READ(ufd, (char *)&magic, sizeof(magic), &got);
if (code != 0 || got != sizeof(magic) || ntohl(magic) != DUMPBEGINMAGIC) {
fprintf(STDERR, "Begin dump signature not found in '%s'.\n",
ufd->fullPathName);
return VOLSERBADOP;
}
return 0;
}