Skip to content

Commit

Permalink
Merge branch 'main' into 256-review-test-cases-for-dos-unexpected-rev…
Browse files Browse the repository at this point in the history
…ert-with-vector
  • Loading branch information
jgcrosta committed Jul 29, 2024
2 parents 5e38ce6 + 02021a0 commit 5ef0cad
Show file tree
Hide file tree
Showing 56 changed files with 323 additions and 210 deletions.
9 changes: 2 additions & 7 deletions .github/workflows/test-detectors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,8 @@ jobs:
key: ${{ runner.os }}-tests-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-tests-

- name: Install Rust nightly and add rust-src
run: |
rustup install nightly-2023-12-16
rustup component add rust-src --toolchain nightly-2023-12-16
- name: Install dylint, dylint-link and cargo-scout-audit
run: cargo +nightly-2023-12-16 install cargo-dylint dylint-link cargo-scout-audit
- name: Install cargo-scout-audit
run: cargo install cargo-scout-audit

- name: Determine build status and write to file
run: echo "${{ job.status }}" > status-${{ matrix.os }}.txt
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ node_modules
!/.vscode/

**/__pycache__/
env/
65 changes: 14 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,61 +14,23 @@ Our interest in this project comes from our experience in manual auditing and vu

## Quick Start

Make sure that [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) is installed on your computer. Then, follow these 5 simple steps:
**Install Scout Audit:**

**1. Install Rust Nightly Toolchain:**

```bash
rustup toolchain install nightly-2023-12-16
```

**2. Set Default Nightly Toolchain:**

```bash
rustup default nightly-2023-12-16
```

**3. Add rust-src Component:**

```bash
rustup component add rust-src --toolchain nightly-2023-12-16
```

**4. Install additional tools required by Scout:**

```bash
cargo install cargo-dylint dylint-link mdbook
```

**5. Install Scout Audit:**
Make sure that [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) is installed on your computer. Then, install Scout with the following command:

```bash
cargo install cargo-scout-audit
```

**6. Run Scout Audit:**
**Run Scout Audit:**

Finally, to run Scout on your project, navigate to the directory of your smart contract and execute the following command:
To run Scout on your project execute the following command:

```bash
cargo scout-audit
```

:warning: Currently Scout doesn't offer full support for workspaces. If you have a workspace, run Scout in each member instead of running it in the workspace `Cargo.toml`.


```
├── your-soroban-project
│ ├── your-smart-contract
│ │ ├── // Run Scout here.
│ │ ├── src
│ │ | ├── contract.rs
│ ├── Cargo.lock
│ ├── Cargo.toml
│ ├── README.md
```

:bulb: Scout supports [Cargo Workspaces](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html). When run on a workspace, Scout will be executed on all packages specified as members of the workspace.

:warning: Make sure that your smart contracts compile properly. Scout won't run if any compilation errors exist.

Expand Down Expand Up @@ -104,24 +66,22 @@ Currently Scout includes the following detectors.

## Output formats

You can choose the output format that best suit your needs (html or markdown). To specify the desired output run the following command:
You can choose the output format that best suit your needs. Scout offers html, markdown, json, pdf and sarif reports. To specify the desired output run the following command:

```
cargo scout-audit --output-format [html|md]
cargo scout-audit --output-format [html|md|pdf|json|sarif]
```

**Example HTML report**
**HTML report**

![Scout HTML report.](/docs/static/img/scout-soroban-html.jpg)
![Scout HTML report.](/docs/static/img/html-report.png)

## Scout VS Code extension

Add Scout to your development workspace with Scout's VS Code extension to run Scout automatically upon saving your file.

![Scout VS Code extension.](/assets/vscode-extension.png)

:warning: To ensure the extension runs properly, make sure that you open the directory containing your smart contract, rather than the entire project. For example, if your smart contracts are located in `myproject/contracts`, and you want to work on the `token` contract while using the Scout VS Code Extension, open `myproject/contracts/token`.

:bulb: Tip: To see the errors highlighted in your code, we recommend installing the [Error Lens Extension](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens).

:point_right: Download Scout VS Code from [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=CoinFabrik.scout-audit).
Expand All @@ -145,10 +105,14 @@ Join us for an exciting series of video tutorials where you'll learn how to inst
- [How to run Scout](https://www.youtube.com/watch?v=_6F24AwscKc)
- [Detecting and fixing issues: Divide before multiply](https://www.youtube.com/watch?v=aLtXyYvw27o)
- [Detecting and fixing issues: Incorrect exponentiation](https://www.youtube.com/watch?v=qjnHwKCD_hM)
- [Detecting and fixing issues: Overflow check](https://www.youtube.com/watch?v=Mi7AcJRPgvU)
- [Detecting and fixing issues: Insufficiently random values](https://www.youtube.com/watch?v=LPBMDPXmczQ)
- [Detecting and fixing issues: DoS - Unexpected revert with vector](https://www.youtube.com/watch?v=H79mMnnWyvA)
- [Detecting and fixing issues: DoS - Unbounded operation](https://www.youtube.com/watch?v=DFM0yNNDiyw)
- [Detecting and fixing issues: Set contract storage](https://www.youtube.com/watch?v=z6RNfhQt6EI)

:clapper: More videos comming soon!


## Tests

To validate our tool, we provide a set of code examples located in the [test-cases](https://github.com/CoinFabrik/scout-soroban/tree/main/test-cases) folder.
Expand Down Expand Up @@ -191,4 +155,3 @@ Our team has an academic background in computer science and mathematics, with wo
## License

Scout is licensed and distributed under a MIT license. [Contact us](https://www.coinfabrik.com/) if you're looking for an exception to the terms.

Binary file added assets/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions detectors/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[workspace]
exclude = [".cargo", "target"]
exclude = [".cargo", "target", ".vscode"]
members = ["*"]
resolver = "2"

[workspace.dependencies]
dylint_linting = { package = "scout-audit-dylint-linting", version = "3.0.1" }
if_chain = "1.0.2"
scout-audit-clippy-utils = { version = "=0.2.3" }
utils = { path = "../utils" }
itertools = { version = "0.12" }
clippy_utils = { git = "https://github.com/rust-lang/rust-clippy", rev = "51a1cf0" }
common = { path = "common" }
dylint_linting = { package = "scout-audit-dylint-linting", git = "https://github.com/CoinFabrik/scout-audit/", rev = "6d6819a" }
if_chain = "=1.0.2"
itertools = { version = "=0.13" }
utils = { path = "../utils" }
2 changes: 1 addition & 1 deletion detectors/assert-violation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version = "0.1.0"
crate-type = ["cdylib"]

[dependencies]
clippy_utils = { workspace = true }
dylint_linting = { workspace = true }
if_chain = { workspace = true }
scout-audit-clippy-utils = { workspace = true }

[package.metadata.rust-analyzer]
rustc_private = true
3 changes: 1 addition & 2 deletions detectors/assert-violation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
extern crate rustc_ast;
extern crate rustc_span;

use clippy_utils::{diagnostics::span_lint_and_help, sym};
use if_chain::if_chain;
use rustc_ast::{
ptr::P,
Expand All @@ -11,7 +12,6 @@ use rustc_ast::{
};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_span::{sym, Span};
use scout_audit_clippy_utils::{diagnostics::span_lint_and_help, sym};

const LINT_MESSAGE: &str = "Assert causes panic. Instead, return a proper error.";

Expand All @@ -20,7 +20,6 @@ dylint_linting::impl_pre_expansion_lint! {
/// Checks for `assert!` usage.
/// ### Why is this bad?
/// `assert!` causes a panic, and panicking it's not a good practice. Instead, use proper error handling.
pub ASSERT_VIOLATION,
Warn,
LINT_MESSAGE,
Expand Down
2 changes: 1 addition & 1 deletion detectors/avoid-core-mem-forget/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version = "0.1.0"
crate-type = ["cdylib"]

[dependencies]
clippy_utils = { workspace = true }
dylint_linting = { workspace = true }
if_chain = { workspace = true }
scout-audit-clippy-utils = { workspace = true }

[package.metadata.rust-analyzer]
rustc_private = true
2 changes: 1 addition & 1 deletion detectors/avoid-core-mem-forget/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
extern crate rustc_ast;
extern crate rustc_span;

use clippy_utils::diagnostics::span_lint_and_help;
use if_chain::if_chain;
use rustc_ast::{Expr, ExprKind, Item, NodeId};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_span::sym;
use scout_audit_clippy_utils::diagnostics::span_lint_and_help;

const LINT_MESSAGE: &str = "Use the `let _ = ...` pattern or `.drop()` method to forget the value";

Expand Down
2 changes: 1 addition & 1 deletion detectors/avoid-panic-error/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version = "0.1.0"
crate-type = ["cdylib"]

[dependencies]
clippy_utils = { workspace = true }
dylint_linting = { workspace = true }
if_chain = { workspace = true }
scout-audit-clippy-utils = { workspace = true }

[package.metadata.rust-analyzer]
rustc_private = true
4 changes: 2 additions & 2 deletions detectors/avoid-panic-error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
extern crate rustc_ast;
extern crate rustc_span;

use clippy_utils::{diagnostics::span_lint_and_help, sym};
use if_chain::if_chain;
use rustc_ast::{
ptr::P,
Expand All @@ -12,7 +13,6 @@ use rustc_ast::{
};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_span::{sym, Span};
use scout_audit_clippy_utils::{diagnostics::span_lint_and_help, sym};

const LINT_MESSAGE: &str = "The panic! macro is used to stop execution when a condition is not met. Even when this does not break the execution of the contract, it is recommended to use Result instead of panic! because it will stop the execution of the caller contract";

Expand Down Expand Up @@ -131,7 +131,7 @@ fn check_macro_call(cx: &EarlyContext, span: Span, mac: &P<MacCall>) {
span,
LINT_MESSAGE,
None,
&format!("You could use instead an Error enum and then 'return Err(Error::{})'", capitalize_err_msg(lit.symbol.as_str()).replace(' ', ""))
format!("You could use instead an Error enum and then 'return Err(Error::{})'", capitalize_err_msg(lit.symbol.as_str()).replace(' ', ""))
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion detectors/avoid-unsafe-block/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version = "0.1.0"
crate-type = ["cdylib"]

[dependencies]
clippy_utils = { workspace = true }
dylint_linting = { workspace = true }
if_chain = { workspace = true }
scout-audit-clippy-utils = { workspace = true }

[package.metadata.rust-analyzer]
rustc_private = true
2 changes: 1 addition & 1 deletion detectors/avoid-unsafe-block/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
extern crate rustc_hir;
extern crate rustc_span;

use clippy_utils::diagnostics::span_lint;
use rustc_hir::{
def_id::LocalDefId,
intravisit::{walk_expr, FnKind, Visitor},
BlockCheckMode, Body, Expr, ExprKind, FnDecl, UnsafeSource,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_span::Span;
use scout_audit_clippy_utils::diagnostics::span_lint;

const LINT_MESSAGE: &str = "Avoid using unsafe blocks as it may lead to undefined behavior";

Expand Down
2 changes: 1 addition & 1 deletion detectors/divide-before-multiply/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version = "0.1.0"
crate-type = ["cdylib"]

[dependencies]
clippy_utils = { workspace = true }
dylint_linting = { workspace = true }
if_chain = { workspace = true }
scout-audit-clippy-utils = { workspace = true }

[package.metadata.rust-analyzer]
rustc_private = true
31 changes: 15 additions & 16 deletions detectors/divide-before-multiply/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern crate rustc_span;

use std::collections::HashSet;

use clippy_utils::diagnostics::span_lint_and_help;
use if_chain::if_chain;
use rustc_hir::{
intravisit::{walk_expr, FnKind, Visitor},
Expand All @@ -24,7 +25,6 @@ use rustc_span::{
def_id::{DefId, LocalDefId},
Span,
};
use scout_audit_clippy_utils::diagnostics::span_lint_and_help;

const LINT_MESSAGE: &str = "Division before multiplication might result in a loss of precision";

Expand Down Expand Up @@ -173,7 +173,7 @@ fn navigate_trough_basicblocks<'tcx>(
Rvalue::Use(operand) => {
check_operand(operand, tainted_places, &assign.0);
}
Rvalue::BinaryOp(op, operands) | Rvalue::CheckedBinaryOp(op, operands) => {
Rvalue::BinaryOp(op, operands) => {
if BinOp::Div == *op {
tainted_places.push(assign.0);
} else if BinOp::Mul == *op
Expand Down Expand Up @@ -208,9 +208,9 @@ fn navigate_trough_basicblocks<'tcx>(
tainted_places.push(*destination);
} else {
for arg in args {
match arg {
match arg.node {
Operand::Copy(place) | Operand::Move(place) => {
if tainted_places.contains(place) {
if tainted_places.contains(&place) {
tainted_places.push(*destination);

if def_ids.checked_mul.is_some_and(|f| f == *id)
Expand Down Expand Up @@ -311,18 +311,17 @@ fn navigate_trough_basicblocks<'tcx>(
spans,
);
}
TerminatorKind::InlineAsm {
destination: Some(dest),
..
} => {
navigate_trough_basicblocks(
*dest,
bbs,
def_ids,
tainted_places,
visited_bbs,
spans,
);
TerminatorKind::InlineAsm { targets, .. } => {
targets.iter().for_each(|target| {
navigate_trough_basicblocks(
*target,
bbs,
def_ids,
tainted_places,
visited_bbs,
spans,
);
});
}

_ => {}
Expand Down
2 changes: 1 addition & 1 deletion detectors/dos-unbounded-operation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version = "0.1.0"
crate-type = ["cdylib"]

[dependencies]
clippy_utils = { workspace = true }
dylint_linting = { workspace = true }
if_chain = { workspace = true }
scout-audit-clippy-utils = { workspace = true }

[package.metadata.rust-analyzer]
rustc_private = true
4 changes: 2 additions & 2 deletions detectors/dos-unbounded-operation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
extern crate rustc_hir;
extern crate rustc_span;

use clippy_utils::diagnostics::span_lint_and_help;
use if_chain::if_chain;
use rustc_hir::{
def::{DefKind, Res},
Expand All @@ -12,7 +13,6 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_span::{def_id::LocalDefId, Span};
use scout_audit_clippy_utils::diagnostics::span_lint_and_help;

const LINT_MESSAGE: &str = "In order to prevent a single transaction from consuming all the gas in a block, unbounded operations must be avoided";

Expand Down Expand Up @@ -84,7 +84,7 @@ impl<'tcx> Visitor<'tcx> for ForLoopVisitor {
// Constant detection
if let ExprKind::Block(a, _) = expr.kind {
a.stmts.iter().for_each(|func| {
if let StmtKind::Local(sd) = func.kind {
if let StmtKind::Let(sd) = func.kind {
if sd.init.is_some() && self.is_expr_constant(sd.init.as_ref().unwrap()) {
self.constants.push(sd.pat.hir_id);
}
Expand Down
Loading

0 comments on commit 5ef0cad

Please sign in to comment.