Skip to content

Commit afd7d0a

Browse files
committed
jailer: implement UUID validation for the...
id parameter (all 2 formats from RFC are supported). Signed-off-by: Diana Popa <[email protected]>
1 parent a3ac997 commit afd7d0a

File tree

2 files changed

+135
-6
lines changed

2 files changed

+135
-6
lines changed

jailer/src/lib.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extern crate sys_util;
55

66
mod cgroup;
77
mod env;
8+
mod uuid;
89

910
use std::ffi::OsStr;
1011
use std::fs::{canonicalize, metadata};
@@ -15,6 +16,7 @@ use std::path::PathBuf;
1516
use std::result;
1617

1718
use env::Env;
19+
use uuid::validate;
1820

1921
pub const KVM_FD: i32 = 3;
2022
pub const DEV_NET_TUN_FD: i32 = 4;
@@ -51,6 +53,7 @@ pub enum Error {
5153
UnexpectedListenerFd(i32),
5254
UnixListener(io::Error),
5355
UnsetCloexec(sys_util::Error),
56+
ValidateUUID(uuid::UUIDError),
5457
Write(PathBuf, io::Error),
5558
}
5659

@@ -74,12 +77,8 @@ impl<'a> JailerArgs<'a> {
7477
uid: &str,
7578
gid: &str,
7679
) -> Result<Self> {
77-
// Maybe it's a good idea to restrict the id to alphanumeric strings.
78-
for c in id.chars() {
79-
if !c.is_alphanumeric() {
80-
return Err(Error::NotAlphanumeric(id.to_string()));
81-
}
82-
}
80+
// Check that id meets the style of an UUID's.
81+
validate(id).map_err(Error::ValidateUUID)?;
8382

8483
let numa_node = node.parse::<u32>()
8584
.map_err(|_| Error::NumaNode(String::from(node)))?;

jailer/src/uuid.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//! Validate UUIDs.
2+
//! A UUID is an unique number of 128bit. UUIDs are used to assign
3+
//! unique identifiers to entities.
4+
//! Check against 3 formats specified by the RFC: https://tools.ietf.org/html/rfc4122.
5+
//! * simple: 9856BAC1F9CBD6b9d80C712AF75C832A7
6+
//! * hyphenated: 551e7604-e35c-42b3-b825-416853441234
7+
//! * urn: urn:uuid:551e7604-e35c-42b3-b825-416853441234
8+
use std::result;
9+
10+
#[derive(Debug, PartialEq)]
11+
pub enum UUIDError {
12+
InvalidChar(char),
13+
InvalidGroupCount(usize),
14+
InvalidLength(usize),
15+
InvalidGroupLength(u8),
16+
}
17+
18+
type Result<T> = result::Result<T, UUIDError>;
19+
20+
// Length of each of the 5 hyphen delimited groups from the RFC.
21+
const GROUP_LENS: [u8; 5] = [8, 4, 4, 4, 12];
22+
const HYPHEN_FORMAT_GROUP_COUNT: usize = 4;
23+
const HYPHEN_FORMAT_LEN: usize = 36;
24+
const SIMPLE_FORMAT_LEN: usize = 32;
25+
const URN_FORMAT_PREFIX_LEN: usize = 9;
26+
27+
/// Validate a `Uuid` from a string of hexadecimal digits against three of the
28+
/// supported formats.
29+
pub fn validate(mut input: &str) -> Result<()> {
30+
// Check against correct length of each format.
31+
let len = input.len();
32+
if input.starts_with("urn:uuid:") && len == (HYPHEN_FORMAT_LEN + URN_FORMAT_PREFIX_LEN) {
33+
input = &input[9..];
34+
} else if len != SIMPLE_FORMAT_LEN && len != HYPHEN_FORMAT_LEN {
35+
return Err(UUIDError::InvalidLength(len));
36+
}
37+
38+
// Used to count digits from each group.
39+
let mut group_index = 0;
40+
let mut group_count = 0;
41+
42+
// Iterate over index and value of each byte of the input string.
43+
for (index, value) in input.bytes().enumerate() {
44+
// If length is bigger than that of the simple format, check that the
45+
// groups are exactly 4 at this moment.
46+
if index as usize >= SIMPLE_FORMAT_LEN && group_index != HYPHEN_FORMAT_GROUP_COUNT {
47+
return Err(UUIDError::InvalidGroupCount(group_index + 1));
48+
}
49+
// Never let the UUID get more than 5 groups.
50+
if group_index > HYPHEN_FORMAT_GROUP_COUNT {
51+
return Err(UUIDError::InvalidGroupCount(group_index + 1));
52+
}
53+
match value {
54+
b'0'...b'9' => group_count += 1,
55+
b'a'...b'f' => group_count += 1,
56+
b'A'...b'F' => group_count += 1,
57+
// With each hyphen we need to make sure that the
58+
// number of digits from the current group meets the RFC.
59+
b'-' => {
60+
if GROUP_LENS[group_index] != group_count {
61+
return Err(UUIDError::InvalidGroupLength(group_count));
62+
}
63+
group_index += 1;
64+
group_count = 0;
65+
}
66+
_ => {
67+
return Err(UUIDError::InvalidChar(
68+
input[index..].chars().next().unwrap(),
69+
))
70+
}
71+
}
72+
}
73+
if group_index > 0 && GROUP_LENS[group_index] != group_count {
74+
return Err(UUIDError::InvalidGroupLength(group_count));
75+
}
76+
Ok(())
77+
}
78+
79+
#[test]
80+
fn test_uuid_validate() {
81+
use super::*;
82+
83+
// Testing invalid uuids.
84+
assert_eq!(validate(""), Err(UUIDError::InvalidLength(0)));
85+
assert_eq!(validate("a"), Err(UUIDError::InvalidLength(1)));
86+
assert_eq!(
87+
validate("551e7604-CDB3-5fbb-C6ADD-338BD51DB2F5"),
88+
Err(UUIDError::InvalidLength(37))
89+
);
90+
assert_eq!(
91+
validate("551e7604-DFC3A5abbAC7CAA431CA48AB2F3"),
92+
Err(UUIDError::InvalidGroupCount(2))
93+
);
94+
assert_eq!(
95+
validate("551e7604-DFC3-DFC3A5abbAC7CAA431CA48"),
96+
Err(UUIDError::InvalidGroupCount(3))
97+
);
98+
assert_eq!(
99+
validate("551e7604-DFC3-DFC3X5AbbAC7CAA431CA48"),
100+
Err(UUIDError::InvalidChar('X'))
101+
);
102+
103+
assert_eq!(
104+
validate("551e7604-DAF-35ab-fC7CAA43-CA48AB2F5"),
105+
Err(UUIDError::InvalidGroupLength(3))
106+
);
107+
assert_eq!(
108+
validate("01020304-1112-2122-3132-41424344"),
109+
Err(UUIDError::InvalidGroupLength(8))
110+
);
111+
assert_eq!(
112+
validate("67e5604510c1436%9257bca00e6fe1da"),
113+
Err(UUIDError::InvalidChar('%'))
114+
);
115+
assert_eq!(
116+
validate("342342323323534535435434587353276861"),
117+
Err(UUIDError::InvalidGroupCount(1))
118+
);
119+
120+
// Testing valid ones also.
121+
assert!(validate("00000000000000000000000000000000").is_ok());
122+
assert!(validate("68f56045-20c2-437a-8257-bb781e5ae0c9").is_ok());
123+
assert!(validate("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").is_ok());
124+
assert!(validate("67e5504410b1426f9247bb680e5fe0c8").is_ok());
125+
assert!(validate("01020304-1112-2122-3132-414243444546").is_ok());
126+
assert!(validate("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
127+
128+
assert!(validate("00000000000000000000000000000000").is_ok());
129+
assert!(validate("00000000-0000-0000-0000-000000000000").is_ok());
130+
}

0 commit comments

Comments
 (0)