Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pin lock - RFC #622

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions comm/comm_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ static THD_FUNCTION(serial_process_thread, arg) {
}

static void process_packet(unsigned char *data, unsigned int len) {
commands_lock_writes(false);
// USB commands are not subject to PIN based write lock
commands_process_packet(data, len, comm_usb_send_packet);
commands_lock_writes(true);
}

static void send_packet_raw(unsigned char *buffer, unsigned int len) {
Expand Down
144 changes: 144 additions & 0 deletions comm/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ static THD_FUNCTION(blocking_thread, arg);
static THD_WORKING_AREA(blocking_thread_wa, 3000);
static thread_t *blocking_tp;

// PIN-Based Write-Lock
static bool is_lock_initialized = false;
static bool writelock = false;//true;
static unsigned int writelock_pin = 0;

// Private variables
static char print_buffer[PRINT_BUFFER_SIZE];
static uint8_t blocking_thread_cmd_buffer[PACKET_MAX_PL_LEN];
Expand Down Expand Up @@ -224,6 +229,48 @@ void commands_process_packet(unsigned char *data, unsigned int len,
send_func_can_fwd = reply_func;
}

if (commands_check_writelock()) {
if ((packet_id != COMM_FW_VERSION) &&
(packet_id != COMM_GET_MCCONF) &&
(packet_id != COMM_GET_APPCONF) &&
(packet_id != COMM_GET_VALUES) &&
(packet_id != COMM_GET_VALUES_SETUP) &&
(packet_id != COMM_GET_VALUES_SELECTIVE) &&
(packet_id != COMM_GET_VALUES_SETUP_SELECTIVE) &&
(packet_id != COMM_GET_DECODED_BALANCE) &&
(packet_id != COMM_GET_STATS) &&
(packet_id != COMM_RESET_STATS) &&
(packet_id != COMM_SET_ODOMETER) &&
(packet_id != COMM_GET_CUSTOM_CONFIG) &&
(packet_id != COMM_CUSTOM_APP_DATA) &&
(packet_id != COMM_LOCK_STATUS) &&
(packet_id != COMM_WRITE_LOCK)) {
//commands_printf("Blocked command: ID %d\n", packet_id);
return;
}
if (writelock && (packet_id == COMM_SET_ODOMETER)) {
// Temporary back door, to allow unlocking from older VESC Tools...
int32_t ind = 1;
uint32_t odo_new = buffer_get_uint32(data, &ind);
uint32_t odo_now = mc_interface_get_odometer();
// Writing the current odometer value removes the writelock
if (abs(odo_now-odo_new) < 500) {
// the VESC App only allows setting of odometer in km/mi not in meters
writelock = false;
}
return;
}
if ((packet_id == COMM_CUSTOM_APP_DATA) && (len > 2)) {
unsigned char magicnr = data[0];
unsigned char floatcmd = data[1];
if ((magicnr == 101) && (floatcmd != 10) && (floatcmd > 1)) {
// reject any float command that isn't just reading rt data
return;
}
}

}

switch (packet_id) {
case COMM_FW_VERSION: {
int32_t ind = 0;
Expand Down Expand Up @@ -317,6 +364,8 @@ void commands_process_packet(unsigned char *data, unsigned int len,
nrf_driver_pause(6000);
}
uint16_t flash_res = flash_helper_erase_new_app(buffer_get_uint32(data, &ind));
// For now, erase the PIN as well - in the future we may want to let the PIN persist
conf_general_set_writelock_pin(0, false);

ind = 0;
uint8_t send_buffer[50];
Expand Down Expand Up @@ -1643,6 +1692,79 @@ void commands_process_packet(unsigned char *data, unsigned int len,
conf_custom_process_cmd(data - 1, len + 1, reply_func);
} break;

case COMM_WRITE_LOCK: {
int32_t ind = 0;
if (len >= 3) {
uint8_t magic_number = data[ind++];
uint32_t pin = buffer_get_uint16(data, &ind);
uint8_t lock_enable = data[ind++];

if ((magic_number == 169) && (pin == writelock_pin)) {
writelock = (lock_enable && pin>0) ? true : false;
}
// Sends no response - call COMM_LOCK_STATUS to check success/fail
}
} break;

case COMM_LOCK_SETPIN: {
if (len >= 6) {
int32_t ind = 0;
uint8_t magic_number = data[ind++];
uint32_t old_pin = buffer_get_uint16(data, &ind);
uint32_t new_pin = buffer_get_uint16(data, &ind);
bool lock_on_boot = (data[ind++] == 1);

if (magic_number == 169) {
int didset = 0;
if (old_pin == writelock_pin) {
// write new pin to eeprom
conf_general_set_writelock_pin(new_pin, lock_on_boot);
writelock_pin = conf_general_get_writelock_pin();

// when lock_on_boot is set, we immediately enable writelock
writelock = (writelock_pin > 0) && lock_on_boot;
didset = 1;
}
else {
new_pin = 0;
}
ind = 0;

// Respond to confirm whether pin has indeed been accepted
uint8_t send_buffer[10];
send_buffer[ind++] = packet_id;
send_buffer[ind++] = 169; // magic number!
send_buffer[ind++] = didset; // if 0 it means old PIN didn't match
send_buffer[ind++] = (new_pin >> 8) & 0xFF; // return the newly set pin...
send_buffer[ind++] = new_pin & 0xFF;
reply_func(send_buffer, ind);
}
}
} break;

case COMM_LOCK_STATUS: {
int32_t ind = 0;
// receive 1-byte magic number and 2-byte PIN code
uint8_t magic_number = data[ind++];
uint32_t pin = buffer_get_uint16(data, &ind);

if (magic_number == 169) {
ind = 0;
uint8_t send_buffer[10];
send_buffer[ind++] = packet_id;
send_buffer[ind++] = 169; // magic number!
send_buffer[ind++] = writelock; // is writelock currently in place?
send_buffer[ind++] = (pin == writelock_pin); // does the passed pin match?
send_buffer[ind++] = (writelock_pin != 0); // is a pin set?
send_buffer[ind++] = conf_general_is_locked_on_boot();

// TEMPORARY: for development only, pass the stored pin (obviously unsafe!)
send_buffer[ind++] = (writelock_pin >> 8) & 0xFF;
send_buffer[ind++] = writelock_pin & 0xFF;
reply_func(send_buffer, ind);
}
} break;

// Blocking commands. Only one of them runs at any given time, in their
// own thread. If other blocking commands come before the previous one has
// finished, they are discarded.
Expand Down Expand Up @@ -2431,3 +2553,25 @@ static THD_FUNCTION(blocking_thread, arg) {
}
}
}

void commands_lock_writes(bool lock)
{
if (lock && (writelock_pin > 0)) {
writelock = true;
}
if (!lock) {
writelock = false;
}
}

bool commands_check_writelock()
{
if (!is_lock_initialized) {
// load PIN from EEPROM and lock if lock-on-boot is set
writelock_pin = conf_general_get_writelock_pin();
writelock = conf_general_is_locked_on_boot();
is_lock_initialized = true;

}
return writelock;
}
2 changes: 2 additions & 0 deletions comm/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@ void commands_plot_add_graph(char *name);
void commands_plot_set_graph(int graph);
void commands_send_plot_points(float x, float y);
int commands_get_fw_version_sent_cnt(void);
void commands_lock_writes(bool lock);
bool commands_check_writelock(void);

#endif /* COMMANDS_H_ */
41 changes: 41 additions & 0 deletions conf_general.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,16 @@ void conf_general_init(void) {
if (g_backup.hw_config_init_flag == BACKUP_VAR_INIT_CODE) {
memcpy((void*)backup_tmp.hw_config, (uint8_t*)g_backup.hw_config, sizeof(g_backup.hw_config));
}

if (g_backup.writelock_pin_init_flag == BACKUP_VAR_INIT_CODE) {
backup_tmp.writelock_pin_code = g_backup.writelock_pin_code;
}
}

backup_tmp.odometer_init_flag = BACKUP_VAR_INIT_CODE;
backup_tmp.runtime_init_flag = BACKUP_VAR_INIT_CODE;
backup_tmp.hw_config_init_flag = BACKUP_VAR_INIT_CODE;
backup_tmp.writelock_pin_init_flag = BACKUP_VAR_INIT_CODE;

g_backup = backup_tmp;
conf_general_store_backup_data();
Expand Down Expand Up @@ -2168,3 +2173,39 @@ int conf_general_detect_apply_all_foc_can(bool detect_can, float max_power_loss,

return res;
}

#define WRITELOCK_PIN_MAGIC_NR 169

uint16_t conf_general_get_writelock_pin()
{
uint32_t pin = g_backup.writelock_pin_code;
uint32_t magicnr = (pin >> 16) & 0x7FFF;

// return pin provided the magic number (upper 16bit) matches
if (magicnr == WRITELOCK_PIN_MAGIC_NR) {
return (uint16_t)pin & 0xFFFF;
}
return 0;
}

bool conf_general_is_locked_on_boot()
{
uint32_t pin = g_backup.writelock_pin_code;
uint32_t magicnr = (pin >> 16) & 0x7FFF;

// return pin provided the magic number (upper 16bit) matches
if (magicnr == WRITELOCK_PIN_MAGIC_NR) {
return ((pin & 0x80000000) != 0);
}
return 0;
}

void conf_general_set_writelock_pin(uint16_t pin, bool lock_on_boot)
{
g_backup.writelock_pin_code = (WRITELOCK_PIN_MAGIC_NR << 16) + pin;
if (lock_on_boot && (pin > 0)) {
// BIT31 indicates the board should be locked on boot
g_backup.writelock_pin_code |= 1 << 31;
}
conf_general_store_backup_data();
}
4 changes: 3 additions & 1 deletion conf_general.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ int conf_general_detect_apply_all_foc_can(bool detect_can, float max_power_loss,
float min_current_in, float max_current_in,
float openloop_rpm, float sl_erpm,
void(*reply_func)(unsigned char* data, unsigned int len));

uint16_t conf_general_get_writelock_pin(void);
bool conf_general_is_locked_on_boot(void);
void conf_general_set_writelock_pin(uint16_t pin, bool lock_on_boot);

#endif /* CONF_GENERAL_H_ */
8 changes: 8 additions & 0 deletions datatypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,11 @@ typedef enum {
COMM_GET_GNSS,

COMM_LOG_DATA_F64,

// PIN Lock to write-protect firmware
COMM_LOCK_SETPIN,
COMM_WRITE_LOCK,
COMM_LOCK_STATUS,
} COMM_PACKET_ID;

// CAN commands
Expand Down Expand Up @@ -1459,6 +1464,9 @@ typedef struct __attribute__((packed)) {
// HW-specific data
uint32_t hw_config_init_flag;
uint8_t hw_config[128];

uint32_t writelock_pin_init_flag;
uint32_t writelock_pin_code;
} backup_data;

#endif /* DATATYPES_H_ */