@@ -6,10 +6,9 @@ use crate::{
66 Compatibility , Compatible , CreateRulesetError , HandledAccess , PrivateHandledAccess ,
77 RestrictSelfError , RulesetError , Scope , ScopeError , TryCompat ,
88} ;
9- use libc:: close;
109use std:: io:: Error ;
1110use std:: mem:: size_of_val;
12- use std:: os:: unix:: io:: { IntoRawFd , RawFd } ;
11+ use std:: os:: unix:: io:: { AsRawFd , FromRawFd , OwnedFd } ;
1312
1413#[ cfg( test) ]
1514use crate :: * ;
@@ -272,7 +271,7 @@ impl Ruleset {
272271 CompatLevel :: HardRequirement => {
273272 Err ( CreateRulesetError :: MissingHandledAccess )
274273 }
275- _ => Ok ( RulesetCreated :: new ( self , - 1 ) ) ,
274+ _ => Ok ( RulesetCreated :: new ( self , None ) ) ,
276275 }
277276 }
278277 CompatState :: Full | CompatState :: Partial => {
@@ -290,7 +289,10 @@ impl Ruleset {
290289 scoped : self . actual_scoped . bits ( ) ,
291290 } ;
292291 match unsafe { uapi:: landlock_create_ruleset ( & attr, size_of_val ( & attr) , 0 ) } {
293- fd if fd >= 0 => Ok ( RulesetCreated :: new ( self , fd) ) ,
292+ fd if fd >= 0 => Ok ( RulesetCreated :: new (
293+ self ,
294+ Some ( unsafe { OwnedFd :: from_raw_fd ( fd) } ) ,
295+ ) ) ,
294296 _ => Err ( CreateRulesetError :: CreateRulesetCall {
295297 source : Error :: last_os_error ( ) ,
296298 } ) ,
@@ -600,15 +602,20 @@ pub trait RulesetCreatedAttr: Sized + AsMut<RulesetCreated> + Compatible {
600602 } ;
601603 match self_ref. compat . state {
602604 CompatState :: Init | CompatState :: No | CompatState :: Dummy => Ok ( self ) ,
603- CompatState :: Full | CompatState :: Partial => match unsafe {
604- uapi:: landlock_add_rule ( self_ref. fd , T :: TYPE_ID , compat_rule. as_ptr ( ) , 0 )
605- } {
606- 0 => Ok ( self ) ,
607- _ => Err ( AddRuleError :: < U > :: AddRuleCall {
608- source : Error :: last_os_error ( ) ,
605+ CompatState :: Full | CompatState :: Partial => {
606+ #[ cfg( test) ]
607+ assert ! ( self_ref. fd. is_some( ) ) ;
608+ let fd = self_ref. fd . as_ref ( ) . map ( |f| f. as_raw_fd ( ) ) . unwrap_or ( -1 ) ;
609+ match unsafe {
610+ uapi:: landlock_add_rule ( fd, T :: TYPE_ID , compat_rule. as_ptr ( ) , 0 )
611+ } {
612+ 0 => Ok ( self ) ,
613+ _ => Err ( AddRuleError :: < U > :: AddRuleCall {
614+ source : Error :: last_os_error ( ) ,
615+ }
616+ . into ( ) ) ,
609617 }
610- . into ( ) ) ,
611- } ,
618+ }
612619 }
613620 } ;
614621 Ok ( body ( ) ?)
@@ -715,15 +722,15 @@ pub trait RulesetCreatedAttr: Sized + AsMut<RulesetCreated> + Compatible {
715722/// Ruleset created with [`Ruleset::create()`].
716723#[ cfg_attr( test, derive( Debug ) ) ]
717724pub struct RulesetCreated {
718- fd : RawFd ,
725+ fd : Option < OwnedFd > ,
719726 no_new_privs : bool ,
720727 pub ( crate ) requested_handled_fs : BitFlags < AccessFs > ,
721728 pub ( crate ) requested_handled_net : BitFlags < AccessNet > ,
722729 compat : Compatibility ,
723730}
724731
725732impl RulesetCreated {
726- pub ( crate ) fn new ( ruleset : Ruleset , fd : RawFd ) -> Self {
733+ pub ( crate ) fn new ( ruleset : Ruleset , fd : Option < OwnedFd > ) -> Self {
727734 // The compatibility state is initialized by Ruleset::create().
728735 #[ cfg( test) ]
729736 assert ! ( !matches!( ruleset. compat. state, CompatState :: Init ) ) ;
@@ -793,7 +800,11 @@ impl RulesetCreated {
793800 no_new_privs : enforced_nnp,
794801 } ) ,
795802 CompatState :: Full | CompatState :: Partial => {
796- match unsafe { uapi:: landlock_restrict_self ( self . fd , 0 ) } {
803+ #[ cfg( test) ]
804+ assert ! ( self . fd. is_some( ) ) ;
805+ // Does not consume ruleset FD, which will be automatically closed after this block.
806+ let fd = self . fd . as_ref ( ) . map ( |f| f. as_raw_fd ( ) ) . unwrap_or ( -1 ) ;
807+ match unsafe { uapi:: landlock_restrict_self ( fd, 0 ) } {
797808 0 => {
798809 self . compat . update ( CompatState :: Full ) ;
799810 Ok ( RestrictionStatus {
@@ -818,13 +829,7 @@ impl RulesetCreated {
818829 /// On error, returns [`std::io::Error`].
819830 pub fn try_clone ( & self ) -> std:: io:: Result < Self > {
820831 Ok ( RulesetCreated {
821- fd : match self . fd {
822- -1 => -1 ,
823- self_fd => match unsafe { libc:: fcntl ( self_fd, libc:: F_DUPFD_CLOEXEC , 0 ) } {
824- dup_fd if dup_fd >= 0 => dup_fd,
825- _ => return Err ( Error :: last_os_error ( ) ) ,
826- } ,
827- } ,
832+ fd : self . fd . as_ref ( ) . map ( |f| f. try_clone ( ) ) . transpose ( ) ?,
828833 no_new_privs : self . no_new_privs ,
829834 requested_handled_fs : self . requested_handled_fs ,
830835 requested_handled_net : self . requested_handled_net ,
@@ -833,20 +838,21 @@ impl RulesetCreated {
833838 }
834839}
835840
836- impl Drop for RulesetCreated {
837- fn drop ( & mut self ) {
838- if self . fd >= 0 {
839- unsafe { close ( self . fd ) } ;
840- }
841+ impl From < RulesetCreated > for Option < OwnedFd > {
842+ fn from ( ruleset : RulesetCreated ) -> Self {
843+ ruleset. fd
841844 }
842845}
843846
844- impl IntoRawFd for RulesetCreated {
845- fn into_raw_fd ( self ) -> RawFd {
846- let fd = self . fd ;
847- std:: mem:: forget ( self ) ;
848- fd
849- }
847+ #[ test]
848+ fn ruleset_created_ownedfd_none ( ) {
849+ let ruleset = Ruleset :: from ( ABI :: Unsupported )
850+ . handle_access ( AccessFs :: Execute )
851+ . unwrap ( )
852+ . create ( )
853+ . unwrap ( ) ;
854+ let fd: Option < OwnedFd > = ruleset. into ( ) ;
855+ assert ! ( fd. is_none( ) ) ;
850856}
851857
852858impl AsMut < RulesetCreated > for RulesetCreated {
@@ -1126,7 +1132,7 @@ fn ruleset_unsupported() {
11261132 . unwrap ( ) ;
11271133 // Fakes a call to create() to test without involving the kernel (i.e. no
11281134 // landlock_ruleset_create() call).
1129- let ruleset_created = RulesetCreated :: new ( ruleset, - 1 ) ;
1135+ let ruleset_created = RulesetCreated :: new ( ruleset, None ) ;
11301136 assert ! ( matches!(
11311137 ruleset_created
11321138 . add_rule( PathBeneath :: new(
0 commit comments