Skip to content

Nano Every - fatal security bug in Wire.h #11221

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

Open
mikrocoder opened this issue Jan 28, 2021 · 6 comments
Open

Nano Every - fatal security bug in Wire.h #11221

mikrocoder opened this issue Jan 28, 2021 · 6 comments
Labels
Library: Wire The Wire Arduino library Type: Bug

Comments

@mikrocoder
Copy link

mikrocoder commented Jan 28, 2021

Hallo,

wire.begin should disable 'output and 'pullup' of pin 18 and 19 before initializing TWI as a precaution. In case someone programs pin 18 and 19 digitally and then turns on TWI. Because pin 18/19 (PortF) TWI (PortA) are different ports, electrical short circuits could occur.
Another problem is that Wire.end does not turn off its own port pullups of PA2 and PA3. Pin 18 and 19 are inputs, Wire is terminated and still the pins output 4.7 volts.

Translated with www.DeepL.com/Translator (free version)

#include <Streaming.h>
#include <Wire.h>

const byte wait {1};  // for enventual electrical measurements

void setup(void) 
{
  Serial.begin(250000);
  Serial.println(F("\nStart #### #### #### ####"));
  showData();

  Serial.println("\nInput_Pullup.18");  pinMode(18, INPUT_PULLUP);  
  Serial.println("Input_Pullup.19");    pinMode(19, INPUT_PULLUP);
  showData();
  delay(wait);
  Serial.println("\nOutput.18");  pinMode(18, OUTPUT);        
  Serial.println("Output.19");    pinMode(19, OUTPUT);
  showData();
  delay(wait);
  Serial.println("\nWire.begin"); Wire.begin();
  showData();
  delay(wait);
  Serial.println("\nInput.18");   pinMode(18, INPUT);  
  Serial.println("Input.19");     pinMode(19, INPUT);
  showData();
  delay(wait);
  Serial.println("\nWire.end");   Wire.end();
  showData();
}

void loop(void) 
{ }

void showData(void)
{
  Serial << "TWI0_MCTRLA    " << _HEX((uint16_t)&TWI0_MCTRLA)    << '\t' << _BIN(TWI0_MCTRLA)    << endl;
  Serial << "TWI0_SCTRLA    " << _HEX((uint16_t)&TWI0_SCTRLA)    << '\t' << _BIN(TWI0_MCTRLA)    << endl;
  Serial << "PORTA_DIR      " << _HEX((uint16_t)&PORTA_DIR)      << '\t' << _BIN(PORTA_DIR)      << endl;
  Serial << "PORTA_PIN2CTRL " << _HEX((uint16_t)&PORTA_PIN2CTRL) << '\t' << _BIN(PORTA_PIN2CTRL) << endl;
  Serial << "PORTA_PIN3CTRL " << _HEX((uint16_t)&PORTA_PIN3CTRL) << '\t' << _BIN(PORTA_PIN3CTRL) << endl;
  Serial << "PORTF_DIR      " << _HEX((uint16_t)&PORTF_DIR)      << '\t' << _BIN(PORTF_DIR)      << endl;
  Serial << "PORTF_PIN2CTRL " << _HEX((uint16_t)&PORTF_PIN2CTRL) << '\t' << _BIN(PORTF_PIN2CTRL) << endl;
  Serial << "PORTF_PIN3CTRL " << _HEX((uint16_t)&PORTF_PIN3CTRL) << '\t' << _BIN(PORTF_PIN3CTRL) << endl;
}
@per1234 per1234 added Library: Wire The Wire Arduino library Type: Bug labels Jan 29, 2021
@mikrocoder
Copy link
Author

mikrocoder commented Jan 29, 2021

Edit: I have delete this code here, wrong file.


If that's not what you want, then you could replace the rest of the code in the two methods with

#if !defined(ARDUINO_AVR_NANO_EVERY)
...
#endif

frame. I don't know how this harmonizes with the big Arduino framework.

Furthermore you can consider to use a twi_disable() for a pinMode call for pin 18 and 19? This can ensure that the pins do not work against each other.

The thought with PF2/PF3 and PA2/PA3 is good, but is also somehow dangerous. :-)
Perhaps one should have built a small series resistor at PF2/PF3 on the board.

Translated with www.DeepL.com/Translator (free version)

@mikrocoder
Copy link
Author

mikrocoder commented Jan 29, 2021

And if we are going to edit TWI, we might as well delete these methods without replacement.

uint8_t TwoWire::requestFrom(int address, int quantity)

uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop)

They only generate unnecessary warnings and are good for nothing. The parameters are implicitly cast to uint8_t.

@mikrocoder
Copy link
Author

mikrocoder commented Jan 29, 2021

Sorry, I was in the wrong twi.c file for the Nano Every.

wrong path:
C:\Arduino IDE Portable\megaAVR0\arduino-1.8.13\hardware\arduino\avr\libraries\Wire\src\utility.

correct path:
C:\Arduino IDE Portable\megaAVR0\arduino-1.8.13\portable\packages\arduino\hardware\megaavr\1.8.7\libraries\Wire\src\utility.

The corrected proposal for the twi.c

void TWI_MasterInit(uint32_t frequency)
{
  if(twi_mode != TWI_MODE_UNKNOWN) return;

  // Precaution due to possible electrical short circuit. PA2/PA3 and PF2/PF3 share one pin.
  #if defined(ARDUINO_AVR_NANO_EVERY)
    // turn off pullups
    PORTF_PIN2CTRL = PORTF_PIN2CTRL & ~PORT_PULLUPEN_bm; // Pin 18 (PF2)
    PORTF_PIN3CTRL = PORTF_PIN3CTRL & ~PORT_PULLUPEN_bm; // Pin 19 (PF3)
    // switch to input
    PORTF_DIRCLR = PORTF_DIRCLR | PIN3_bm | PIN2_bm; // Pin 18 & 19
  #endif

  // Enable pullups just in case, should have external ones though

  #ifdef NO_EXTERNAL_I2C_PULLUP
    pinMode(PIN_WIRE_SDA, INPUT_PULLUP);
    pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
  #endif
  PORTMUX.TWISPIROUTEA |= TWI_MUX;

  twi_mode = TWI_MODE_MASTER;

  master_bytesRead = 0;
  master_bytesWritten = 0;
  master_trans_status = TWIM_STATUS_READY;
  master_result = TWIM_RESULT_UNKNOWN;

  TWI0.MCTRLA = TWI_RIEN_bm | TWI_WIEN_bm | TWI_ENABLE_bm;
  TWI_MasterSetBaud(frequency);
  TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc;
}

void TWI_SlaveInit(uint8_t address)
{
  if(twi_mode != TWI_MODE_UNKNOWN) return;

  // Precaution due to possible electrical short circuit. PA2/PA3 and PF2/PF3 share one pin.
  #if defined(ARDUINO_AVR_NANO_EVERY)
    // turn off pullups
    PORTF_PIN2CTRL = PORTF_PIN2CTRL & ~PORT_PULLUPEN_bm; // Pin 18 (PF2)
    PORTF_PIN3CTRL = PORTF_PIN3CTRL & ~PORT_PULLUPEN_bm; // Pin 19 (PF3)
    // switch to input
    PORTF_DIRCLR = PORTF_DIRCLR | PIN3_bm | PIN2_bm; // Pin 18 & 19
  #endif

  twi_mode = TWI_MODE_SLAVE;

  slave_bytesRead = 0;
  slave_bytesWritten = 0;
  slave_trans_status = TWIS_STATUS_READY;
  slave_result = TWIS_RESULT_UNKNOWN;
  slave_callUserRequest = 0;
  slave_callUserReceive = 0;

  TWI0.SADDR = address << 1;	
  TWI0.SCTRLA = TWI_DIEN_bm | TWI_APIEN_bm | TWI_PIEN_bm  | TWI_ENABLE_bm;

  /* Bus Error Detection circuitry needs Master enabled to work */
  TWI0.MCTRLA = TWI_ENABLE_bm;
}

void TWI_Disable(void)
{
  TWI0.MCTRLA = 0x00;
  TWI0.MBAUD = 0x00;
  TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc;
  TWI0.SADDR = 0x00;
  TWI0.SCTRLA = 0x00;

  twi_mode = TWI_MODE_UNKNOWN;

  // Precaution due to possible electrical short circuit. PA2/PA3 and PF2/PF3 share one pin.
  #if defined(ARDUINO_AVR_NANO_EVERY)
    // turn off pullups
    PORTA_PIN2CTRL = PORTA_PIN2CTRL & ~PORT_PULLUPEN_bm; // Pin 22 (PA2)
    PORTA_PIN3CTRL = PORTA_PIN3CTRL & ~PORT_PULLUPEN_bm; // Pin 23 (PA3)
    // switch to input
    PORTA_DIRCLR = PORTA_DIRCLR | PIN3_bm | PIN2_bm; // Pin 22 & 23
  #endif
}

@mikrocoder
Copy link
Author

Why are my code tags not working properly?
Is someone correcting this for me after the fact?

@per1234
Copy link
Collaborator

per1234 commented Jan 30, 2021

Why are my code tags not working properly?

You need to use code fencing. You are using inline code blocks, which only works for single lines or less. You can learn how to use code fencing from this guide:
https://guides.github.com/features/mastering-markdown/#examples

Is someone correcting this for me after the fact?

Yes. I have been adding code fencing to all your posts.

@mikrocoder
Copy link
Author

mikrocoder commented Jan 30, 2021

Okay thanks. 👍 I edited the previous post.

code tags != code tags

😄

To be honest, it's very cumbersome. If I may say so. But well, let's stay on the topic with the pins.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Library: Wire The Wire Arduino library Type: Bug
Projects
None yet
Development

No branches or pull requests

2 participants