diff --git a/python/ql/src/experimental/Security/BufferedRWPairUndefinedBehavior.qhelp b/python/ql/src/experimental/Security/BufferedRWPairUndefinedBehavior.qhelp new file mode 100644 index 000000000000..8921ff5d2766 --- /dev/null +++ b/python/ql/src/experimental/Security/BufferedRWPairUndefinedBehavior.qhelp @@ -0,0 +1,24 @@ +<!DOCTYPE qhelp PUBLIC +"-//Semmle//qhelp//EN" +"qhelp.dtd"> +<qhelp> + + <overview> + <p> + <code>BufferedRWPair</code> does not attempt to synchronize accesses to its underlying raw streams. + You should not pass it the same object as reader and writer. + </p> + </overview> + + <recommendation> + <p> + + Use <code>BufferedRandom</code> instead. + + </p> + </recommendation> + + <references> + <li>Python Documentation: <a href="https://docs.python.org/3/library/io.html#io.BufferedRWPair">BufferedRWPair</a></li> + </references> +</qhelp> diff --git a/python/ql/src/experimental/Security/BufferedRWPairUndefinedBehavior.ql b/python/ql/src/experimental/Security/BufferedRWPairUndefinedBehavior.ql new file mode 100644 index 000000000000..e3029fb589cf --- /dev/null +++ b/python/ql/src/experimental/Security/BufferedRWPairUndefinedBehavior.ql @@ -0,0 +1,24 @@ +/** + * @name Same parameter used as reader and writer in BufferedRWPair + * @description Use of same parameter as reader and writer in BufferedRWPair. + * @kind problem + * @problem.severity warning + * @id py/bufferedrwpair-undefined-behavior + * @tags reliability + * security + * external/cwe/cwe-475 + * external/cwe/cwe-758 + */ + +import python + +ClassValue requestFunction() { result = Module::named("io").attr("BufferedRWPair") } + +from CallNode call, ClassValue func, ControlFlowNode read, ControlFlowNode write +where + func = requestFunction() and + func.getACall() = call and + read = call.getArg(0) and + write = call.getArg(1) and + read.pointsTo() = write.pointsTo() +select call, "Using the same reader and writer for BufferedRWPair may cause unexpected behavior" diff --git a/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.expected b/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.expected new file mode 100644 index 000000000000..48c0e2710835 --- /dev/null +++ b/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.expected @@ -0,0 +1 @@ +| BufferedRWPairUndefinedBehavior.py:7:13:7:45 | ControlFlowNode for Attribute() | Using the same reader and writer for BufferedRWPair may cause unexpected behavior | diff --git a/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.py b/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.py new file mode 100644 index 000000000000..ca4e44825caa --- /dev/null +++ b/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.py @@ -0,0 +1,16 @@ +import io + +def buffer_rw_pair_test(): + + reader = io.BufferedReader(io.RawIOBase) + # BAD, uses reader for both parameters + pair1 = io.BufferedRWPair(reader, reader) + + writer = io.BufferedWriter(io.RawIOBase) + # GOOD, uses different reader/writer + pair2 = io.BufferedRWPair(reader, writer) + + # GOOD, uses reader variable as both reader and writer for random access + random = io.BufferedRandom(reader) + + return (pair1, pair2, random) \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.qlref b/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.qlref new file mode 100644 index 000000000000..42a2c930029f --- /dev/null +++ b/python/ql/test/experimental/query-tests/BufferedRWPairUndefinedBehavior.qlref @@ -0,0 +1 @@ +experimental/Security/BufferedRWPairUndefinedBehavior.ql \ No newline at end of file