@@ -26,6 +26,7 @@ use camino::Utf8PathBuf;
26
26
use cap_std:: fs:: { Dir , MetadataExt } ;
27
27
use cap_std_ext:: cap_std;
28
28
use cap_std_ext:: cap_std:: fs_utf8:: DirEntry as DirEntryUtf8 ;
29
+ use cap_std_ext:: cap_tempfile:: TempDir ;
29
30
use cap_std_ext:: cmdext:: CapStdExtCommandExt ;
30
31
use cap_std_ext:: prelude:: CapStdExtDirExt ;
31
32
use chrono:: prelude:: * ;
@@ -322,6 +323,7 @@ pub(crate) struct State {
322
323
pub ( crate ) root_ssh_authorized_keys : Option < String > ,
323
324
/// The root filesystem of the running container
324
325
pub ( crate ) container_root : Dir ,
326
+ pub ( crate ) tempdir : TempDir ,
325
327
}
326
328
327
329
impl State {
@@ -342,6 +344,7 @@ impl State {
342
344
343
345
#[ context( "Finalizing state" ) ]
344
346
pub ( crate ) fn consume ( self ) -> Result < ( ) > {
347
+ self . tempdir . close ( ) ?;
345
348
// If we had invoked `setenforce 0`, then let's re-enable it.
346
349
if let SELinuxFinalState :: Enabled ( Some ( guard) ) = self . selinux_state {
347
350
guard. consume ( ) ?;
@@ -1001,7 +1004,7 @@ fn ensure_var() -> Result<()> {
1001
1004
/// via a custom bwrap container today) and work around it by
1002
1005
/// mounting a writable transient overlayfs.
1003
1006
#[ context( "Ensuring writable /etc" ) ]
1004
- fn ensure_writable_etc_containers ( ) -> Result < ( ) > {
1007
+ fn ensure_writable_etc_containers ( tempdir : & Dir ) -> Result < ( ) > {
1005
1008
let etc_containers = Utf8Path :: new ( "/etc/containers" ) ;
1006
1009
// If there's no /etc/containers, nothing to do
1007
1010
if !etc_containers. try_exists ( ) ? {
@@ -1010,24 +1013,18 @@ fn ensure_writable_etc_containers() -> Result<()> {
1010
1013
if rustix:: fs:: access ( etc_containers. as_std_path ( ) , rustix:: fs:: Access :: WRITE_OK ) . is_ok ( ) {
1011
1014
return Ok ( ( ) ) ;
1012
1015
}
1013
- // Create a tempdir for the overlayfs upper; right now this is leaked,
1014
- // but in the case we care about it's into a tmpfs allocated only while
1015
- // we're running (equivalent to PrivateTmp=yes), so it's not
1016
- // really a leak.
1017
- let td = tempfile:: tempdir_in ( "/tmp" ) ?. into_path ( ) ;
1018
- let td: & Utf8Path = ( td. as_path ( ) ) . try_into ( ) ?;
1019
- let upper = & td. join ( "upper" ) ;
1020
- let work = & td. join ( "work" ) ;
1021
- std:: fs:: create_dir ( upper) ?;
1022
- std:: fs:: create_dir ( work) ?;
1023
- let opts = format ! ( "lowerdir={etc_containers},workdir={work},upperdir={upper}" ) ;
1024
- Task :: new (
1016
+ // Create dirs for the overlayfs upper and work in the install-global tmpdir.
1017
+ tempdir. create_dir_all ( "etc-ovl/upper" ) ?;
1018
+ tempdir. create_dir ( "etc-ovl/work" ) ?;
1019
+ let opts = format ! ( "lowerdir={etc_containers},workdir=etc-ovl/work,upperdir=etc-ovl/upper" ) ;
1020
+ let mut t = Task :: new (
1025
1021
& format ! ( "Mount transient overlayfs for {etc_containers}" ) ,
1026
1022
"mount" ,
1027
1023
)
1028
1024
. args ( [ "-t" , "overlay" , "overlay" , "-o" , opts. as_str ( ) ] )
1029
- . arg ( etc_containers)
1030
- . run ( ) ?;
1025
+ . arg ( etc_containers) ;
1026
+ t. cmd . cwd_dir ( tempdir. try_clone ( ) ?) ;
1027
+ t. run ( ) ?;
1031
1028
Ok ( ( ) )
1032
1029
}
1033
1030
@@ -1123,11 +1120,12 @@ pub(crate) fn setup_sys_mount(fstype: &str, fspath: &str) -> Result<()> {
1123
1120
1124
1121
/// Verify that we can load the manifest of the target image
1125
1122
#[ context( "Verifying fetch" ) ]
1126
- async fn verify_target_fetch ( imgref : & ostree_container:: OstreeImageReference ) -> Result < ( ) > {
1127
- let tmpdir = tempfile:: tempdir ( ) ?;
1128
- let tmprepo = & ostree:: Repo :: new_for_path ( tmpdir. path ( ) ) ;
1129
- tmprepo
1130
- . create ( ostree:: RepoMode :: Bare , ostree:: gio:: Cancellable :: NONE )
1123
+ async fn verify_target_fetch (
1124
+ tmpdir : & Dir ,
1125
+ imgref : & ostree_container:: OstreeImageReference ,
1126
+ ) -> Result < ( ) > {
1127
+ let tmpdir = & TempDir :: new_in ( & tmpdir) ?;
1128
+ let tmprepo = & ostree:: Repo :: create_at_dir ( tmpdir. as_fd ( ) , "." , ostree:: RepoMode :: Bare , None )
1131
1129
. context ( "Init tmp repo" ) ?;
1132
1130
1133
1131
tracing:: trace!( "Verifying fetch for {imgref}" ) ;
@@ -1210,13 +1208,18 @@ async fn prepare_install(
1210
1208
} ;
1211
1209
tracing:: debug!( "Target image reference: {target_imgref}" ) ;
1212
1210
1213
- if !target_opts. skip_fetch_check {
1214
- verify_target_fetch ( & target_imgref) . await ?;
1215
- }
1216
-
1211
+ // A bit of basic global state setup
1217
1212
ensure_var ( ) ?;
1218
1213
setup_tmp_mounts ( ) ?;
1219
- ensure_writable_etc_containers ( ) ?;
1214
+ // Allocate a temporary directory we can use in various places to avoid
1215
+ // creating multiple.
1216
+ let tempdir = cap_std_ext:: cap_tempfile:: TempDir :: new ( cap_std:: ambient_authority ( ) ) ?;
1217
+ // And continue to init global state
1218
+ ensure_writable_etc_containers ( & tempdir) ?;
1219
+
1220
+ if !target_opts. skip_fetch_check {
1221
+ verify_target_fetch ( & tempdir, & target_imgref) . await ?;
1222
+ }
1220
1223
1221
1224
// Even though we require running in a container, the mounts we create should be specific
1222
1225
// to this process, so let's enter a private mountns to avoid leaking them.
@@ -1260,6 +1263,7 @@ async fn prepare_install(
1260
1263
install_config,
1261
1264
root_ssh_authorized_keys,
1262
1265
container_root : rootfs,
1266
+ tempdir,
1263
1267
} ) ;
1264
1268
1265
1269
Ok ( state)
0 commit comments