Skip to content

Commit c454457

Browse files
committed
Fix _removeNotInterestingHeaders
Upgrade the list structure to support quick insertion, and fix a use-after-free in _removeNotInterestingHeaders. This bug has been reported and "fixed" many times upstream, but several of those fixes seem to be bad. See me-no-dev/ESPAsyncWebServer me-no-dev#951, me-no-dev#837
1 parent 2d05da8 commit c454457

File tree

2 files changed

+59
-34
lines changed

2 files changed

+59
-34
lines changed

src/StringArray.h

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class LinkedListNode {
2929
T _value;
3030
public:
3131
LinkedListNode<T>* next;
32-
LinkedListNode(const T val): _value(val), next(nullptr) {}
32+
LinkedListNode(T val): _value(std::move(val)), next(nullptr) {}
3333
~LinkedListNode(){}
3434
const T& value() const { return _value; };
3535
T& value(){ return _value; }
@@ -43,11 +43,13 @@ class LinkedList {
4343
typedef std::function<bool(const T&)> Predicate;
4444
private:
4545
ItemType* _root;
46+
ItemType* _last;
4647
OnRemove _onRemove;
4748

4849
class Iterator {
4950
ItemType* _node;
5051
ItemType* _nextNode = nullptr;
52+
friend class LinkedList;
5153
public:
5254
Iterator(ItemType* current = nullptr) : _node(current) {
5355
_nextNode = _node != nullptr ? _node->next : nullptr;
@@ -64,23 +66,43 @@ class LinkedList {
6466
const T& operator * () const { return _node->value(); }
6567
const T* operator -> () const { return &_node->value(); }
6668
};
69+
70+
void _remove(ItemType* pit, ItemType* it) {
71+
if(pit == nullptr){ // item is root
72+
_root = _root->next;
73+
if (_root == nullptr) {
74+
_last = nullptr;
75+
}
76+
} else {
77+
pit->next = it->next;
78+
if (it == _last) {
79+
_last = pit;
80+
}
81+
}
82+
83+
if (_onRemove) {
84+
_onRemove(it->value());
85+
}
86+
87+
delete it;
88+
}
6789

6890
public:
6991
typedef const Iterator ConstIterator;
7092
ConstIterator begin() const { return ConstIterator(_root); }
7193
ConstIterator end() const { return ConstIterator(nullptr); }
7294

73-
LinkedList(OnRemove onRemove) : _root(nullptr), _onRemove(onRemove) {}
74-
~LinkedList(){}
75-
void add(const T& t){
76-
auto it = new ItemType(t);
95+
LinkedList(OnRemove onRemove) : _root(nullptr), _last(nullptr), _onRemove(onRemove) {}
96+
~LinkedList() { free(); }
97+
void add(T t){
98+
auto it = new ItemType(std::move(t));
7799
if(!_root){
78100
_root = it;
101+
_last = it;
79102
} else {
80-
auto i = _root;
81-
while(i->next) i = i->next;
82-
i->next = it;
103+
_last->next = it;
83104
}
105+
_last = it;
84106
}
85107
T& front() const {
86108
return _root->value();
@@ -124,20 +146,10 @@ class LinkedList {
124146
}
125147
bool remove(const T& t){
126148
auto it = _root;
127-
auto pit = _root;
149+
auto pit = decltype(it) { nullptr };
128150
while(it){
129151
if(it->value() == t){
130-
if(it == _root){
131-
_root = _root->next;
132-
} else {
133-
pit->next = it->next;
134-
}
135-
136-
if (_onRemove) {
137-
_onRemove(it->value());
138-
}
139-
140-
delete it;
152+
_remove(pit, it);
141153
return true;
142154
}
143155
pit = it;
@@ -147,26 +159,36 @@ class LinkedList {
147159
}
148160
bool remove_first(Predicate predicate){
149161
auto it = _root;
150-
auto pit = _root;
162+
auto pit = decltype(it) { nullptr };
151163
while(it){
152164
if(predicate(it->value())){
153-
if(it == _root){
154-
_root = _root->next;
155-
} else {
156-
pit->next = it->next;
157-
}
158-
if (_onRemove) {
159-
_onRemove(it->value());
160-
}
161-
delete it;
165+
_remove(pit, it);
162166
return true;
163167
}
164168
pit = it;
165169
it = it->next;
166170
}
167171
return false;
168172
}
169-
173+
bool remove(const ConstIterator& t, const ConstIterator& where = ConstIterator(nullptr)) {
174+
if (where._node) {
175+
if ((where._nextNode) != t._node) return false;
176+
_remove(where._node, t._node);
177+
return true;
178+
}
179+
180+
auto it = _root;
181+
auto pit = decltype(it) { nullptr };
182+
while(it){
183+
if(it == t._node){
184+
_remove(pit, it);
185+
return true;
186+
}
187+
pit = it;
188+
it = it->next;
189+
}
190+
return false;
191+
}
170192
void free(){
171193
while(_root != nullptr){
172194
auto it = _root;
@@ -177,6 +199,7 @@ class LinkedList {
177199
delete it;
178200
}
179201
_root = nullptr;
202+
_last = nullptr;
180203
}
181204
};
182205

src/WebRequest.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,11 @@ void AsyncWebServerRequest::_onData(void *buf, size_t len){
180180

181181
void AsyncWebServerRequest::_removeNotInterestingHeaders(){
182182
if (_interestingHeaders.containsIgnoreCase("ANY")) return; // nothing to do
183-
for(const auto& header: _headers){
184-
if(!_interestingHeaders.containsIgnoreCase(header->name().c_str())){
185-
_headers.remove(header);
183+
auto prev = decltype(_headers.begin()) { nullptr };
184+
for(auto it = _headers.begin(); it != _headers.end(); prev = it, ++it){
185+
if(!_interestingHeaders.containsIgnoreCase((*it)->name().c_str())){
186+
_headers.remove(it, prev);
187+
it = prev;
186188
}
187189
}
188190
}

0 commit comments

Comments
 (0)