mirror of
				https://github.com/kata-containers/kata-containers.git
				synced 2025-10-30 08:52:39 +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" | scan_fmt = "0.2" | ||||||
| regex = "1.1" | regex = "1.1" | ||||||
| path-absolutize = "1.2.0" | path-absolutize = "1.2.0" | ||||||
| dirs = "3.0.1" |  | ||||||
| anyhow = "1.0.32" | anyhow = "1.0.32" | ||||||
| cgroups = { package = "cgroups-rs", version = "0.2.1" } | cgroups = { package = "cgroups-rs", version = "0.2.1" } | ||||||
| tempfile = "3.1.0" | tempfile = "3.1.0" | ||||||
|   | |||||||
| @@ -58,6 +58,8 @@ use async_trait::async_trait; | |||||||
| use rlimit::{setrlimit, Resource, Rlim}; | use rlimit::{setrlimit, Resource, Rlim}; | ||||||
| use tokio::io::AsyncBufReadExt; | use tokio::io::AsyncBufReadExt; | ||||||
|  |  | ||||||
|  | use crate::utils; | ||||||
|  |  | ||||||
| const STATE_FILENAME: &str = "state.json"; | const STATE_FILENAME: &str = "state.json"; | ||||||
| const EXEC_FIFO_FILENAME: &str = "exec.fifo"; | const EXEC_FIFO_FILENAME: &str = "exec.fifo"; | ||||||
| const VER_MARKER: &str = "1.2.5"; | 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" |     // set the "HOME" env getting from "/etc/passwd" | ||||||
|     if env::var_os(HOME_ENV_KEY).is_none() { |     if env::var_os(HOME_ENV_KEY).is_none() { | ||||||
|         if let Some(home_dir) = dirs::home_dir() { |         match utils::home_dir(guser.uid) { | ||||||
|             env::set_var(HOME_ENV_KEY, home_dir); |             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 specconv; | ||||||
| pub mod sync; | pub mod sync; | ||||||
| pub mod sync_with_async; | pub mod sync_with_async; | ||||||
|  | pub mod utils; | ||||||
| pub mod validator; | pub mod validator; | ||||||
|  |  | ||||||
| // pub mod factory; | // pub mod factory; | ||||||
| //pub mod configs; | //pub mod configs; | ||||||
| // pub mod devices; | // 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