}
pub fn process_write_record<'b>(&mut self, r: &RpcPacket<'b>, w: &Nfs3RequestWrite<'b>) -> u32 {
- // for now assume that stable FILE_SYNC flags means a single chunk
- let is_last = if w.stable == 2 { true } else { false };
-
let mut fill_bytes = 0;
- let pad = w.file_len % 4;
+ let pad = w.count % 4;
if pad != 0 {
fill_bytes = 4 - pad;
}
+ // linux defines a max of 1mb. Allow several multiples.
+ if w.count == 0 || w.count > 16777216 {
+ return 0;
+ }
+
+ // for now assume that stable FILE_SYNC flags means a single chunk
+ let is_last = if w.stable == 2 { true } else { false };
let file_handle = w.handle.value.to_vec();
let file_name = match self.namemap.get(w.handle.value) {
Some(n) => {
}
if !self.is_udp {
self.ts_chunk_xid = r.hdr.xid;
- let file_data_len = w.file_data.len() as u32 - fill_bytes as u32;
- self.ts_chunk_left = w.file_len as u32 - file_data_len as u32;
+ //debug_validate_bug_on!(w.file_data.len() as u32 > w.count);
+ self.ts_chunk_left = w.count - w.file_data.len() as u32;
self.ts_chunk_fh = file_handle;
SCLogDebug!("REQUEST chunk_xid {:04X} chunk_left {}", self.ts_chunk_xid, self.ts_chunk_left);
}
// lets try to parse the RPC record. Might fail with Incomplete.
match parse_rpc(cur_i) {
Ok((remaining, ref rpc_record)) => {
- match parse_nfs3_request_write(rpc_record.prog_data) {
+ match parse_nfs3_request_write(rpc_record.prog_data, false) {
Ok((_, ref nfs_request_write)) => {
// deal with the partial nfs write data
status |= self.process_partial_write_request_record(rpc_record, nfs_request_write);
},
};
} else if r.procedure == NFSPROC3_WRITE {
- match parse_nfs3_request_write(r.prog_data) {
+ match parse_nfs3_request_write(r.prog_data, true) {
Ok((_, w)) => {
self.process_write_record(r, &w);
},
//! Nom parsers for RPC & NFSv3
+use std::cmp;
use nom::{IResult, be_u32, be_u64, rest};
use crate::nfs::nfs_records::*;
pub file_data: &'a[u8],
}
-named!(pub parse_nfs3_request_write<Nfs3RequestWrite>,
- do_parse!(
- handle: parse_nfs3_handle
- >> offset: be_u64
- >> count: be_u32
- >> stable: verify!(be_u32, |v| v <= 2)
- >> file_len: verify!(be_u32, |v| v <= count)
- >> file_data: rest // likely partial
- >> (
- Nfs3RequestWrite {
- handle:handle,
- offset:offset,
- count:count,
- stable:stable,
- file_len:file_len,
- file_data:file_data,
- }
- ))
-);
+/// Complete data expected
+fn parse_nfs3_request_write_data_complete(i: &[u8], file_len: usize, fill_bytes: usize) -> IResult<&[u8], &[u8]> {
+ let (i, file_data) = take!(i, file_len as usize)?;
+ let (i, _) = cond!(i, fill_bytes > 0, take!(fill_bytes))?;
+ Ok((i, file_data))
+}
+
+/// Partial data. We have all file_len, but need to consider fill_bytes
+fn parse_nfs3_request_write_data_partial(i: &[u8], file_len: usize, fill_bytes: usize) -> IResult<&[u8], &[u8]> {
+ let (i, file_data) = take!(i, file_len as usize)?;
+ let fill_bytes = cmp::min(fill_bytes as usize, i.len());
+ let (i, _) = cond!(i, fill_bytes > 0, take!(fill_bytes))?;
+ Ok((i, file_data))
+}
+
+pub fn parse_nfs3_request_write(i: &[u8], complete: bool) -> IResult<&[u8], Nfs3RequestWrite> {
+ let (i, handle) = parse_nfs3_handle(i)?;
+ let (i, offset) = be_u64(i)?;
+ let (i, count) = be_u32(i)?;
+ let (i, stable) = verify!(i, be_u32, |v| v <= 2)?;
+ let (i, file_len) = verify!(i, be_u32, |v| v <= count)?;
+ let fill_bytes = if file_len % 4 != 0 { 4 - file_len % 4 } else { 0 };
+ let (i, file_data) = if complete {
+ parse_nfs3_request_write_data_complete(i, file_len as usize, fill_bytes as usize)?
+ } else if i.len() >= file_len as usize {
+ parse_nfs3_request_write_data_partial(i, file_len as usize, fill_bytes as usize)?
+ } else {
+ rest(i)?
+ };
+ Ok((i, Nfs3RequestWrite {
+ handle,
+ offset,
+ count,
+ stable,
+ file_len,
+ file_data,
+ }))
+}
+
/*
#[derive(Debug,PartialEq)]
pub struct Nfs3ReplyRead<'a> {
//! Nom parsers for RPCv2
use nom::{be_u32, rest};
+use nom::IResult;
pub const RPC_MAX_MACHINE_SIZE: u32 = 256; // Linux kernel defines 64.
pub const RPC_MAX_CREDS_SIZE: u32 = 4096; // Linux kernel defines 400.
pub prog_data: &'a[u8],
}
-named!(pub parse_rpc<RpcPacket>,
- do_parse!(
- hdr: parse_rpc_packet_header
-
- >> rpcver: be_u32
- >> program: be_u32
- >> progver: be_u32
- >> procedure: be_u32
-
- >> creds_flavor: be_u32
- >> creds_len: verify!(be_u32, |size| size < RPC_MAX_CREDS_SIZE)
- >> creds: flat_map!(take!(creds_len), switch!(value!(creds_flavor),
- 1 => call!(parse_rpc_request_creds_unix) |
- 6 => call!(parse_rpc_request_creds_gssapi) |
- _ => call!(parse_rpc_request_creds_unknown) ))
-
- >> verifier_flavor: be_u32
- >> verifier_len: verify!(be_u32, |size| size < RPC_MAX_VERIFIER_SIZE)
- >> verifier: take!(verifier_len as usize)
-
- >> pl: rest
-
- >> (
- RpcPacket {
- hdr:hdr,
-
- rpcver:rpcver,
- program:program,
- progver:progver,
- procedure:procedure,
-
- creds_flavor:creds_flavor,
- creds:creds,
-
- verifier_flavor:verifier_flavor,
- verifier_len:verifier_len,
- verifier:verifier,
+pub fn parse_rpc(start_i: &[u8]) -> IResult<&[u8], RpcPacket> {
+ let (i, hdr) = parse_rpc_packet_header(start_i)?;
+ let rec_size = hdr.frag_len as usize + 4;
+
+ let (i, rpcver) = be_u32(i)?;
+ let (i, program) = be_u32(i)?;
+ let (i, progver) = be_u32(i)?;
+ let (i, procedure) = be_u32(i)?;
+
+ let (i, creds_flavor) = be_u32(i)?;
+ let (i, creds_len) = verify!(i, be_u32, |size| size < RPC_MAX_CREDS_SIZE)?;
+ let (i, creds) = flat_map!(i, take!(creds_len), switch!(value!(creds_flavor),
+ 1 => call!(parse_rpc_request_creds_unix) |
+ 6 => call!(parse_rpc_request_creds_gssapi) |
+ _ => call!(parse_rpc_request_creds_unknown) ))?;
+
+ let (i, verifier_flavor) = be_u32(i)?;
+ let (i, verifier_len) = verify!(i, be_u32, |size| size < RPC_MAX_VERIFIER_SIZE)?;
+ let (i, verifier) = take!(i, verifier_len as usize)?;
+
+ let consumed = start_i.len() - i.len();
+ if consumed > rec_size as usize {
+ return Err(nom::Err::Error(error_position!(i, nom::ErrorKind::LengthValue)));
+ }
- prog_data:pl,
- }
- ))
-);
+ let (i, prog_data) = rest(i)?;
+
+ Ok((i, RpcPacket {
+ hdr,
+ rpcver,
+ program,
+ progver,
+ procedure,
+ creds_flavor,
+ creds,
+ verifier_flavor,
+ verifier_len,
+ verifier,
+ prog_data,
+ }))
+}
// to be called with data <= hdr.frag_len + 4. Sending more data is undefined.
named!(pub parse_rpc_reply<RpcReplyPacket>,