mirror of
				https://github.com/kata-containers/kata-containers.git
				synced 2025-11-04 03:29:55 +00:00 
			
		
		
		
	rustjail: fix the issue of home_dir function
Since the crate dirs::home_dir function depends on the libc's api: getpwuid_r, but this api function wouldn't be static linked on glibc, thus we'd better to figure out an alternative way to get the home dir from /etc/passwd. For much more info about this glibc's issue, please see: https://sourceware.org/bugzilla/show_bug.cgi?id=19341. This commit read and parse the "/etc/passwd" directly and fetch the corresponding uid's home dir. Fixes: #675 Signed-off-by: fupan.lfp <fupan.lfp@antfin.com>
This commit is contained in:
		@@ -22,7 +22,6 @@ slog-scope = "4.1.2"
 | 
			
		||||
scan_fmt = "0.2"
 | 
			
		||||
regex = "1.1"
 | 
			
		||||
path-absolutize = "1.2.0"
 | 
			
		||||
dirs = "3.0.1"
 | 
			
		||||
anyhow = "1.0.32"
 | 
			
		||||
cgroups = { package = "cgroups-rs", version = "0.2.1" }
 | 
			
		||||
tempfile = "3.1.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -58,6 +58,8 @@ use async_trait::async_trait;
 | 
			
		||||
use rlimit::{setrlimit, Resource, Rlim};
 | 
			
		||||
use tokio::io::AsyncBufReadExt;
 | 
			
		||||
 | 
			
		||||
use crate::utils;
 | 
			
		||||
 | 
			
		||||
const STATE_FILENAME: &str = "state.json";
 | 
			
		||||
const EXEC_FIFO_FILENAME: &str = "exec.fifo";
 | 
			
		||||
const VER_MARKER: &str = "1.2.5";
 | 
			
		||||
@@ -634,8 +636,9 @@ fn do_init_child(cwfd: RawFd) -> Result<()> {
 | 
			
		||||
 | 
			
		||||
    // set the "HOME" env getting from "/etc/passwd"
 | 
			
		||||
    if env::var_os(HOME_ENV_KEY).is_none() {
 | 
			
		||||
        if let Some(home_dir) = dirs::home_dir() {
 | 
			
		||||
            env::set_var(HOME_ENV_KEY, home_dir);
 | 
			
		||||
        match utils::home_dir(guser.uid) {
 | 
			
		||||
            Ok(home_dir) => env::set_var(HOME_ENV_KEY, home_dir),
 | 
			
		||||
            Err(e) => log_child!(cfd_log, "failed to get home dir: {:?}", e),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,8 +45,8 @@ pub mod process;
 | 
			
		||||
pub mod specconv;
 | 
			
		||||
pub mod sync;
 | 
			
		||||
pub mod sync_with_async;
 | 
			
		||||
pub mod utils;
 | 
			
		||||
pub mod validator;
 | 
			
		||||
 | 
			
		||||
// pub mod factory;
 | 
			
		||||
//pub mod configs;
 | 
			
		||||
// pub mod devices;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										119
									
								
								src/agent/rustjail/src/utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/agent/rustjail/src/utils.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
// Copyright (c) 2021 Ant Group
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
//
 | 
			
		||||
use anyhow::{anyhow, Context, Result};
 | 
			
		||||
use libc::gid_t;
 | 
			
		||||
use libc::uid_t;
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::io::{BufRead, BufReader};
 | 
			
		||||
 | 
			
		||||
const PASSWD_FILE: &str = "/etc/passwd";
 | 
			
		||||
 | 
			
		||||
// An entry from /etc/passwd
 | 
			
		||||
#[derive(Debug, PartialEq, PartialOrd)]
 | 
			
		||||
pub struct PasswdEntry {
 | 
			
		||||
    // username
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    // user password
 | 
			
		||||
    pub passwd: String,
 | 
			
		||||
    // user id
 | 
			
		||||
    pub uid: uid_t,
 | 
			
		||||
    // group id
 | 
			
		||||
    pub gid: gid_t,
 | 
			
		||||
    // user Information
 | 
			
		||||
    pub gecos: String,
 | 
			
		||||
    // home directory
 | 
			
		||||
    pub dir: String,
 | 
			
		||||
    // User's Shell
 | 
			
		||||
    pub shell: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// get an entry for a given `uid` from `/etc/passwd`
 | 
			
		||||
fn get_entry_by_uid(uid: uid_t, path: &str) -> Result<PasswdEntry> {
 | 
			
		||||
    let file = File::open(path).with_context(|| format!("open file {}", path))?;
 | 
			
		||||
    let mut reader = BufReader::new(file);
 | 
			
		||||
 | 
			
		||||
    let mut line = String::new();
 | 
			
		||||
    loop {
 | 
			
		||||
        line.clear();
 | 
			
		||||
        match reader.read_line(&mut line) {
 | 
			
		||||
            Ok(0) => return Err(anyhow!(format!("file {} is empty", path))),
 | 
			
		||||
            Ok(_) => (),
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                return Err(anyhow!(format!(
 | 
			
		||||
                    "failed to read file {} with {:?}",
 | 
			
		||||
                    path, e
 | 
			
		||||
                )))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if line.starts_with('#') {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let parts: Vec<&str> = line.split(':').map(|part| part.trim()).collect();
 | 
			
		||||
        if parts.len() != 7 {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        match parts[2].parse() {
 | 
			
		||||
            Err(_e) => continue,
 | 
			
		||||
            Ok(new_uid) => {
 | 
			
		||||
                if uid != new_uid {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let entry = PasswdEntry {
 | 
			
		||||
                    name: parts[0].to_string(),
 | 
			
		||||
                    passwd: parts[1].to_string(),
 | 
			
		||||
                    uid: new_uid,
 | 
			
		||||
                    gid: parts[3].parse().unwrap_or(0),
 | 
			
		||||
                    gecos: parts[4].to_string(),
 | 
			
		||||
                    dir: parts[5].to_string(),
 | 
			
		||||
                    shell: parts[6].to_string(),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                return Ok(entry);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn home_dir(uid: uid_t) -> Result<String> {
 | 
			
		||||
    get_entry_by_uid(uid, PASSWD_FILE).map(|entry| entry.dir)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use std::io::{self, Write};
 | 
			
		||||
    use tempfile::Builder;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_get_entry_by_uid() {
 | 
			
		||||
        let tmpdir = Builder::new().tempdir().unwrap();
 | 
			
		||||
        let tmpdir_path = tmpdir.path().to_str().unwrap();
 | 
			
		||||
        let temp_passwd = format!("{}/passwd", tmpdir_path);
 | 
			
		||||
 | 
			
		||||
        let mut tempf = File::create(temp_passwd.as_str()).unwrap();
 | 
			
		||||
        writeln!(tempf, "root:x:0:0:root:/root0:/bin/bash").unwrap();
 | 
			
		||||
        writeln!(tempf, "root:x:1:0:root:/root1:/bin/bash").unwrap();
 | 
			
		||||
        writeln!(tempf, "#root:x:1:0:root:/rootx:/bin/bash").unwrap();
 | 
			
		||||
        writeln!(tempf, "root:x:2:0:root:/root2:/bin/bash").unwrap();
 | 
			
		||||
        writeln!(tempf, "root:x:3:0:root:/root3").unwrap();
 | 
			
		||||
        writeln!(tempf, "root:x:3:0:root:/root3:/bin/bash").unwrap();
 | 
			
		||||
 | 
			
		||||
        let entry = get_entry_by_uid(0, temp_passwd.as_str()).unwrap();
 | 
			
		||||
        assert_eq!(entry.dir.as_str(), "/root0");
 | 
			
		||||
 | 
			
		||||
        let entry = get_entry_by_uid(1, temp_passwd.as_str()).unwrap();
 | 
			
		||||
        assert_eq!(entry.dir.as_str(), "/root1");
 | 
			
		||||
 | 
			
		||||
        let entry = get_entry_by_uid(2, temp_passwd.as_str()).unwrap();
 | 
			
		||||
        assert_eq!(entry.dir.as_str(), "/root2");
 | 
			
		||||
 | 
			
		||||
        let entry = get_entry_by_uid(3, temp_passwd.as_str()).unwrap();
 | 
			
		||||
        assert_eq!(entry.dir.as_str(), "/root3");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user