transform/BindingRemapper: Validate access mode

Ensure that remapped access modes are valid enum values.

NB: This is hard to test, as UBSan flags an out-of-range enum value as
a hard error.

Fixed: chromium:1248754, chromium:1248755
Change-Id: I2e686843134e6a285fb8316a1960fc4eadff2a93
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/64120
Auto-Submit: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/ast/access.h b/src/ast/access.h
index 664e5e3..34d93e8 100644
--- a/src/ast/access.h
+++ b/src/ast/access.h
@@ -24,13 +24,15 @@
 /// The access control settings
 enum Access {
   /// Not declared in the source
-  kUndefined,
+  kUndefined = 0,
   /// Read only
   kRead,
   /// Write only
   kWrite,
   /// Read write
-  kReadWrite
+  kReadWrite,
+  // Last valid access mode
+  kLastValid = kReadWrite,
 };
 
 /// @param out the std::ostream to write to
diff --git a/src/transform/binding_remapper.cc b/src/transform/binding_remapper.cc
index 67d47cd..adecc84 100644
--- a/src/transform/binding_remapper.cc
+++ b/src/transform/binding_remapper.cc
@@ -113,6 +113,13 @@
       auto ac_it = remappings->access_controls.find(from);
       if (ac_it != remappings->access_controls.end()) {
         ast::Access ac = ac_it->second;
+        if (ac > ast::Access::kLastValid) {
+          ctx.dst->Diagnostics().add_error(
+              diag::System::Transform,
+              "invalid access mode (" +
+                  std::to_string(static_cast<uint32_t>(ac)) + ")");
+          return;
+        }
         auto* sem = ctx.src->Sem().Get(var);
         if (sem->StorageClass() != ast::StorageClass::kStorage) {
           ctx.dst->Diagnostics().add_error(