Skip to content

Commit 9e8735f

Browse files
authored
Merge pull request #20878 from paldepind/rust/axum-model
Rust: Add models for Axum
2 parents 47e375f + 420dd9a commit 9e8735f

File tree

9 files changed

+352
-202
lines changed

9 files changed

+352
-202
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added models for the Axum web application framework.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
extensions:
2+
- addsTo:
3+
pack: codeql/rust-all
4+
extensible: sourceModel
5+
data:
6+
# Get
7+
- ["axum::routing::method_routing::get", "Argument[0].Parameter[0..7]", "remote", "manual"]
8+
- ["<axum::routing::method_routing::MethodRouter>::get", "Argument[0].Parameter[0..7]", "remote", "manual"]
9+
# Post
10+
- ["axum::routing::method_routing::post", "Argument[0].Parameter[0..7]", "remote", "manual"]
11+
- ["<axum::routing::method_routing::MethodRouter>::post", "Argument[0].Parameter[0..7]", "remote", "manual"]
12+
# Put
13+
- ["axum::routing::method_routing::put", "Argument[0].Parameter[0..7]", "remote", "manual"]
14+
- ["<axum::routing::method_routing::MethodRouter>::put", "Argument[0].Parameter[0..7]", "remote", "manual"]
15+
# Delete
16+
- ["axum::routing::method_routing::delete", "Argument[0].Parameter[0..7]", "remote", "manual"]
17+
- ["<axum::routing::method_routing::MethodRouter>::delete", "Argument[0].Parameter[0..7]", "remote", "manual"]
18+
# Patch
19+
- ["axum::routing::method_routing::patch", "Argument[0].Parameter[0..7]", "remote", "manual"]
20+
- ["<axum::routing::method_routing::MethodRouter>::patch", "Argument[0].Parameter[0..7]", "remote", "manual"]
21+
# on
22+
- ["axum::routing::method_routing::on", "Argument[1].Parameter[0..7]", "remote", "manual"]
23+
- ["<axum::routing::method_routing::MethodRouter>::on", "Argument[1].Parameter[0..7]", "remote", "manual"]

rust/ql/lib/codeql/rust/security/XssExtensions.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,14 @@ module Xss {
5959
)
6060
}
6161
}
62+
63+
// TODO: Convert this to MaD once MaD supports sink for tuple struct expressions.
64+
private class AxumHtmlSink extends Sink {
65+
AxumHtmlSink() {
66+
exists(TupleStructExpr call |
67+
call.getResolvedTarget().getCanonicalPath() = "axum::response::Html" and
68+
this.asExpr() = call.getSyntacticPositionalArgument(0)
69+
)
70+
}
71+
}
6272
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
nonUniqueCertainType
2-
| test.rs:139:30:139:39 | ...::get(...) | |
3-
| test.rs:140:34:140:43 | ...::get(...) | |
4-
| test.rs:141:30:141:39 | ...::get(...) | |
2+
| test.rs:131:30:131:39 | ...::get(...) | |
3+
| test.rs:132:34:132:43 | ...::get(...) | |
4+
| test.rs:133:30:133:39 | ...::get(...) | |

rust/ql/test/library-tests/dataflow/sources/web_frameworks/InlineFlow.expected

Lines changed: 140 additions & 83 deletions
Large diffs are not rendered by default.

rust/ql/test/library-tests/dataflow/sources/web_frameworks/TaintSources.expected

Lines changed: 120 additions & 64 deletions
Large diffs are not rendered by default.

rust/ql/test/library-tests/dataflow/sources/web_frameworks/test.rs

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,7 @@ mod actix_test {
9494
use super::sink;
9595
use actix_web::{get, web, App};
9696

97-
async fn my_actix_handler_1(
98-
path: web::Path<String>,
99-
) -> String {
97+
async fn my_actix_handler_1(path: web::Path<String>) -> String {
10098
let a = path.into_inner();
10199
sink(a.as_str()); // $ hasTaintFlow=my_actix_handler_1
102100
sink(a.as_bytes()); // $ hasTaintFlow=my_actix_handler_1
@@ -105,9 +103,7 @@ mod actix_test {
105103
"".to_string()
106104
}
107105

108-
async fn my_actix_handler_2(
109-
path: web::Path<(String, String)>,
110-
) -> String {
106+
async fn my_actix_handler_2(path: web::Path<(String, String)>) -> String {
111107
let (a, b) = path.into_inner();
112108

113109
sink(a); // $ hasTaintFlow=my_actix_handler_2
@@ -116,18 +112,14 @@ mod actix_test {
116112
"".to_string()
117113
}
118114

119-
async fn my_actix_handler_3(
120-
web::Query(a): web::Query<String>,
121-
) -> String {
115+
async fn my_actix_handler_3(web::Query(a): web::Query<String>) -> String {
122116
sink(a); // $ hasTaintFlow=my_actix_handler_3
123117

124118
"".to_string()
125119
}
126120

127121
#[get("/4/{a}")] // $ Alert[rust/summary/taint-sources]
128-
async fn my_actix_handler_4(
129-
path: web::Path<String>,
130-
) -> String {
122+
async fn my_actix_handler_4(path: web::Path<String>) -> String {
131123
let a = path.into_inner();
132124
sink(a); // $ hasTaintFlow=my_actix_handler_4
133125

@@ -148,83 +140,71 @@ mod actix_test {
148140
mod axum_test {
149141
use super::sink;
150142
use axum::extract::{Json, Path, Query, Request};
151-
use axum::routing::get;
143+
use axum::routing::{get, post, put, MethodFilter};
152144
use axum::Router;
153145
use std::collections::HashMap;
154146

155-
async fn my_axum_handler_1(
156-
Path(a): Path<String>, // $ MISSING: Alert[rust/summary/taint-sources]
157-
) -> &'static str {
158-
sink(a.as_str()); // $ MISSING: hasTaintFlow
159-
sink(a.as_bytes()); // $ MISSING: hasTaintFlow
160-
sink(a); // $ MISSING: hasTaintFlow
147+
async fn my_axum_handler_1(Path(a): Path<String>) -> &'static str {
148+
sink(a.as_str()); // $ hasTaintFlow=my_axum_handler_1
149+
sink(a.as_bytes()); // $ hasTaintFlow=my_axum_handler_1
150+
sink(a); // $ hasTaintFlow=my_axum_handler_1
161151

162152
""
163153
}
164154

165-
async fn my_axum_handler_2(
166-
Path((a, b)): Path<(String, String)>, // $ MISSING: Alert[rust/summary/taint-sources]
167-
) -> &'static str {
168-
sink(a); // $ MISSING: hasTaintFlow
169-
sink(b); // $ MISSING: hasTaintFlow
155+
async fn my_axum_handler_2(Path((a, b)): Path<(String, String)>) -> &'static str {
156+
sink(a); // $ hasTaintFlow=my_axum_handler_2
157+
sink(b); // $ hasTaintFlow=my_axum_handler_2
170158

171159
""
172160
}
173161

174-
async fn my_axum_handler_3(
175-
Query(params): Query<HashMap<String, String>>, // $ MISSING: Alert[rust/summary/taint-sources]
176-
) -> &'static str {
162+
async fn my_axum_handler_3(Query(params): Query<HashMap<String, String>>) -> &'static str {
177163
for (key, value) in params {
178-
sink(key); // $ MISSING: hasTaintFlow
179-
sink(value); // $ MISSING: hasTaintFlow
164+
sink(key); // $ hasTaintFlow=my_axum_handler_3
165+
sink(value); // $ hasTaintFlow=my_axum_handler_3
180166
}
181167

182168
""
183169
}
184170

185-
async fn my_axum_handler_4(
186-
request: Request, // $ MISSING: Alert[rust/summary/taint-sources]
187-
) -> &'static str {
171+
async fn my_axum_handler_4(request: Request) -> &'static str {
188172
sink(request.body()); // $ MISSING: hasTaintFlow
189173
request.headers().get("header").unwrap(); // $ MISSING: hasTaintFlow
190174
sink(request.into_body()); // $ MISSING: hasTaintFlow
191175

192176
""
193177
}
194178

195-
async fn my_axum_handler_5(
196-
Json(payload): Json<serde_json::Value>, // $ MISSING: Alert[rust/summary/taint-sources]
197-
) -> &'static str {
179+
async fn my_axum_handler_5(Json(payload): Json<serde_json::Value>) -> &'static str {
198180
sink(payload.as_str()); // $ MISSING: hasTaintFlow
199-
sink(payload); // $ MISSING: hasTaintFlow
181+
sink(payload); // $ hasTaintFlow=...::DELETE
200182

201183
""
202184
}
203185

204-
async fn my_axum_handler_6(
205-
body: String, // $ MISSING: Alert[rust/summary/taint-sources]
206-
) -> &'static str {
207-
sink(body); // $ MISSING: hasTaintFlow
186+
async fn my_axum_handler_6(body: String) -> &'static str {
187+
sink(body); // $ hasTaintFlow=my_axum_handler_6
208188

209189
""
210190
}
211191

212-
async fn my_axum_handler_7(
213-
body: String, // $ MISSING: Alert[rust/summary/taint-sources]
214-
) -> &'static str {
215-
sink(body); // $ MISSING: hasTaintFlow
192+
async fn my_axum_handler_7(body: String) -> &'static str {
193+
sink(body); // $ hasTaintFlow=my_axum_handler_7
216194

217195
""
218196
}
219197

220198
async fn test_axum() {
221199
let app = Router::<()>::new()
222-
.route("/1/{a}", get(my_axum_handler_1))
223-
.route("/2/{a}/{b}", get(my_axum_handler_2))
224-
.route("/3/:a", get(my_axum_handler_3))
225-
.route("/4/:a", get(my_axum_handler_4))
226-
.route("/5/:a", get(my_axum_handler_5))
227-
.route("/67/:a", get(my_axum_handler_6).get(my_axum_handler_7));
200+
.route("/1/{a}", get(my_axum_handler_1)) // $ Alert[rust/summary/taint-sources])
201+
.route("/2/{a}/{b}", post(my_axum_handler_2)) // $ Alert[rust/summary/taint-sources])
202+
.route("/3/:a", put(my_axum_handler_3)) // $ Alert[rust/summary/taint-sources])
203+
.route(
204+
"/4/:a",
205+
get(my_axum_handler_4).on(MethodFilter::DELETE, my_axum_handler_5), // $ Alert[rust/summary/taint-sources])
206+
)
207+
.route("/5/:a", get(my_axum_handler_6).get(my_axum_handler_7)); // $ Alert[rust/summary/taint-sources])
228208

229209
// ...
230210
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
11
#select
2+
| main.rs:10:10:10:21 | html_content | main.rs:15:51:15:53 | get | main.rs:10:10:10:21 | html_content | Cross-site scripting vulnerability due to a $@. | main.rs:15:51:15:53 | get | user-provided value |
23
edges
4+
| main.rs:8:24:8:59 | ...: Query::<...> | main.rs:9:32:9:63 | MacroExpr | provenance | |
5+
| main.rs:9:9:9:20 | html_content | main.rs:10:10:10:21 | html_content | provenance | |
6+
| main.rs:9:32:9:63 | ...::format(...) | main.rs:9:32:9:63 | { ... } | provenance | |
7+
| main.rs:9:32:9:63 | ...::must_use(...) | main.rs:9:9:9:20 | html_content | provenance | |
8+
| main.rs:9:32:9:63 | MacroExpr | main.rs:9:32:9:63 | ...::format(...) | provenance | MaD:2 |
9+
| main.rs:9:32:9:63 | { ... } | main.rs:9:32:9:63 | ...::must_use(...) | provenance | MaD:3 |
10+
| main.rs:15:51:15:53 | get | main.rs:8:24:8:59 | ...: Query::<...> | provenance | Src:MaD:1 |
11+
models
12+
| 1 | Source: axum::routing::method_routing::get; Argument[0].Parameter[0..7]; remote |
13+
| 2 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
14+
| 3 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
315
nodes
16+
| main.rs:8:24:8:59 | ...: Query::<...> | semmle.label | ...: Query::<...> |
17+
| main.rs:9:9:9:20 | html_content | semmle.label | html_content |
18+
| main.rs:9:32:9:63 | ...::format(...) | semmle.label | ...::format(...) |
19+
| main.rs:9:32:9:63 | ...::must_use(...) | semmle.label | ...::must_use(...) |
20+
| main.rs:9:32:9:63 | MacroExpr | semmle.label | MacroExpr |
21+
| main.rs:9:32:9:63 | { ... } | semmle.label | { ... } |
22+
| main.rs:10:10:10:21 | html_content | semmle.label | html_content |
23+
| main.rs:15:51:15:53 | get | semmle.label | get |
424
subpaths

rust/ql/test/query-tests/security/CWE-079/axum/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ struct GreetingParams {
77

88
async fn greet_handler(Query(params): Query<GreetingParams>) -> Html<String> {
99
let html_content = format!("<p>Hello, {}!</p>", params.name);
10-
Html(html_content) // $ MISSING: Alert[rust/xss]
10+
Html(html_content) // $ Alert[rust/xss]=greet
1111
}
1212

1313
#[tokio::main]
1414
pub async fn main() {
15-
let app = Router::<()>::new().route("/greet", get(greet_handler));
15+
let app = Router::<()>::new().route("/greet", get(greet_handler)); // $ Source=greet
1616
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
1717
.await
1818
.unwrap();

0 commit comments

Comments
 (0)