Skip to content

Commit 0487b0b

Browse files
authored
Merge pull request #33 from mathstuf/port-keyutils-tests-add
Port keyutils tests add
2 parents cbd4ba8 + 3ff0ff4 commit 0487b0b

File tree

7 files changed

+416
-0
lines changed

7 files changed

+416
-0
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ edition = "2018"
1313
[workspace]
1414
members = ["keyutils-raw"]
1515

16+
[dev-dependencies]
17+
lazy_static = "1"
18+
regex = "1"
19+
1620
[dependencies]
1721
bitflags = "1.0.4"
1822
errno = "0.2"

src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
3131
#![warn(missing_docs)]
3232

33+
#[cfg(test)]
34+
#[macro_use]
35+
extern crate lazy_static;
36+
3337
mod api;
3438
mod constants;
3539
mod keytype;
@@ -41,3 +45,6 @@ pub use self::constants::*;
4145
pub use self::keytype::*;
4246

4347
pub use keyutils_raw::{DefaultKeyring, KeyPermissions, KeyringSerial, TimeoutSeconds};
48+
49+
#[cfg(test)]
50+
mod tests;

src/tests/add.rs

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright (c) 2019, Ben Boeckel
2+
// All rights reserved.
3+
//
4+
// Redistribution and use in source and binary forms, with or without modification,
5+
// are permitted provided that the following conditions are met:
6+
//
7+
// * Redistributions of source code must retain the above copyright notice,
8+
// this list of conditions and the following disclaimer.
9+
// * Redistributions in binary form must reproduce the above copyright notice,
10+
// this list of conditions and the following disclaimer in the documentation
11+
// and/or other materials provided with the distribution.
12+
// * Neither the name of this project nor the names of its contributors
13+
// may be used to endorse or promote products derived from this software
14+
// without specific prior written permission.
15+
//
16+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
use std::iter;
28+
29+
use crate::keytypes::User;
30+
use crate::{Keyring, KeyringSerial, SpecialKeyring};
31+
32+
use super::utils::kernel::*;
33+
use super::utils::keys::*;
34+
35+
#[test]
36+
fn empty_key_type() {
37+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
38+
let err = keyring.add_key::<EmptyKey, _, _>("", ()).unwrap_err();
39+
assert_eq!(err, errno::Errno(libc::EINVAL));
40+
}
41+
42+
#[test]
43+
fn unsupported_key_type() {
44+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
45+
let err = keyring.add_key::<UnsupportedKey, _, _>("", ()).unwrap_err();
46+
assert_eq!(err, errno::Errno(libc::ENODEV));
47+
}
48+
49+
#[test]
50+
fn invalid_key_type() {
51+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
52+
let err = keyring.add_key::<InvalidKey, _, _>("", ()).unwrap_err();
53+
assert_eq!(err, errno::Errno(libc::EPERM));
54+
}
55+
56+
#[test]
57+
fn maxlen_key_type() {
58+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
59+
let err = keyring.add_key::<MaxLenKey, _, _>("", ()).unwrap_err();
60+
assert_eq!(err, errno::Errno(libc::ENODEV));
61+
}
62+
63+
#[test]
64+
fn overlong_key_type() {
65+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
66+
let err = keyring.add_key::<OverlongKey, _, _>("", ()).unwrap_err();
67+
assert_eq!(err, errno::Errno(libc::EINVAL));
68+
}
69+
70+
#[test]
71+
fn keyring_with_payload() {
72+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
73+
let err = keyring
74+
.add_key::<KeyringShadow, _, _>("", "payload")
75+
.unwrap_err();
76+
assert_eq!(err, errno::Errno(libc::EINVAL));
77+
}
78+
79+
#[test]
80+
fn max_user_description() {
81+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
82+
// Subtract one because the NUL is added in the kernel API.
83+
let maxdesc: String = iter::repeat('a').take(*PAGE_SIZE - 1).collect();
84+
let res = keyring.add_key::<User, _, _>(maxdesc.as_ref(), "payload".as_bytes());
85+
// If the user's quota is smaller than this, it's an error.
86+
if KEY_INFO.maxbytes < *PAGE_SIZE {
87+
assert_eq!(res.unwrap_err(), errno::Errno(libc::EDQUOT));
88+
} else {
89+
let key = res.unwrap();
90+
assert_eq!(key.description().unwrap().description, maxdesc);
91+
key.invalidate().unwrap();
92+
}
93+
}
94+
95+
#[test]
96+
fn overlong_user_description() {
97+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Process).unwrap();
98+
// On MIPS with < 3.19, there is a bug where this is allowed. 3.19 was released in Feb 2015,
99+
// so this is being ignored here.
100+
let toolarge: String = iter::repeat('a').take(*PAGE_SIZE).collect();
101+
let err = keyring
102+
.add_key::<User, _, _>(toolarge.as_ref(), "payload".as_bytes())
103+
.unwrap_err();
104+
assert_eq!(err, errno::Errno(libc::EINVAL));
105+
}
106+
107+
#[test]
108+
fn invalid_keyring() {
109+
// Yes, we're explicitly breaking the NonZeroI32 rules here. However, it is not passing
110+
// through any bits which care (e.g., `Option`), so this is purely to test that using an
111+
// invalid keyring ID gives back `EINVAL` as expected.
112+
let mut keyring = unsafe { Keyring::new(KeyringSerial::new_unchecked(0)) };
113+
let err = keyring
114+
.add_key::<User, _, _>("desc", "payload".as_bytes())
115+
.unwrap_err();
116+
assert_eq!(err, errno::Errno(libc::EINVAL));
117+
}
118+
119+
#[test]
120+
fn add_key_to_session() {
121+
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Session).unwrap();
122+
let expected = "stuff".as_bytes();
123+
let mut key = keyring.add_key::<User, _, _>("wibble", expected).unwrap();
124+
let payload = key.read().unwrap();
125+
assert_eq!(payload, expected);
126+
let new_expected = "lizard".as_bytes();
127+
key.update(new_expected).unwrap();
128+
let new_payload = key.read().unwrap();
129+
assert_eq!(new_payload, new_expected);
130+
keyring.unlink_key(&key).unwrap();
131+
}

src/tests/mod.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2019, Ben Boeckel
2+
// All rights reserved.
3+
//
4+
// Redistribution and use in source and binary forms, with or without modification,
5+
// are permitted provided that the following conditions are met:
6+
//
7+
// * Redistributions of source code must retain the above copyright notice,
8+
// this list of conditions and the following disclaimer.
9+
// * Redistributions in binary form must reproduce the above copyright notice,
10+
// this list of conditions and the following disclaimer in the documentation
11+
// and/or other materials provided with the distribution.
12+
// * Neither the name of this project nor the names of its contributors
13+
// may be used to endorse or promote products derived from this software
14+
// without specific prior written permission.
15+
//
16+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
//! The test structure here comes from the structure in libkeyutils.
28+
29+
mod utils;
30+
31+
mod add;

src/tests/utils/kernel.rs

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright (c) 2019, Ben Boeckel
2+
// All rights reserved.
3+
//
4+
// Redistribution and use in source and binary forms, with or without modification,
5+
// are permitted provided that the following conditions are met:
6+
//
7+
// * Redistributions of source code must retain the above copyright notice,
8+
// this list of conditions and the following disclaimer.
9+
// * Redistributions in binary form must reproduce the above copyright notice,
10+
// this list of conditions and the following disclaimer in the documentation
11+
// and/or other materials provided with the distribution.
12+
// * Neither the name of this project nor the names of its contributors
13+
// may be used to endorse or promote products derived from this software
14+
// without specific prior written permission.
15+
//
16+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
use std::collections::HashMap;
28+
use std::fs;
29+
use std::str::FromStr;
30+
31+
use regex::{Captures, Regex};
32+
33+
lazy_static! {
34+
pub static ref PAGE_SIZE: usize = page_size();
35+
pub static ref KEY_INFO: KeyQuota = key_user_info();
36+
}
37+
38+
fn page_size() -> usize {
39+
errno::set_errno(errno::Errno(0));
40+
let ret = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
41+
if ret < 0 {
42+
let err = errno::errno();
43+
if err.0 == 0 {
44+
panic!("page size is indeterminite?");
45+
} else {
46+
panic!("failed to query the page size: {}", errno::errno());
47+
}
48+
}
49+
ret as usize
50+
}
51+
52+
const KEY_USERS_FILE: &str = "/proc/key-users";
53+
54+
lazy_static! {
55+
static ref KEY_USERS: Regex = Regex::new(
56+
" *(?P<uid>\\d+): +\
57+
(?P<usage>\\d+) \
58+
(?P<nkeys>\\d+)/(?P<nikeys>\\d+) \
59+
(?P<qnkeys>\\d+)/(?P<maxkeys>\\d+) \
60+
(?P<qnbytes>\\d+)/(?P<maxbytes>\\d+)"
61+
)
62+
.unwrap();
63+
}
64+
65+
fn by_name<T: FromStr>(capture: &Captures, name: &str) -> T {
66+
let cap = capture
67+
.name(name)
68+
.expect("name should be captured")
69+
.as_str();
70+
match cap.parse() {
71+
Ok(v) => v,
72+
Err(_) => panic!("failed to parse {} as an integer", name),
73+
}
74+
}
75+
76+
#[derive(Debug, Clone, Copy)]
77+
pub struct KeyQuota {
78+
pub usage: usize,
79+
pub nkeys: usize,
80+
pub nikeys: usize,
81+
pub qnkeys: usize,
82+
pub maxkeys: usize,
83+
pub qnbytes: usize,
84+
pub maxbytes: usize,
85+
}
86+
87+
fn all_key_user_info() -> HashMap<libc::uid_t, KeyQuota> {
88+
let data = String::from_utf8(fs::read(KEY_USERS_FILE).unwrap()).unwrap();
89+
(*KEY_USERS)
90+
.captures_iter(&data)
91+
.map(|capture| {
92+
let uid = by_name(&capture, "uid");
93+
let usage = by_name(&capture, "usage");
94+
let nkeys = by_name(&capture, "nkeys");
95+
let nikeys = by_name(&capture, "nikeys");
96+
let qnkeys = by_name(&capture, "qnkeys");
97+
let maxkeys = by_name(&capture, "maxkeys");
98+
let qnbytes = by_name(&capture, "qnbytes");
99+
let maxbytes = by_name(&capture, "maxbytes");
100+
101+
(
102+
uid,
103+
KeyQuota {
104+
usage,
105+
nkeys,
106+
nikeys,
107+
qnkeys,
108+
maxkeys,
109+
qnbytes,
110+
maxbytes,
111+
},
112+
)
113+
})
114+
.collect()
115+
}
116+
117+
fn key_user_info() -> KeyQuota {
118+
let uid = unsafe { libc::getuid() };
119+
*all_key_user_info()
120+
.get(&uid)
121+
.expect("the current user has no keys?")
122+
}

0 commit comments

Comments
 (0)