@@ -11,6 +11,7 @@ use crate::fs::{
11
11
errors, open, open_unchecked, readlink_unchecked, set_times_follow_unchecked, FollowSymlinks ,
12
12
Metadata , OpenOptions , SystemTimeSpec ,
13
13
} ;
14
+ use once_cell:: sync:: Lazy ;
14
15
use posish:: {
15
16
fs:: { chmodat, fstatfs, major, renameat, Mode } ,
16
17
path:: DecInt ,
@@ -35,10 +36,6 @@ const PROC_SUPER_MAGIC: libc::__fsword_t = 0x0000_9fa0;
35
36
#[ cfg( target_env = "musl" ) ]
36
37
const PROC_SUPER_MAGIC : libc:: c_ulong = 0x0000_9fa0 ;
37
38
38
- lazy_static ! {
39
- static ref PROC_SELF_FD : io:: Result <fs:: File > = init_proc_self_fd( ) ;
40
- }
41
-
42
39
// Identify a subdirectory of "/proc", to determine which anomalies to
43
40
// check for.
44
41
enum Subdir {
@@ -47,46 +44,6 @@ enum Subdir {
47
44
Fd ,
48
45
}
49
46
50
- /// Open a handle for "/proc/self/fd".
51
- #[ allow( clippy:: useless_conversion) ]
52
- fn init_proc_self_fd ( ) -> io:: Result < fs:: File > {
53
- // When libc does have this constant, check that our copy has the same value.
54
- #[ cfg( not( target_env = "musl" ) ) ]
55
- assert_eq ! (
56
- PROC_SUPER_MAGIC ,
57
- libc:: __fsword_t:: from( libc:: PROC_SUPER_MAGIC )
58
- ) ;
59
-
60
- // Open "/proc". Here and below, use `read(true)` even though we don't need
61
- // read permissions, because Rust's libstd requires an access mode, and
62
- // Linux ignores `O_RDONLY` with `O_PATH`.
63
- let proc = fs:: OpenOptions :: new ( )
64
- . read ( true )
65
- . custom_flags ( libc:: O_PATH | libc:: O_DIRECTORY | libc:: O_NOFOLLOW )
66
- . open ( "/proc" ) ?;
67
- let proc_metadata = check_proc_dir ( Subdir :: Proc , & proc, None , 0 , 0 ) ?;
68
-
69
- let ( uid, gid, pid) = ( getuid ( ) , getgid ( ) , getpid ( ) ) ;
70
- let mut options = OpenOptions :: new ( ) ;
71
- let options = options
72
- . read ( true )
73
- . follow ( FollowSymlinks :: No )
74
- . custom_flags ( libc:: O_PATH | libc:: O_DIRECTORY ) ;
75
-
76
- // Open "/proc/self". Use our pid to compute the name rather than literally
77
- // using "self", as "self" is a symlink.
78
- let proc_self = open_unchecked ( & proc, & DecInt :: new ( pid) , options) ?;
79
- drop ( proc) ;
80
- check_proc_dir ( Subdir :: Pid , & proc_self, Some ( & proc_metadata) , uid, gid) ?;
81
-
82
- // Open "/proc/self/fd".
83
- let proc_self_fd = open_unchecked ( & proc_self, Path :: new ( "fd" ) , options) ?;
84
- drop ( proc_self) ;
85
- check_proc_dir ( Subdir :: Fd , & proc_self_fd, Some ( & proc_metadata) , uid, gid) ?;
86
-
87
- Ok ( proc_self_fd)
88
- }
89
-
90
47
/// Check a subdirectory of "/proc" for anomalies.
91
48
fn check_proc_dir (
92
49
kind : Subdir ,
@@ -222,6 +179,45 @@ fn is_mountpoint(file: &fs::File) -> io::Result<bool> {
222
179
}
223
180
224
181
fn proc_self_fd ( ) -> io:: Result < & ' static fs:: File > {
182
+ #[ allow( clippy:: useless_conversion) ]
183
+ static PROC_SELF_FD : Lazy < io:: Result < fs:: File > > = Lazy :: new ( || {
184
+ // When libc does have this constant, check that our copy has the same value.
185
+ #[ cfg( not( target_env = "musl" ) ) ]
186
+ assert_eq ! (
187
+ PROC_SUPER_MAGIC ,
188
+ libc:: __fsword_t:: from( libc:: PROC_SUPER_MAGIC )
189
+ ) ;
190
+
191
+ // Open "/proc". Here and below, use `read(true)` even though we don't need
192
+ // read permissions, because Rust's libstd requires an access mode, and
193
+ // Linux ignores `O_RDONLY` with `O_PATH`.
194
+ let proc = fs:: OpenOptions :: new ( )
195
+ . read ( true )
196
+ . custom_flags ( libc:: O_PATH | libc:: O_DIRECTORY | libc:: O_NOFOLLOW )
197
+ . open ( "/proc" ) ?;
198
+ let proc_metadata = check_proc_dir ( Subdir :: Proc , & proc, None , 0 , 0 ) ?;
199
+
200
+ let ( uid, gid, pid) = ( getuid ( ) , getgid ( ) , getpid ( ) ) ;
201
+ let mut options = OpenOptions :: new ( ) ;
202
+ let options = options
203
+ . read ( true )
204
+ . follow ( FollowSymlinks :: No )
205
+ . custom_flags ( libc:: O_PATH | libc:: O_DIRECTORY ) ;
206
+
207
+ // Open "/proc/self". Use our pid to compute the name rather than literally
208
+ // using "self", as "self" is a symlink.
209
+ let proc_self = open_unchecked ( & proc, & DecInt :: new ( pid) , options) ?;
210
+ drop ( proc) ;
211
+ check_proc_dir ( Subdir :: Pid , & proc_self, Some ( & proc_metadata) , uid, gid) ?;
212
+
213
+ // Open "/proc/self/fd".
214
+ let proc_self_fd = open_unchecked ( & proc_self, Path :: new ( "fd" ) , options) ?;
215
+ drop ( proc_self) ;
216
+ check_proc_dir ( Subdir :: Fd , & proc_self_fd, Some ( & proc_metadata) , uid, gid) ?;
217
+
218
+ Ok ( proc_self_fd)
219
+ } ) ;
220
+
225
221
PROC_SELF_FD . as_ref ( ) . map_err ( |e| {
226
222
io:: Error :: new (
227
223
io:: ErrorKind :: Other ,
0 commit comments