Skip to content

Commit 5bc3079

Browse files
Fix Updater potential overflow, add host tests (#6954)
* Fix Updater potential overflow, add host tests Fixes #4674 The Updater class could, when exactly 4K bytes were in the buffer but not yet written to flash, allow overwriting data written to it beyond the passed-in size parameter. Fix per @jason-but's suggestion, and add a host test (plus minor changes to Updater code to support host testing). * Add missed mock file * Remove most testing ifdefs fro updater Per @mcspr's suggestion, we can pass in fake link symbols allowing Updater to take the address of `_FS_start`/etc. even when building on the host for testing. There is still a single remaining wifi_set_power_mode ifdef'd and a duplication of the digitalWrite/pinMode for testing vs. host building. Co-authored-by: Develo <[email protected]>
1 parent 5e537e5 commit 5bc3079

File tree

4 files changed

+121
-5
lines changed

4 files changed

+121
-5
lines changed

cores/esp8266/Updater.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
104104
_reset();
105105
clearError(); // _error = 0
106106

107+
#ifndef HOST_MOCK
107108
wifi_set_sleep_type(NONE_SLEEP_T);
109+
#endif
108110

109111
//address where we will start writing the update
110112
uintptr_t updateStartAddress = 0;
@@ -378,9 +380,7 @@ size_t UpdaterClass::write(uint8_t *data, size_t len) {
378380
if(hasError() || !isRunning())
379381
return 0;
380382

381-
if(len > remaining()){
382-
//len = remaining();
383-
//fail instead
383+
if(progress() + _bufferLen + len > _size) {
384384
_setError(UPDATE_ERROR_SPACE);
385385
return 0;
386386
}

tests/host/Makefile

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ LIBRARIES_PATH := ../../libraries
66
FORCE32 ?= 1
77
OPTZ ?= -Os
88
V ?= 0
9+
DEFSYM_FS ?= -Wl,--defsym,_FS_start=0x40300000 -Wl,--defsym,_FS_end=0x411FA000 -Wl,--defsym,_FS_page=0x100 -Wl,--defsym,_FS_block=0x2000 -Wl,--defsym,_EEPROM_start=0x411fb000
910

1011
MAKEFILE = $(word 1, $(MAKEFILE_LIST))
1112

@@ -70,6 +71,7 @@ CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\
7071
Schedule.cpp \
7172
HardwareSerial.cpp \
7273
crc32.cpp \
74+
Updater.cpp \
7375
) \
7476
$(addprefix $(LIBRARIES_PATH)/ESP8266SdFat/src/, \
7577
FatLib/FatFile.cpp \
@@ -98,6 +100,7 @@ MOCK_CPP_FILES_COMMON := $(addprefix common/,\
98100
MockUART.cpp \
99101
MockTools.cpp \
100102
MocklwIP.cpp \
103+
MockDigital.cpp \
101104
)
102105

103106
MOCK_CPP_FILES := $(MOCK_CPP_FILES_COMMON) $(addprefix common/,\
@@ -136,7 +139,8 @@ TEST_CPP_FILES := \
136139
core/test_md5builder.cpp \
137140
core/test_string.cpp \
138141
core/test_PolledTimeout.cpp \
139-
core/test_Print.cpp
142+
core/test_Print.cpp \
143+
core/test_Updater.cpp
140144

141145
PREINCLUDES := \
142146
-include common/mock.h \
@@ -233,7 +237,7 @@ $(BINDIR)/core.a: $(C_OBJECTS) $(CPP_OBJECTS_CORE)
233237
ranlib -c $@
234238

235239
$(OUTPUT_BINARY): $(CPP_OBJECTS_TESTS) $(BINDIR)/core.a
236-
$(VERBLD) $(CXX) $(LDFLAGS) $^ -o $@
240+
$(VERBLD) $(CXX) $(DEFSYM_FS) $(LDFLAGS) $^ -o $@
237241

238242
#################################################
239243
# building ino sources

tests/host/common/MockDigital.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
digital.c - wiring digital implementation for esp8266
3+
4+
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
5+
This file is part of the esp8266 core for Arduino environment.
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
#define ARDUINO_MAIN
22+
#include "wiring_private.h"
23+
#include "pins_arduino.h"
24+
#include "c_types.h"
25+
#include "eagle_soc.h"
26+
#include "ets_sys.h"
27+
#include "user_interface.h"
28+
#include "core_esp8266_waveform.h"
29+
#include "interrupts.h"
30+
31+
extern "C" {
32+
33+
static uint8_t _mode[17];
34+
static uint8_t _gpio[17];
35+
36+
extern void pinMode(uint8_t pin, uint8_t mode) {
37+
if (pin < 17) {
38+
_mode[pin] = mode;
39+
}
40+
}
41+
42+
extern void digitalWrite(uint8_t pin, uint8_t val) {
43+
if (pin < 17) {
44+
_gpio[pin] = val;
45+
}
46+
}
47+
48+
extern int digitalRead(uint8_t pin) {
49+
if (pin < 17) {
50+
return _gpio[pin] != 0;
51+
} else {
52+
return 0;
53+
}
54+
}
55+
56+
};

tests/host/core/test_Updater.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
test_Updater.cpp - Updater tests
3+
Copyright © 2019 Earle F. Philhower, III
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
*/
15+
16+
#include <catch.hpp>
17+
#include <Updater.h>
18+
19+
20+
// Use a SPIFFS file because we can't instantiate a virtual class like Print
21+
TEST_CASE("Updater fails when writes overflow requested size", "[core][Updater]")
22+
{
23+
UpdaterClass *u;
24+
uint8_t buff[6000];
25+
memset(buff, 0, sizeof(buff));
26+
u = new UpdaterClass();
27+
REQUIRE(u->begin(6000));
28+
REQUIRE(u->write(buff, 1000));
29+
REQUIRE(u->write(buff, 1000));
30+
REQUIRE(u->write(buff, 1000));
31+
REQUIRE(u->write(buff, 1000));
32+
REQUIRE(u->write(buff, 1000));
33+
REQUIRE(u->write(buff, 1000));
34+
REQUIRE(u->remaining() == 0);
35+
// All bytes written, should fail next
36+
REQUIRE(!u->write(buff, 1000));
37+
delete u;
38+
39+
// Updater to a 4K aligned size, check nomissing over/underflow
40+
u = new UpdaterClass();
41+
REQUIRE(u->begin(8192));
42+
REQUIRE(u->remaining() == 8192);
43+
REQUIRE(u->write(buff, 4096));
44+
REQUIRE(u->write(buff, 4096));
45+
REQUIRE(!u->write(buff, 1));
46+
delete u;
47+
48+
// Issue #4674
49+
u = new UpdaterClass();
50+
REQUIRE(u->begin(5000));
51+
REQUIRE(u->write(buff, 2048));
52+
REQUIRE(u->write(buff, 2048));
53+
// Should fail, would write 6KB
54+
REQUIRE(!u->write(buff, 2048));
55+
delete u;
56+
}

0 commit comments

Comments
 (0)