1
1
//! Routines for "secure" memory operations; i.e. data that we need to send to Linux-PAM and don't
2
2
//! want any copies to leak (that we would then need to zeroize).
3
- use std:: slice;
3
+ use std:: {
4
+ alloc:: { self , Layout } ,
5
+ mem,
6
+ ptr:: NonNull ,
7
+ slice,
8
+ } ;
4
9
5
- pub struct PamBuffer ( * mut u8 ) ;
10
+ const SIZE : usize = super :: sys:: PAM_MAX_RESP_SIZE as usize ;
11
+ const ALIGN : usize = mem:: align_of :: < u8 > ( ) ;
6
12
7
- impl PamBuffer {
8
- const SIZE : usize = super :: sys:: PAM_MAX_RESP_SIZE as usize ;
13
+ pub struct PamBuffer ( NonNull < [ u8 ; SIZE ] > ) ;
14
+
15
+ fn layout ( ) -> Layout {
16
+ // does not panic with the given arguments; also see unit test at the bottom
17
+ Layout :: from_size_align ( SIZE , ALIGN ) . unwrap ( )
18
+ }
9
19
20
+ impl PamBuffer {
10
21
// consume this buffer and return its internal pointer
11
22
// (ending the type-level security, but guaranteeing you need unsafe code to access the data)
12
- pub fn leak ( self ) -> * const u8 {
23
+ pub fn leak ( self ) -> NonNull < u8 > {
13
24
let result = self . 0 ;
14
25
std:: mem:: forget ( self ) ;
15
26
16
- result
27
+ result. cast ( )
17
28
}
18
29
19
30
// initialize the buffer with already existing data (otherwise populating it is a bit hairy)
@@ -31,7 +42,12 @@ impl PamBuffer {
31
42
32
43
impl Default for PamBuffer {
33
44
fn default ( ) -> Self {
34
- PamBuffer ( unsafe { libc:: calloc ( 1 , Self :: SIZE ) as * mut u8 } )
45
+ let res = unsafe { libc:: calloc ( 1 , SIZE ) } ;
46
+ if let Some ( nn) = NonNull :: new ( res) {
47
+ PamBuffer ( nn. cast ( ) )
48
+ } else {
49
+ alloc:: handle_alloc_error ( layout ( ) )
50
+ }
35
51
}
36
52
}
37
53
@@ -40,22 +56,20 @@ impl std::ops::Deref for PamBuffer {
40
56
41
57
fn deref ( & self ) -> & [ u8 ] {
42
58
// make the slice one less in size to guarantee the existence of a terminating NUL
43
- unsafe { slice:: from_raw_parts ( self . 0 , Self :: SIZE - 1 ) }
59
+ unsafe { slice:: from_raw_parts ( self . 0 . as_ptr ( ) . cast ( ) , SIZE - 1 ) }
44
60
}
45
61
}
46
62
47
63
impl std:: ops:: DerefMut for PamBuffer {
48
64
fn deref_mut ( & mut self ) -> & mut [ u8 ] {
49
- unsafe { slice:: from_raw_parts_mut ( self . 0 , Self :: SIZE - 1 ) }
65
+ unsafe { slice:: from_raw_parts_mut ( self . 0 . as_ptr ( ) . cast ( ) , SIZE - 1 ) }
50
66
}
51
67
}
52
68
53
69
impl Drop for PamBuffer {
54
70
fn drop ( & mut self ) {
55
- if !self . 0 . is_null ( ) {
56
- wipe_memory ( unsafe { & mut * ( self . 0 as * mut [ u8 ; Self :: SIZE ] ) } ) ;
57
- unsafe { libc:: free ( self . 0 as * mut _ ) }
58
- }
71
+ wipe_memory ( unsafe { self . 0 . as_mut ( ) } ) ;
72
+ unsafe { libc:: free ( self . 0 . as_ptr ( ) . cast ( ) ) }
59
73
}
60
74
}
61
75
@@ -82,9 +96,9 @@ mod test {
82
96
let test = |text : & str | unsafe {
83
97
let buf = PamBuffer :: new ( text. to_string ( ) . as_bytes_mut ( ) ) ;
84
98
assert_eq ! ( & buf[ ..text. len( ) ] , text. as_bytes( ) ) ;
85
- let ptr = buf. leak ( ) ;
86
- let result = crate :: cutils:: string_from_ptr ( ptr as * mut _ ) ;
87
- libc:: free ( ptr as * mut libc :: c_void ) ;
99
+ let nn = buf. leak ( ) ;
100
+ let result = crate :: cutils:: string_from_ptr ( nn . as_ptr ( ) . cast ( ) ) ;
101
+ libc:: free ( nn . as_ptr ( ) . cast ( ) ) ;
88
102
result
89
103
} ;
90
104
assert_eq ! ( test( "" ) , "" ) ;
@@ -100,4 +114,9 @@ mod test {
100
114
assert ! ( fix[ 3 ..] . iter( ) . all( |& x| x == 0 ) ) ;
101
115
std:: mem:: drop ( fix) ;
102
116
}
117
+
118
+ #[ test]
119
+ fn layout_does_not_panic ( ) {
120
+ let _ = super :: layout ( ) ;
121
+ }
103
122
}
0 commit comments