From cef3cd9b54e9194128c839af696fd84f0bc05a51 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 10 Apr 2025 14:58:23 +0100 Subject: [PATCH 1/6] Rust: Add tests for std::io sources. --- .../dataflow/sources/TaintSources.expected | 2 +- .../library-tests/dataflow/sources/test.rs | 149 ++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected index 8448ee783720..6edfbb562da0 100644 --- a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected +++ b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected @@ -22,4 +22,4 @@ | test.rs:80:24:80:35 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). | | test.rs:112:35:112:46 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). | | test.rs:119:31:119:42 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). | -| test.rs:203:16:203:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs (DEFAULT). | +| test.rs:352:16:352:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs (DEFAULT). | diff --git a/rust/ql/test/library-tests/dataflow/sources/test.rs b/rust/ql/test/library-tests/dataflow/sources/test.rs index e4c6b2736d74..3e5e55568704 100644 --- a/rust/ql/test/library-tests/dataflow/sources/test.rs +++ b/rust/ql/test/library-tests/dataflow/sources/test.rs @@ -198,6 +198,155 @@ async fn test_hyper_http(case: i64) -> Result<(), Box> { Ok(()) } +use std::io::Read; +use std::io::BufRead; + +fn test_io_fs() -> std::io::Result<()> { + // --- stdin --- + + { + let mut buffer = [0u8; 100]; + let _bytes = std::io::stdin().read(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = Vec::::new(); + let _bytes = std::io::stdin().read_to_end(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = String::new(); + let _bytes = std::io::stdin().read_to_string(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = [0; 100]; + std::io::stdin().read_exact(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(&buffer); // $ MISSING: hasTaintFlow + } + + for byte in std::io::stdin().bytes() { // $ MISSING: Alert[rust/summary/taint-sources] + sink(byte); // $ MISSING: hasTaintFlow + } + + // --- file --- + + let mut file = std::fs::File::open("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + + { + let mut buffer = [0u8; 100]; + let _bytes = file.read(&mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = Vec::::new(); + let _bytes = file.read_to_end(&mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = String::new(); + let _bytes = file.read_to_string(&mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = [0; 100]; + file.read_exact(&mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + for byte in file.bytes() { + sink(byte); // $ MISSING: hasTaintFlow + } + + // --- BufReader --- + + { + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let data = reader.fill_buf()?; + sink(&data); // $ MISSING: hasTaintFlow + } + + { + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let data = reader.buffer(); + sink(&data); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = String::new(); + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + reader.read_line(&mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = Vec::::new(); + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + reader.read_until(b',', &mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = Vec::::new(); + let mut reader_split = std::io::BufReader::new(std::io::stdin()).split(b','); // $ MISSING: Alert[rust/summary/taint-sources] + while let Some(chunk) = reader_split.next() { + sink(chunk.unwrap()); // $ MISSING: hasTaintFlow + } + } + + { + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + for line in reader.lines() { + sink(line); // $ MISSING: Alert[rust/summary/taint-sources] + } + } + + { + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let line = reader.lines().nth(1).unwrap(); + sink(line.unwrap().clone()); // $ MISSING: hasTaintFlow + } + + { + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let lines: Vec<_> = reader.lines().collect(); + sink(lines[1].as_ref().unwrap().clone()); // $ MISSING: hasTaintFlow + } + + // --- misc operations --- + + { + let mut buffer = String::new(); + let mut file1 = std::fs::File::open("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + let mut file2 = std::fs::File::open("another_file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = file1.chain(file2); + reader.read_to_string(&mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = String::new(); + let mut file1 = std::fs::File::open("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = file1.take(100); + reader.read_to_string(&mut buffer)?; + sink(&buffer); // $ MISSING: hasTaintFlow + } + + { + let mut buffer = String::new(); + let _bytes = std::io::stdin().lock().read_to_string(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(&buffer); // $ MISSING: hasTaintFlow + } + + Ok(()) +} + #[tokio::main] async fn main() -> Result<(), Box> { let case = std::env::args().nth(1).unwrap_or(String::from("1")).parse::().unwrap(); // $ Alert[rust/summary/taint-sources] From 258c1afe27d7c108b931df752efe90a4ba11bb1c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 11 Apr 2025 10:06:49 +0100 Subject: [PATCH 2/6] Rust: Add tests for std::fs sources. --- .../dataflow/sources/TaintSources.expected | 2 +- .../library-tests/dataflow/sources/test.rs | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected index 6edfbb562da0..312842134d5e 100644 --- a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected +++ b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected @@ -22,4 +22,4 @@ | test.rs:80:24:80:35 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). | | test.rs:112:35:112:46 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). | | test.rs:119:31:119:42 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). | -| test.rs:352:16:352:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs (DEFAULT). | +| test.rs:386:16:386:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs (DEFAULT). | diff --git a/rust/ql/test/library-tests/dataflow/sources/test.rs b/rust/ql/test/library-tests/dataflow/sources/test.rs index 3e5e55568704..fa6f3ec37b1d 100644 --- a/rust/ql/test/library-tests/dataflow/sources/test.rs +++ b/rust/ql/test/library-tests/dataflow/sources/test.rs @@ -198,6 +198,40 @@ async fn test_hyper_http(case: i64) -> Result<(), Box> { Ok(()) } +use std::fs; + +fn test_fs() -> Result<(), Box> { + { + let buffer: Vec = std::fs::read("file.bin")?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(buffer); // $ MISSING: hasTaintFlow + } + + { + let buffer: Vec = fs::read("file.bin")?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(buffer); // $ MISSING: hasTaintFlow + } + + { + let buffer = fs::read_to_string("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(buffer); // $ MISSING: hasTaintFlow + } + + for entry in fs::read_dir("directory")? { + let e = entry?; + let path = e.path(); // $ MISSING: Alert[rust/summary/taint-sources] + let file_name = e.file_name(); // $ MISSING: Alert[rust/summary/taint-sources] + sink(path); // $ MISSING: hasTaintFlow + sink(file_name); // $ MISSING: hasTaintFlow + } + + { + let target = fs::read_link("symlink.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + sink(target); // $ MISSING: hasTaintFlow + } + + Ok(()) +} + use std::io::Read; use std::io::BufRead; From 4f9f550ba62863e9c1ce3a681e5ffcc6190b3d30 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:18:37 +0100 Subject: [PATCH 3/6] Rust: Add source models for fs. --- rust/ql/lib/codeql/rust/Concepts.qll | 26 +++++++++++++++ .../rust/frameworks/stdlib/fs.model.yml | 10 ++++-- .../dataflow/sources/TaintSources.expected | 10 ++++++ .../library-tests/dataflow/sources/test.rs | 32 +++++++++---------- 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 723cde6913a8..10bf4d86998b 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -102,6 +102,32 @@ class ModeledEnvironmentSource extends EnvironmentSource::Range { ModeledEnvironmentSource() { sourceNode(this, "environment-source") } } +/** + * A data flow source corresponding to a file access. + */ +final class FileSource = FileSource::Range; + +/** + * An externally modeled source for data from a file access. + */ +class ModeledFileSource extends FileSource::Range { + ModeledFileSource() { sourceNode(this, "file") } +} + +/** + * Provides a class for modeling new sources for file accesses. + */ +module FileSource { + /** + * A data flow source corresponding to a file access. + */ + abstract class Range extends ThreatModelSource::Range { + override string getThreatModel() { result = "file" } + + override string getSourceType() { result = "FileSource" } + } +} + /** * A data flow source corresponding to the program's database reads. */ diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/fs.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/fs.model.yml index c7fa72793306..436ff2002baa 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/fs.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/fs.model.yml @@ -2,7 +2,14 @@ extensions: - addsTo: pack: codeql/rust-all extensible: sourceModel - data: [] + data: + - ["lang:std", "crate::fs::read", "ReturnValue.Field[crate::result::Result::Ok(0)]", "file", "manual"] + - ["lang:std", "crate::fs::read_to_string", "ReturnValue.Field[crate::result::Result::Ok(0)]", "file", "manual"] + - ["lang:std", "crate::fs::read_link", "ReturnValue.Field[crate::result::Result::Ok(0)]", "file", "manual"] + - ["lang:std", "::path", "ReturnValue", "file", "manual"] + - ["lang:std", "::file_name", "ReturnValue", "file", "manual"] + - ["lang:std", "::open", "ReturnValue.Field[crate::result::Result::Ok(0)]", "file", "manual"] + - ["lang:std", "::open_buffered", "ReturnValue.Field[crate::result::Result::Ok(0)]", "file", "manual"] - addsTo: pack: codeql/rust-all extensible: sinkModel @@ -34,7 +41,6 @@ extensions: - ["lang:std", "::create_new", "Argument[0]", "path-injection", "manual"] - ["lang:std", "::open", "Argument[0]", "path-injection", "manual"] - ["lang:std", "::open_buffered", "Argument[0]", "path-injection", "manual"] - - addsTo: pack: codeql/rust-all extensible: summaryModel diff --git a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected index 312842134d5e..5f02eb718457 100644 --- a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected +++ b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected @@ -22,4 +22,14 @@ | test.rs:80:24:80:35 | ...::get | Flow source 'RemoteSource' of type remote (DEFAULT). | | test.rs:112:35:112:46 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). | | test.rs:119:31:119:42 | send_request | Flow source 'RemoteSource' of type remote (DEFAULT). | +| test.rs:205:31:205:43 | ...::read | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:210:31:210:38 | ...::read | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:215:22:215:39 | ...::read_to_string | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:221:22:221:25 | path | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:222:27:222:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:228:22:228:34 | ...::read_link | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:271:20:271:38 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:360:25:360:43 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:361:25:361:43 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:369:25:369:43 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:386:16:386:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs (DEFAULT). | diff --git a/rust/ql/test/library-tests/dataflow/sources/test.rs b/rust/ql/test/library-tests/dataflow/sources/test.rs index fa6f3ec37b1d..ed33e5841287 100644 --- a/rust/ql/test/library-tests/dataflow/sources/test.rs +++ b/rust/ql/test/library-tests/dataflow/sources/test.rs @@ -202,31 +202,31 @@ use std::fs; fn test_fs() -> Result<(), Box> { { - let buffer: Vec = std::fs::read("file.bin")?; // $ MISSING: Alert[rust/summary/taint-sources] - sink(buffer); // $ MISSING: hasTaintFlow + let buffer: Vec = std::fs::read("file.bin")?; // $ Alert[rust/summary/taint-sources] + sink(buffer); // $ hasTaintFlow="file.bin" } { - let buffer: Vec = fs::read("file.bin")?; // $ MISSING: Alert[rust/summary/taint-sources] - sink(buffer); // $ MISSING: hasTaintFlow + let buffer: Vec = fs::read("file.bin")?; // $ Alert[rust/summary/taint-sources] + sink(buffer); // $ hasTaintFlow="file.bin" } { - let buffer = fs::read_to_string("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] - sink(buffer); // $ MISSING: hasTaintFlow + let buffer = fs::read_to_string("file.txt")?; // $ Alert[rust/summary/taint-sources] + sink(buffer); // $ hasTaintFlow="file.txt" } for entry in fs::read_dir("directory")? { let e = entry?; - let path = e.path(); // $ MISSING: Alert[rust/summary/taint-sources] - let file_name = e.file_name(); // $ MISSING: Alert[rust/summary/taint-sources] - sink(path); // $ MISSING: hasTaintFlow - sink(file_name); // $ MISSING: hasTaintFlow + let path = e.path(); // $ Alert[rust/summary/taint-sources] + let file_name = e.file_name(); // $ Alert[rust/summary/taint-sources] + sink(path); // $ hasTaintFlow + sink(file_name); // $ hasTaintFlow } { - let target = fs::read_link("symlink.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] - sink(target); // $ MISSING: hasTaintFlow + let target = fs::read_link("symlink.txt")?; // $ Alert[rust/summary/taint-sources] + sink(target); // $ hasTaintFlow="symlink.txt" } Ok(()) @@ -268,7 +268,7 @@ fn test_io_fs() -> std::io::Result<()> { // --- file --- - let mut file = std::fs::File::open("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + let mut file = std::fs::File::open("file.txt")?; // $ Alert[rust/summary/taint-sources] { let mut buffer = [0u8; 100]; @@ -357,8 +357,8 @@ fn test_io_fs() -> std::io::Result<()> { { let mut buffer = String::new(); - let mut file1 = std::fs::File::open("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] - let mut file2 = std::fs::File::open("another_file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + let mut file1 = std::fs::File::open("file.txt")?; // $ Alert[rust/summary/taint-sources] + let mut file2 = std::fs::File::open("another_file.txt")?; // $ Alert[rust/summary/taint-sources] let mut reader = file1.chain(file2); reader.read_to_string(&mut buffer)?; sink(&buffer); // $ MISSING: hasTaintFlow @@ -366,7 +366,7 @@ fn test_io_fs() -> std::io::Result<()> { { let mut buffer = String::new(); - let mut file1 = std::fs::File::open("file.txt")?; // $ MISSING: Alert[rust/summary/taint-sources] + let mut file1 = std::fs::File::open("file.txt")?; // $ Alert[rust/summary/taint-sources] let mut reader = file1.take(100); reader.read_to_string(&mut buffer)?; sink(&buffer); // $ MISSING: hasTaintFlow From 7a9ea52bc79a693c749dca09e512add9568260dc Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:00:36 +0100 Subject: [PATCH 4/6] Rust: Add source models for io. --- rust/ql/lib/codeql/rust/Concepts.qll | 26 +++++++++++++++++ .../rust/frameworks/stdlib/io.model.yml | 6 ++++ .../dataflow/sources/TaintSources.expected | 14 ++++++++++ .../library-tests/dataflow/sources/test.rs | 28 +++++++++---------- 4 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 10bf4d86998b..544a87e11f18 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -128,6 +128,32 @@ module FileSource { } } +/** + * A data flow source corresponding to standard input. + */ +final class StdInSource = StdInSource::Range; + +/** + * An externally modeled source for data from standard input. + */ +class ModeledStdInSourceSource extends StdInSource::Range { + ModeledStdInSourceSource() { sourceNode(this, "stdin") } +} + +/** + * Provides a class for modeling new sources for standard input. + */ +module StdInSource { + /** + * A data flow source corresponding to standard input. + */ + abstract class Range extends ThreatModelSource::Range { + override string getThreatModel() { result = "stdin" } + + override string getSourceType() { result = "StdInSource" } + } +} + /** * A data flow source corresponding to the program's database reads. */ diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml new file mode 100644 index 000000000000..91eab1cab898 --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/rust-all + extensible: sourceModel + data: + - ["lang:std", "crate::io::stdio::stdin", "ReturnValue", "stdin", "manual"] diff --git a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected index 5f02eb718457..ba7eeae00081 100644 --- a/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected +++ b/rust/ql/test/library-tests/dataflow/sources/TaintSources.expected @@ -28,8 +28,22 @@ | test.rs:221:22:221:25 | path | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:222:27:222:35 | file_name | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:228:22:228:34 | ...::read_link | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:243:22:243:35 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:249:22:249:35 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:255:22:255:35 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:261:9:261:22 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:265:17:265:30 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | | test.rs:271:20:271:38 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:304:50:304:63 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:310:50:310:63 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:317:50:317:63 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:324:50:324:63 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:331:56:331:69 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:338:50:338:63 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:345:50:345:63 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | +| test.rs:351:50:351:63 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | | test.rs:360:25:360:43 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:361:25:361:43 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | | test.rs:369:25:369:43 | ...::open | Flow source 'FileSource' of type file (DEFAULT). | +| test.rs:377:22:377:35 | ...::stdin | Flow source 'StdInSource' of type stdin (DEFAULT). | | test.rs:386:16:386:29 | ...::args | Flow source 'CommandLineArgs' of type commandargs (DEFAULT). | diff --git a/rust/ql/test/library-tests/dataflow/sources/test.rs b/rust/ql/test/library-tests/dataflow/sources/test.rs index ed33e5841287..f6aa96767786 100644 --- a/rust/ql/test/library-tests/dataflow/sources/test.rs +++ b/rust/ql/test/library-tests/dataflow/sources/test.rs @@ -240,29 +240,29 @@ fn test_io_fs() -> std::io::Result<()> { { let mut buffer = [0u8; 100]; - let _bytes = std::io::stdin().read(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + let _bytes = std::io::stdin().read(&mut buffer)?; // $ Alert[rust/summary/taint-sources] sink(&buffer); // $ MISSING: hasTaintFlow } { let mut buffer = Vec::::new(); - let _bytes = std::io::stdin().read_to_end(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + let _bytes = std::io::stdin().read_to_end(&mut buffer)?; // $ Alert[rust/summary/taint-sources] sink(&buffer); // $ MISSING: hasTaintFlow } { let mut buffer = String::new(); - let _bytes = std::io::stdin().read_to_string(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + let _bytes = std::io::stdin().read_to_string(&mut buffer)?; // $ Alert[rust/summary/taint-sources] sink(&buffer); // $ MISSING: hasTaintFlow } { let mut buffer = [0; 100]; - std::io::stdin().read_exact(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + std::io::stdin().read_exact(&mut buffer)?; // $ Alert[rust/summary/taint-sources] sink(&buffer); // $ MISSING: hasTaintFlow } - for byte in std::io::stdin().bytes() { // $ MISSING: Alert[rust/summary/taint-sources] + for byte in std::io::stdin().bytes() { // $ Alert[rust/summary/taint-sources] sink(byte); // $ MISSING: hasTaintFlow } @@ -301,54 +301,54 @@ fn test_io_fs() -> std::io::Result<()> { // --- BufReader --- { - let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] let data = reader.fill_buf()?; sink(&data); // $ MISSING: hasTaintFlow } { - let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] let data = reader.buffer(); sink(&data); // $ MISSING: hasTaintFlow } { let mut buffer = String::new(); - let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] reader.read_line(&mut buffer)?; sink(&buffer); // $ MISSING: hasTaintFlow } { let mut buffer = Vec::::new(); - let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] reader.read_until(b',', &mut buffer)?; sink(&buffer); // $ MISSING: hasTaintFlow } { let mut buffer = Vec::::new(); - let mut reader_split = std::io::BufReader::new(std::io::stdin()).split(b','); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader_split = std::io::BufReader::new(std::io::stdin()).split(b','); // $ Alert[rust/summary/taint-sources] while let Some(chunk) = reader_split.next() { sink(chunk.unwrap()); // $ MISSING: hasTaintFlow } } { - let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] for line in reader.lines() { sink(line); // $ MISSING: Alert[rust/summary/taint-sources] } } { - let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] let line = reader.lines().nth(1).unwrap(); sink(line.unwrap().clone()); // $ MISSING: hasTaintFlow } { - let mut reader = std::io::BufReader::new(std::io::stdin()); // $ MISSING: Alert[rust/summary/taint-sources] + let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] let lines: Vec<_> = reader.lines().collect(); sink(lines[1].as_ref().unwrap().clone()); // $ MISSING: hasTaintFlow } @@ -374,7 +374,7 @@ fn test_io_fs() -> std::io::Result<()> { { let mut buffer = String::new(); - let _bytes = std::io::stdin().lock().read_to_string(&mut buffer)?; // $ MISSING: Alert[rust/summary/taint-sources] + let _bytes = std::io::stdin().lock().read_to_string(&mut buffer)?; // $ Alert[rust/summary/taint-sources] sink(&buffer); // $ MISSING: hasTaintFlow } From 24bcd041b8825ef8b6c1349c11eb36ec7c1ad437 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 11 Apr 2025 19:05:23 +0100 Subject: [PATCH 5/6] Rust: Add flow models for io. --- .../rust/frameworks/stdlib/io.model.yml | 32 +++++++++++++++++ .../library-tests/dataflow/sources/test.rs | 34 +++++++++---------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml b/rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml index 91eab1cab898..3cdbb911b5b8 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/io.model.yml @@ -4,3 +4,35 @@ extensions: extensible: sourceModel data: - ["lang:std", "crate::io::stdio::stdin", "ReturnValue", "stdin", "manual"] + - addsTo: + pack: codeql/rust-all + extensible: summaryModel + data: + - ["lang:std", "::new", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["lang:std", "::fill_buf", "Argument[self]", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "manual"] + - ["lang:std", "::buffer", "Argument[self]", "ReturnValue", "taint", "manual"] + - ["lang:std", "::read", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "crate::io::Read::read", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read_to_string", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read_to_string", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read_to_string", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "crate::io::Read::read_to_string", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", ":::read_to_end", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", ":::read_to_end", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read_to_end", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "crate::io::Read::read_to_end", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read_exact", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read_exact", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "::read_exact", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "crate::io::Read::read_exact", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "crate::io::BufRead::read_line", "Argument[self]", "Argument[0].Reference", "taint", "manual"] + - ["lang:std", "crate::io::BufRead::read_until", "Argument[self]", "Argument[1].Reference", "taint", "manual"] + - ["lang:std", "crate::io::BufRead::split", "Argument[self]", "ReturnValue", "taint", "manual"] + - ["lang:std", "crate::io::BufRead::lines", "Argument[self]", "ReturnValue", "taint", "manual"] + - ["lang:std", "crate::io::Read::bytes", "Argument[self]", "ReturnValue", "taint", "manual"] + - ["lang:std", "crate::io::Read::chain", "Argument[self]", "ReturnValue", "taint", "manual"] + - ["lang:std", "crate::io::Read::chain", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["lang:std", "crate::io::Read::take", "Argument[self]", "ReturnValue", "taint", "manual"] + - ["lang:std", "::lock", "Argument[self]", "ReturnValue", "taint", "manual"] diff --git a/rust/ql/test/library-tests/dataflow/sources/test.rs b/rust/ql/test/library-tests/dataflow/sources/test.rs index f6aa96767786..2ec0b8964ca2 100644 --- a/rust/ql/test/library-tests/dataflow/sources/test.rs +++ b/rust/ql/test/library-tests/dataflow/sources/test.rs @@ -241,7 +241,7 @@ fn test_io_fs() -> std::io::Result<()> { { let mut buffer = [0u8; 100]; let _bytes = std::io::stdin().read(&mut buffer)?; // $ Alert[rust/summary/taint-sources] - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow } { @@ -253,17 +253,17 @@ fn test_io_fs() -> std::io::Result<()> { { let mut buffer = String::new(); let _bytes = std::io::stdin().read_to_string(&mut buffer)?; // $ Alert[rust/summary/taint-sources] - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow } { let mut buffer = [0; 100]; std::io::stdin().read_exact(&mut buffer)?; // $ Alert[rust/summary/taint-sources] - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow } for byte in std::io::stdin().bytes() { // $ Alert[rust/summary/taint-sources] - sink(byte); // $ MISSING: hasTaintFlow + sink(byte); // $ hasTaintFlow } // --- file --- @@ -273,29 +273,29 @@ fn test_io_fs() -> std::io::Result<()> { { let mut buffer = [0u8; 100]; let _bytes = file.read(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow="file.txt" } { let mut buffer = Vec::::new(); let _bytes = file.read_to_end(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow="file.txt" } { let mut buffer = String::new(); let _bytes = file.read_to_string(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow="file.txt" } { let mut buffer = [0; 100]; file.read_exact(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow="file.txt" } for byte in file.bytes() { - sink(byte); // $ MISSING: hasTaintFlow + sink(byte); // $ hasTaintFlow="file.txt" } // --- BufReader --- @@ -303,27 +303,27 @@ fn test_io_fs() -> std::io::Result<()> { { let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] let data = reader.fill_buf()?; - sink(&data); // $ MISSING: hasTaintFlow + sink(&data); // $ hasTaintFlow } { let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] let data = reader.buffer(); - sink(&data); // $ MISSING: hasTaintFlow + sink(&data); // $ hasTaintFlow } { let mut buffer = String::new(); let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] reader.read_line(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow } { let mut buffer = Vec::::new(); let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] reader.read_until(b',', &mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow } { @@ -337,7 +337,7 @@ fn test_io_fs() -> std::io::Result<()> { { let mut reader = std::io::BufReader::new(std::io::stdin()); // $ Alert[rust/summary/taint-sources] for line in reader.lines() { - sink(line); // $ MISSING: Alert[rust/summary/taint-sources] + sink(line); // $ hasTaintFlow } } @@ -361,7 +361,7 @@ fn test_io_fs() -> std::io::Result<()> { let mut file2 = std::fs::File::open("another_file.txt")?; // $ Alert[rust/summary/taint-sources] let mut reader = file1.chain(file2); reader.read_to_string(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow="file.txt" hasTaintFlow="another_file.txt" } { @@ -369,13 +369,13 @@ fn test_io_fs() -> std::io::Result<()> { let mut file1 = std::fs::File::open("file.txt")?; // $ Alert[rust/summary/taint-sources] let mut reader = file1.take(100); reader.read_to_string(&mut buffer)?; - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow="file.txt" } { let mut buffer = String::new(); let _bytes = std::io::stdin().lock().read_to_string(&mut buffer)?; // $ Alert[rust/summary/taint-sources] - sink(&buffer); // $ MISSING: hasTaintFlow + sink(&buffer); // $ hasTaintFlow } Ok(()) From a8b552200a1ca973e7608b44db94359cc551f26f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 14 Apr 2025 15:03:04 +0100 Subject: [PATCH 6/6] Rust: Impact on dataflow/local test. --- .../dataflow/local/DataFlowStep.expected | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index fcd4d2786106..2721ef7092de 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1940,8 +1940,25 @@ storeStep | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:proc_macro::_::::decode | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:proc_macro::_::::decode | | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:proc_macro::_::::decode | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:proc_macro::_::::decode | | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:proc_macro::_::::decode | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:proc_macro::_::::decode | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_:::::read_to_end | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_:::::read_to_end | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_:::::read_to_end | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_:::::read_to_end | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read_exact | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read_exact | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read_to_end | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read_to_end | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read_to_string | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read_to_string | | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::advance_slices | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::advance_slices | | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::advance_slices | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::advance_slices | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read_exact | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read_exact | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read_to_string | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read_to_string | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read_exact | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read_exact | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::::read_to_string | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::::read_to_string | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::crate::io::BufRead::read_line | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::crate::io::BufRead::read_line | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::crate::io::Read::read | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::crate::io::Read::read | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::crate::io::Read::read_exact | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::crate::io::Read::read_exact | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::crate::io::Read::read_to_end | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::crate::io::Read::read_to_end | +| file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:std::_::crate::io::Read::read_to_string | &ref | file://:0:0:0:0 | [post] [summary param] 0 in lang:std::_::crate::io::Read::read_to_string | | file://:0:0:0:0 | [summary] to write: Argument[0].Reference.Reference in lang:proc_macro::_::<&[u8] as crate::bridge::rpc::DecodeMut>::decode | &ref | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:proc_macro::_::<&[u8] as crate::bridge::rpc::DecodeMut>::decode | | file://:0:0:0:0 | [summary] to write: Argument[0].Reference.Reference in lang:proc_macro::_::::decode | &ref | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:proc_macro::_::::decode | | file://:0:0:0:0 | [summary] to write: Argument[0].Reference.Reference in lang:proc_macro::_::::decode | &ref | file://:0:0:0:0 | [summary] to write: Argument[0].Reference in lang:proc_macro::_::::decode | @@ -1957,6 +1974,7 @@ storeStep | file://:0:0:0:0 | [summary] to write: Argument[1].Parameter[0].Reference in lang:core::_::::map_split | &ref | file://:0:0:0:0 | [summary] to write: Argument[1].Parameter[0] in lang:core::_::::map_split | | file://:0:0:0:0 | [summary] to write: Argument[1].Parameter[0].Reference in lang:std::_::::wait_while | &ref | file://:0:0:0:0 | [summary] to write: Argument[1].Parameter[0] in lang:std::_::::wait_while | | file://:0:0:0:0 | [summary] to write: Argument[1].Reference in lang:core::_::<_ as crate::clone::uninit::CopySpec>::clone_one | &ref | file://:0:0:0:0 | [post] [summary param] 1 in lang:core::_::<_ as crate::clone::uninit::CopySpec>::clone_one | +| file://:0:0:0:0 | [summary] to write: Argument[1].Reference in lang:std::_::crate::io::BufRead::read_until | &ref | file://:0:0:0:0 | [post] [summary param] 1 in lang:std::_::crate::io::BufRead::read_until | | file://:0:0:0:0 | [summary] to write: Argument[2].Parameter[0].Reference in lang:core::_::crate::cmp::max_by | &ref | file://:0:0:0:0 | [summary] to write: Argument[2].Parameter[0] in lang:core::_::crate::cmp::max_by | | file://:0:0:0:0 | [summary] to write: Argument[2].Parameter[0].Reference in lang:core::_::crate::cmp::max_by_key | &ref | file://:0:0:0:0 | [summary] to write: Argument[2].Parameter[0] in lang:core::_::crate::cmp::max_by_key | | file://:0:0:0:0 | [summary] to write: Argument[2].Parameter[0].Reference in lang:core::_::crate::cmp::min_by | &ref | file://:0:0:0:0 | [summary] to write: Argument[2].Parameter[0] in lang:core::_::crate::cmp::min_by | @@ -2178,6 +2196,7 @@ storeStep | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:core::_::::or_else | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::or_else | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:core::_::::parse | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:core::_::::parse | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::<&[u8] as crate::io::BufRead>::fill_buf | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::<&[u8] as crate::io::BufRead>::fill_buf | +| file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::::fill_buf | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::fill_buf | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::::canonicalize | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::canonicalize | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::::wait | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::wait | | file://:0:0:0:0 | [summary] to write: ReturnValue.Field[crate::result::Result::Ok(0)] in lang:std::_::::wait_timeout | Ok | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:std::_::::wait_timeout |