/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Mutex for modifying our hash tables
StaticMutex gConnRecvMutex;
// This structure will be created by addNetworkFuzzingBuffer below // and then added to the gNetworkFuzzingBuffers structure. // // It is assigned on connect and associated with the socket it belongs to. typedefstruct { const uint8_t* buf;
size_t size; bool allowRead; bool allowUnused;
PRNetAddr* addr;
} NetworkFuzzingBuffer;
// This holds all connections we have currently open.
MOZ_RUNINIT static nsTHashMap<nsPtrHashKey<PRFileDesc>, NetworkFuzzingBuffer*>
gConnectedNetworkFuzzingBuffers;
// This holds all buffers for connections we can still open.
MOZ_RUNINIT static nsDeque<NetworkFuzzingBuffer> gNetworkFuzzingBuffers;
// This is `true` once all connections are closed and either there are // no buffers left to be used or all remaining buffers are marked optional. // Used by `signalNetworkFuzzingDone` to tell the main thread if it needs // to spin-wait for `gFuzzingConnClosed`. static Atomic<bool> fuzzingNoWaitRequired(false);
// Used to memorize if the main thread has indicated that it is done with // its iteration and we don't expect more connections now. static Atomic<bool> fuzzingMainSignaledDone(false);
/* * The flag `gFuzzingConnClosed` is set by `FuzzyClose` when all connections * are closed *and* there are no more buffers in `gNetworkFuzzingBuffers` that * must be used. The main thread spins until this becomes true to synchronize * the fuzzing iteration between the main thread and the socket thread, if * the prior call to `signalNetworkFuzzingDone` returned `false`.
*/
Atomic<bool> gFuzzingConnClosed(true);
/* * This method should be called by fuzzing from the main thread to signal to * the layer code that a fuzzing iteration is done. As a result, we can throw * away any optional buffers and signal back once all connections have been * closed. The main thread should synchronize on all connections being closed * after the actual request/action is complete.
*/ bool signalNetworkFuzzingDone() {
FUZZING_LOG(("[signalNetworkFuzzingDone] Called."));
StaticMutexAutoLock lock(gConnRecvMutex); bool rv = false;
if (fuzzingNoWaitRequired) {
FUZZING_LOG(("[signalNetworkFuzzingDone] Purging remaining buffers.")); // Easy case, we already have no connections and non-optional buffers left.
gNetworkFuzzingBuffers.Erase();
gFuzzingConnClosed = true;
rv = true;
} else { // We still have either connections left open or non-optional buffers left. // In this case, FuzzyClose will handle the tear-down and signaling.
fuzzingMainSignaledDone = true;
}
// Store connection address
buf->addr = new PRNetAddr;
memcpy(buf->addr, addr, sizeof(PRNetAddr));
fuzzingNoWaitRequired = false;
FUZZING_LOG(("[FuzzySendTo] Successfully opened connection: %p", fd));
gFuzzingConnClosed = false;
}
// Allow reading once the implementation has written at least some data if (fuzzBuf && !fuzzBuf->allowRead) {
FUZZING_LOG(("[FuzzySendTo] Write received, allowing further reads."));
fuzzBuf->allowRead = true;
}
FUZZING_LOG(("[FuzzySendTo] Sent %" PRIx32 " bytes of data.", amount));
NetworkFuzzingBuffer* fuzzBuf = gConnectedNetworkFuzzingBuffers.Get(fd); if (!fuzzBuf) {
FUZZING_LOG(("[FuzzySend] Write on socket that is not connected."));
amount = 0;
}
// Allow reading once the implementation has written at least some data if (fuzzBuf && !fuzzBuf->allowRead) {
FUZZING_LOG(("[FuzzySend] Write received, allowing further reads."));
fuzzBuf->allowRead = true;
}
FUZZING_LOG(("[FuzzySend] Sent %" PRIx32 " bytes of data.", amount));
NetworkFuzzingBuffer* fuzzBuf = gConnectedNetworkFuzzingBuffers.Get(fd); if (!fuzzBuf) {
FUZZING_LOG(("[FuzzyRecv] Denying read, connection is closed.")); return 0;
}
// As long as we haven't written anything, act as if no data was there yet if (!fuzzBuf->allowRead) {
FUZZING_LOG(("[FuzzyRecv] Denying read, nothing written before."));
PR_SetError(PR_WOULD_BLOCK_ERROR, 0); return -1;
}
if (gFuzzingConnClosed) {
FUZZING_LOG(("[FuzzyRecv] Denying read, connection is closed.")); return 0;
}
// No data left, act as if the connection was closed. if (!fuzzBuf->size) {
FUZZING_LOG(("[FuzzyRecv] Read failed, no data left.")); return 0;
}
// Use the remains of fuzzing buffer, if too little is left if (fuzzBuf->size < (PRUint32)amount) amount = fuzzBuf->size;
// Consume buffer, copy data
memcpy(buf, fuzzBuf->buf, amount);
static PRStatus FuzzyClose(PRFileDesc* fd) { if (!fd) { return PR_FAILURE;
}
PRFileDesc* layer = PR_PopIOLayer(fd, PR_TOP_IO_LAYER);
MOZ_RELEASE_ASSERT(layer && layer->identity == sFuzzyLayerIdentity, "Fuzzy Layer not on top of stack");
layer->dtor(layer);
StaticMutexAutoLock lock(gConnRecvMutex);
NetworkFuzzingBuffer* fuzzBuf = nullptr; if (gConnectedNetworkFuzzingBuffers.Remove(fd, &fuzzBuf)) {
FUZZING_LOG(("[FuzzyClose] Received close on socket %p", fd)); if (fuzzBuf->addr) { delete fuzzBuf->addr;
} delete fuzzBuf;
} else { /* Happens when close is called on a non-connected socket */
FUZZING_LOG(("[FuzzyClose] Received close on unknown socket %p.", fd));
}
PRStatus ret = fd->methods->close(fd);
if (!gConnectedNetworkFuzzingBuffers.Count()) { // At this point, all connections are closed, but we might still have // unused network buffers that were not marked as optional. bool haveRemainingUnusedBuffers = false; for (size_t i = 0; i < gNetworkFuzzingBuffers.GetSize(); ++i) {
NetworkFuzzingBuffer* buf = gNetworkFuzzingBuffers.ObjectAt(i);
if (!buf->allowUnused) {
haveRemainingUnusedBuffers = true; break;
}
}
if (haveRemainingUnusedBuffers) {
FUZZING_LOG(
("[FuzzyClose] All connections closed, waiting for remaining " "connections."));
} elseif (!fuzzingMainSignaledDone) { // We have no connections left, but the main thread hasn't signaled us // yet. For now, that means once the main thread signals us, we can tell // it immediately that it won't have to wait for closing connections.
FUZZING_LOG(
("[FuzzyClose] All connections closed, waiting for main thread."));
fuzzingNoWaitRequired = true;
} else { // No connections left and main thread is already done. Perform cleanup // and then signal the main thread to continue.
FUZZING_LOG(("[FuzzyClose] All connections closed, cleaning up."));
// We need to dispatch this so the main thread is guaranteed to wake up
nsCOMPtr<nsIRunnable> r(new mozilla::Runnable("Dummy"));
NS_DispatchToMainThread(r.forget());
}
} else {
FUZZING_LOG(("[FuzzyClose] Connection closed."));
}
return ret;
}
nsresult AttachFuzzyIOLayer(PRFileDesc* fd) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.