gardesk/garwarp / 94095a9

Browse files

limit control request size

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
94095a97be70e4083c7be23324de6b85e6610682
Parents
4b69bf1
Tree
9ac97e0

1 changed file

StatusFile+-
M garwarp/src/daemon.rs 51 3
garwarp/src/daemon.rsmodified
@@ -1,5 +1,5 @@
11
 use std::fs;
2
-use std::io::{self, BufRead, BufReader, Write};
2
+use std::io::{self, BufRead, BufReader, Read, Write};
33
 use std::os::unix::net::{UnixListener, UnixStream};
44
 use std::thread;
55
 use std::time::{Duration, Instant};
@@ -19,6 +19,8 @@ use crate::runtime::RuntimePaths;
1919
 use crate::validate::{validate_request_id, validate_request_identity};
2020
 use crate::window::parse_optional_parent_window;
2121
 
22
+const MAX_CONTROL_LINE_BYTES: usize = 4096;
23
+
2224
 pub fn run() -> io::Result<()> {
2325
     let config = Config::from_env();
2426
     let paths = RuntimePaths::from_env();
@@ -110,7 +112,21 @@ struct DaemonState {
110112
 fn handle_connection(stream: UnixStream, state: &mut DaemonState) -> io::Result<()> {
111113
     let mut reader = BufReader::new(stream);
112114
     let mut line = String::new();
113
-    reader.read_line(&mut line)?;
115
+    let bytes_read = {
116
+        let mut limited = reader.by_ref().take((MAX_CONTROL_LINE_BYTES + 1) as u64);
117
+        limited.read_line(&mut line)?
118
+    };
119
+
120
+    if bytes_read > MAX_CONTROL_LINE_BYTES {
121
+        let mapping = map_portal_error(&PortalError::InvalidRequestPayload);
122
+        return write_response(
123
+            reader.into_inner(),
124
+            ControlResponse::Error {
125
+                code: mapping.code as u32,
126
+                reason: mapping.reason.to_string(),
127
+            },
128
+        );
129
+    }
114130
 
115131
     let response = match ControlRequest::parse_line(&line) {
116132
         Some(ControlRequest::Status) => ControlResponse::Status(StatusResponse {
@@ -329,7 +345,9 @@ fn persist_registry_state(path: &std::path::Path, registry: &RequestRegistry) {
329345
 
330346
 #[cfg(test)]
331347
 mod tests {
332
-    use super::{DaemonState, handle_connection, load_registry_with_recovery};
348
+    use super::{
349
+        DaemonState, MAX_CONTROL_LINE_BYTES, handle_connection, load_registry_with_recovery,
350
+    };
333351
     use garwarp_ipc::{ControlResponse, HealthStatus};
334352
     use std::fs;
335353
     use std::io::{BufRead, BufReader, Write};
@@ -499,6 +517,36 @@ mod tests {
499517
         );
500518
     }
501519
 
520
+    #[test]
521
+    fn oversized_request_maps_to_invalid_request() {
522
+        let (mut client, server) = UnixStream::pair().expect("pair should be created");
523
+        let oversized = format!("{}\n", "x".repeat(MAX_CONTROL_LINE_BYTES + 1));
524
+        client
525
+            .write_all(oversized.as_bytes())
526
+            .expect("oversized request should be written");
527
+
528
+        let mut state = DaemonState {
529
+            health: HealthStatus::Healthy,
530
+            requests: RequestRegistry::new(Duration::from_secs(5)),
531
+            running: true,
532
+        };
533
+        handle_connection(server, &mut state).expect("request should be handled");
534
+
535
+        let mut response_line = String::new();
536
+        let mut reader = BufReader::new(client);
537
+        reader
538
+            .read_line(&mut response_line)
539
+            .expect("response should be readable");
540
+        let response = ControlResponse::parse_line(&response_line).expect("response should parse");
541
+        assert_eq!(
542
+            response,
543
+            ControlResponse::Error {
544
+                code: 2,
545
+                reason: "invalid_request".to_string(),
546
+            }
547
+        );
548
+    }
549
+
502550
     #[test]
503551
     fn duplicate_request_fields_map_to_invalid_request() {
504552
         let (mut client, server) = UnixStream::pair().expect("pair should be created");