vos: convertROtoRW susceptible to VLDB changes during override prompt
authorMark Vitale <mvitale@sinenomine.net>
Mon, 20 Aug 2012 21:39:06 +0000 (17:39 -0400)
committerDerrick Brashear <shadow@dementix.org>
Wed, 22 Aug 2012 19:25:06 +0000 (12:25 -0700)
vos convertROtoRW obtains a VLDB entry, then peforms some setup logic
(including a possible user prompt) before obtaining a volume lock.
This exposes the code to possible time-of-check/time-of-use issues.
After obtaining the volume lock, get a second copy of the VLDB entry
and compare it to the first copy; if it has changed, fail the conversion
with an error message asking the user to re-issue the vos convertROtoRW
command.

Change-Id: I9c1a634cea2e22188869d54b00b7831aed12b1cd
Reviewed-on: http://gerrit.openafs.org/8008
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementix.org>

src/volser/vos.c

index fc43f5d..89b5bd8 100644 (file)
@@ -5497,7 +5497,7 @@ ConvertRO(struct cmd_syndesc *as, void *arock)
     afs_uint32 volid;
     afs_uint32 server;
     afs_int32 code, i, same;
-    struct nvldbentry entry, storeEntry;
+    struct nvldbentry entry, checkEntry, storeEntry;
     afs_int32 vcode;
     afs_int32 rwindex = 0;
     afs_uint32 rwserver = 0;
@@ -5542,6 +5542,7 @@ ConvertRO(struct cmd_syndesc *as, void *arock)
     if (as->parms[3].items)
        force = 1;
 
+    memset(&entry, 0, sizeof(entry));
     vcode = VLDB_GetEntryByID(volid, -1, &entry);
     if (vcode) {
        fprintf(STDERR,
@@ -5552,7 +5553,6 @@ ConvertRO(struct cmd_syndesc *as, void *arock)
     }
 
     /* use RO volid even if user specified RW or BK volid */
-
     if (volid != entry.volumeId[ROVOL])
        volid = entry.volumeId[ROVOL];
 
@@ -5617,6 +5617,30 @@ ConvertRO(struct cmd_syndesc *as, void *arock)
        PrintError("", vcode);
        return -1;
     }
+
+    /* make sure the VLDB entry hasn't changed since we started */
+    memset(&checkEntry, 0, sizeof(checkEntry));
+    vcode = VLDB_GetEntryByID(volid, -1, &checkEntry);
+    if (vcode) {
+       fprintf(STDERR,
+                "Could not fetch the entry for volume %lu from VLDB\n",
+                (unsigned long)volid);
+       PrintError("convertROtoRW ", vcode);
+       code = vcode;
+       goto error_exit;
+    }
+
+    MapHostToNetwork(&checkEntry);
+    entry.flags &= ~VLOP_ALLOPERS;  /* clear any stale lock operation flags */
+    entry.flags |= VLOP_MOVE;        /* set to match SetLock operation above */
+    if (memcmp(&entry, &checkEntry, sizeof(entry)) != 0) {
+        fprintf(STDERR,
+                "VLDB entry for volume %lu has changed; please reissue the command.\n",
+                (unsigned long)volid);
+        code = -1;
+        goto error_exit;
+    }
+
     aconn = UV_Bind(server, AFSCONF_VOLUMEPORT);
     code = AFSVolConvertROtoRWvolume(aconn, partition, volid);
     if (code) {