Add debug module authentication.
authorTim Newsome <tim@sifive.com>
Tue, 27 Feb 2018 20:30:46 +0000 (12:30 -0800)
committerTim Newsome <tim@sifive.com>
Tue, 27 Feb 2018 20:30:46 +0000 (12:30 -0800)
Off by default, enabled with --debug-auth.
The protocol is very simple (definitely not secure) to allow debuggers
to test their authentication feature. To authenticate a debugger must:
1. Read authdata
2. Write to authdata the value that it just read, plus 1

riscv/debug_module.cc
riscv/debug_module.h
riscv/jtag_dtm.cc
riscv/sim.cc
riscv/sim.h
spike_main/spike.cc

index 12956a56426fd46d577fa7ae43dfe2e919f7aba8..f10c866ed26e21cec0f949b82712929bce898eef 100644 (file)
 
 ///////////////////////// debug_module_t
 
-debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits) :
+debug_module_t::debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits,
+    bool require_authentication) :
   progbufsize(progbufsize),
   program_buffer_bytes(4 + 4*progbufsize),
   max_bus_master_bits(max_bus_master_bits),
+  require_authentication(require_authentication),
   debug_progbuf_start(debug_data_start - program_buffer_bytes),
   debug_abstract_start(debug_progbuf_start - debug_abstract_size*4),
   sim(sim)
@@ -61,7 +63,7 @@ void debug_module_t::reset()
 
   dmstatus = {0};
   dmstatus.impebreak = true;
-  dmstatus.authenticated = 1;
+  dmstatus.authenticated = !require_authentication;
   dmstatus.version = 2;
 
   abstractcs = {0};
@@ -83,6 +85,8 @@ void debug_module_t::reset()
     sbcs.access16 = true;
   if (max_bus_master_bits >= 8)
     sbcs.access8 = true;
+
+  challenge = random();
 }
 
 void debug_module_t::add_device(bus_t *bus) {
@@ -458,6 +462,9 @@ bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
       case DMI_SBDATA3:
         result = sbdata[3];
         break;
+      case DMI_AUTHDATA:
+        result = challenge;
+        break;
       default:
         result = 0;
         D(fprintf(stderr, "Unexpected. Returning Error."));
@@ -548,6 +555,11 @@ bool debug_module_t::perform_abstract_command()
 bool debug_module_t::dmi_write(unsigned address, uint32_t value)
 {
   D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
+
+  if (!dmstatus.authenticated && address != DMI_AUTHDATA &&
+      address != DMI_DMCONTROL)
+    return false;
+
   if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
     unsigned i = address - DMI_DATA0;
     if (!abstractcs.busy)
@@ -580,6 +592,8 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
           if (!dmcontrol.dmactive && get_field(value, DMI_DMCONTROL_DMACTIVE))
             reset();
           dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
+          if (!dmstatus.authenticated)
+            return true;
           if (dmcontrol.dmactive) {
             dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
             dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
@@ -662,6 +676,18 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t value)
       case DMI_SBDATA3:
         sbdata[3] = value;
         return true;
+      case DMI_AUTHDATA:
+        D(fprintf(stderr, "debug authentication: got 0x%x; 0x%x unlocks\n", value,
+            challenge + secret));
+        if (require_authentication) {
+          if (value == challenge + secret) {
+            dmstatus.authenticated = true;
+          } else {
+            dmstatus.authenticated = false;
+            challenge = random();
+          }
+        }
+        return true;
     }
   }
   return false;
index 36037b402684e640b488f90af709572433b4328e..e554ffc8f3623863851a1a4f5fbf4192402fae69 100644 (file)
@@ -74,7 +74,14 @@ typedef struct {
 class debug_module_t : public abstract_device_t
 {
   public:
-    debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits);
+    /*
+     * If require_authentication is true, then a debugger must authenticate as
+     * follows:
+     * 1. Read a 32-bit value from authdata:
+     * 2. Write the value that was read back, plus one, to authdata.
+     */
+    debug_module_t(sim_t *sim, unsigned progbufsize, unsigned max_bus_master_bits,
+        bool require_authentication);
     ~debug_module_t();
 
     void add_device(bus_t *bus);
@@ -96,7 +103,8 @@ class debug_module_t : public abstract_device_t
     // Actual size of the program buffer, which is 1 word bigger than we let on
     // to implement the implicit ebreak at the end.
     unsigned program_buffer_bytes;
-    unsigned max_bus_master_bits ;
+    unsigned max_bus_master_bits;
+    bool require_authentication;
     static const unsigned debug_data_start = 0x380;
     unsigned debug_progbuf_start;
 
@@ -134,6 +142,9 @@ class debug_module_t : public abstract_device_t
     uint32_t sbaddress[4];
     uint32_t sbdata[4];
 
+    uint32_t challenge;
+    const uint32_t secret = 1;
+
     processor_t *current_proc() const;
     void reset();
     bool perform_abstract_command();
index 3a0e8d254096903e94ba0f1d828e6cf76d54dbbe..365528a49a7566919c7b0742151f3fab846b5435 100644 (file)
@@ -14,7 +14,8 @@
 enum {
   IR_IDCODE=1,
   IR_DTMCONTROL=0x10,
-  IR_DBUS=0x11
+  IR_DBUS=0x11,
+  IR_RESET=0x1c
 };
 
 #define DTMCONTROL_VERSION      0xf
@@ -104,8 +105,11 @@ void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) {
       case SHIFT_IR:
         _tdo = ir & 1;
         break;
-      case UPDATE_IR:
-        break;
+      //case UPDATE_IR:
+        //if (ir == IR_RESET) {
+          // Make a reset happen
+        //}
+        //break;
       default:
         break;
     }
index 009bb98845d3d9723132abe9a4e839169ae107cf..0e38c53fa96444a263f1560cbf631e21edc45497 100644 (file)
@@ -27,10 +27,11 @@ sim_t::sim_t(const char* isa, size_t nprocs, bool halted, reg_t start_pc,
              std::vector<std::pair<reg_t, mem_t*>> mems,
              const std::vector<std::string>& args,
              std::vector<int> const hartids, unsigned progsize,
-             unsigned max_bus_master_bits)
+             unsigned max_bus_master_bits, bool require_authentication)
   : htif_t(args), mems(mems), procs(std::max(nprocs, size_t(1))),
     start_pc(start_pc), current_step(0), current_proc(0), debug(false),
-    remote_bitbang(NULL), debug_module(this, progsize, max_bus_master_bits)
+    remote_bitbang(NULL),
+    debug_module(this, progsize, max_bus_master_bits, require_authentication)
 {
   signal(SIGINT, &handle_signal);
 
index 47f3a452077e650fa2ea868b23800b1a9ba568cf..6c6e4350702d62b240a42730a20f0b3efbd8f901 100644 (file)
@@ -22,7 +22,7 @@ public:
   sim_t(const char* isa, size_t _nprocs,  bool halted, reg_t start_pc,
         std::vector<std::pair<reg_t, mem_t*>> mems,
         const std::vector<std::string>& args, const std::vector<int> hartids,
-        unsigned progsize, unsigned max_bus_master_bits);
+        unsigned progsize, unsigned max_bus_master_bits, bool require_authentication);
   ~sim_t();
 
   // run the simulation to completion
index f77d488b4f2c6de73a924a95c0522319f3a064c0..eb57baf5abfe7360ebcd4010dde0807eda8df032 100644 (file)
@@ -36,9 +36,10 @@ static void help()
   fprintf(stderr, "  --extlib=<name>       Shared library to load\n");
   fprintf(stderr, "  --rbb-port=<port>     Listen on <port> for remote bitbang connection\n");
   fprintf(stderr, "  --dump-dts            Print device tree string and exit\n");
-  fprintf(stderr, "  --progsize=<words>    progsize for the debug module [default 2]\n");
-  fprintf(stderr, "  --debug-sba=<bits>    debug bus master supports up to "
+  fprintf(stderr, "  --progsize=<words>    Progsize for the debug module [default 2]\n");
+  fprintf(stderr, "  --debug-sba=<bits>    Debug bus master supports up to "
       "<bits> wide accesses [default 0]\n");
+  fprintf(stderr, "  --debug-auth          Debug module requires debugger to authenticate\n");
   exit(1);
 }
 
@@ -92,6 +93,7 @@ int main(int argc, char** argv)
   bool use_rbb = false;
   unsigned progsize = 2;
   unsigned max_bus_master_bits = 0;
+  bool require_authentication = false;
   std::vector<int> hartids;
 
   auto const hartids_parser = [&](const char *s) {
@@ -135,6 +137,8 @@ int main(int argc, char** argv)
   parser.option(0, "progsize", 1, [&](const char* s){progsize = atoi(s);});
   parser.option(0, "debug-sba", 1,
       [&](const char* s){max_bus_master_bits = atoi(s);});
+  parser.option(0, "debug-auth", 0,
+      [&](const char* s){require_authentication = true;});
 
   auto argv1 = parser.parse(argv);
   std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
@@ -142,7 +146,7 @@ int main(int argc, char** argv)
     mems = make_mems("2048");
 
   sim_t s(isa, nprocs, halted, start_pc, mems, htif_args, std::move(hartids),
-      progsize, max_bus_master_bits);
+      progsize, max_bus_master_bits, require_authentication);
   std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL);
   std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module));
   if (use_rbb) {