@@ -8,9 +8,66 @@ use crate::sys_common::AsInner;
8
8
9
9
use libc:: { c_int, c_void} ;
10
10
11
+ // Android's libc allows for file descriptors to be marked with a tag that marks ownership.
12
+ // If a tagged file descriptor is closed with the wrong tag, either a backtrace is printed to logs,
13
+ // or the process aborts, depending on process configuration.
14
+ #[ cfg( target_os = "android" ) ]
15
+ mod android {
16
+ use crate :: sync:: atomic:: { AtomicU64 , Ordering } ;
17
+ use libc:: c_int;
18
+
19
+ #[ derive( Debug ) ]
20
+ pub struct CloseTag ( u64 ) ;
21
+
22
+ static FD_TAG : AtomicU64 = AtomicU64 :: new ( 0 ) ;
23
+
24
+ fn next_tag ( ) -> u64 {
25
+ // The most significant 8 bits of the tag are used to identify the type of the owner, as
26
+ // a debugging aid. The value 13 has been reserved to identify Rust-owned fds.
27
+ let tag = FD_TAG . fetch_add ( 1 , Ordering :: Relaxed ) ;
28
+ tag | 13 << 56
29
+ }
30
+
31
+ impl CloseTag {
32
+ pub fn tag ( fd : c_int ) -> CloseTag {
33
+ weak ! ( fn android_fdsan_exchange_owner_tag( c_int, u64 , u64 ) -> u64 ) ;
34
+ match android_fdsan_exchange_owner_tag. get ( ) {
35
+ Some ( f) => {
36
+ let tag = next_tag ( ) ;
37
+ let prev = unsafe { f ( fd, 0 , tag) } ;
38
+ if prev != 0 {
39
+ panic ! ( "attempted to take ownership of an already-owned file descriptor" ) ;
40
+ }
41
+ CloseTag ( tag)
42
+ }
43
+
44
+ None => CloseTag ( 0 ) ,
45
+ }
46
+ }
47
+
48
+ pub fn close ( & mut self , fd : c_int ) {
49
+ weak ! ( fn android_fdsan_close_with_tag( c_int, u64 ) -> c_int) ;
50
+ match android_fdsan_close_with_tag. get ( ) {
51
+ Some ( f) => unsafe {
52
+ f ( fd, self . 0 ) ;
53
+ } ,
54
+
55
+ None => {
56
+ assert_eq ! ( self . 0 , 0 ) ;
57
+ unsafe {
58
+ libc:: close ( fd) ;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+
11
66
#[ derive( Debug ) ]
12
67
pub struct FileDesc {
13
68
fd : c_int ,
69
+ #[ cfg( target_os = "android" ) ]
70
+ tag : android:: CloseTag ,
14
71
}
15
72
16
73
// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
@@ -27,6 +84,12 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1;
27
84
const READ_LIMIT : usize = libc:: ssize_t:: MAX as usize ;
28
85
29
86
impl FileDesc {
87
+ #[ cfg( target_os = "android" ) ]
88
+ pub fn new ( fd : c_int ) -> FileDesc {
89
+ FileDesc { fd, tag : android:: CloseTag :: tag ( fd) }
90
+ }
91
+
92
+ #[ cfg( not( target_os = "android" ) ) ]
30
93
pub fn new ( fd : c_int ) -> FileDesc {
31
94
FileDesc { fd }
32
95
}
@@ -247,6 +310,12 @@ impl AsInner<c_int> for FileDesc {
247
310
}
248
311
249
312
impl Drop for FileDesc {
313
+ #[ cfg( target_os = "android" ) ]
314
+ fn drop ( & mut self ) {
315
+ self . tag . close ( self . fd ) ;
316
+ }
317
+
318
+ #[ cfg( not( target_os = "android" ) ) ]
250
319
fn drop ( & mut self ) {
251
320
// Note that errors are ignored when closing a file descriptor. The
252
321
// reason for this is that if an error occurs we don't actually know if
0 commit comments