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 @@
1
 use std::fs;
1
 use std::fs;
2
-use std::io::{self, BufRead, BufReader, Write};
2
+use std::io::{self, BufRead, BufReader, Read, Write};
3
 use std::os::unix::net::{UnixListener, UnixStream};
3
 use std::os::unix::net::{UnixListener, UnixStream};
4
 use std::thread;
4
 use std::thread;
5
 use std::time::{Duration, Instant};
5
 use std::time::{Duration, Instant};
@@ -19,6 +19,8 @@ use crate::runtime::RuntimePaths;
19
 use crate::validate::{validate_request_id, validate_request_identity};
19
 use crate::validate::{validate_request_id, validate_request_identity};
20
 use crate::window::parse_optional_parent_window;
20
 use crate::window::parse_optional_parent_window;
21
 
21
 
22
+const MAX_CONTROL_LINE_BYTES: usize = 4096;
23
+
22
 pub fn run() -> io::Result<()> {
24
 pub fn run() -> io::Result<()> {
23
     let config = Config::from_env();
25
     let config = Config::from_env();
24
     let paths = RuntimePaths::from_env();
26
     let paths = RuntimePaths::from_env();
@@ -110,7 +112,21 @@ struct DaemonState {
110
 fn handle_connection(stream: UnixStream, state: &mut DaemonState) -> io::Result<()> {
112
 fn handle_connection(stream: UnixStream, state: &mut DaemonState) -> io::Result<()> {
111
     let mut reader = BufReader::new(stream);
113
     let mut reader = BufReader::new(stream);
112
     let mut line = String::new();
114
     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
+    }
114
 
130
 
115
     let response = match ControlRequest::parse_line(&line) {
131
     let response = match ControlRequest::parse_line(&line) {
116
         Some(ControlRequest::Status) => ControlResponse::Status(StatusResponse {
132
         Some(ControlRequest::Status) => ControlResponse::Status(StatusResponse {
@@ -329,7 +345,9 @@ fn persist_registry_state(path: &std::path::Path, registry: &RequestRegistry) {
329
 
345
 
330
 #[cfg(test)]
346
 #[cfg(test)]
331
 mod tests {
347
 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
+    };
333
     use garwarp_ipc::{ControlResponse, HealthStatus};
351
     use garwarp_ipc::{ControlResponse, HealthStatus};
334
     use std::fs;
352
     use std::fs;
335
     use std::io::{BufRead, BufReader, Write};
353
     use std::io::{BufRead, BufReader, Write};
@@ -499,6 +517,36 @@ mod tests {
499
         );
517
         );
500
     }
518
     }
501
 
519
 
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
+
502
     #[test]
550
     #[test]
503
     fn duplicate_request_fields_map_to_invalid_request() {
551
     fn duplicate_request_fields_map_to_invalid_request() {
504
         let (mut client, server) = UnixStream::pair().expect("pair should be created");
552
         let (mut client, server) = UnixStream::pair().expect("pair should be created");