This is an automated email from the ASF dual-hosted git repository.
bstoyanov pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.20 by this push:
new 35e6d7c5ba8 fix that log sensitive infomation in cmd of script (#12024)
35e6d7c5ba8 is described below
commit 35e6d7c5ba8f921c7611ab6c0c84d7b3db557456
Author: Edward-x <[email protected]>
AuthorDate: Wed Jan 28 19:16:59 2026 +0800
fix that log sensitive infomation in cmd of script (#12024)
* fix that log sensitive infomation in cmd of script
* Remove unnecessary line break in Script.java
* Update utils/src/main/java/com/cloud/utils/script/Script.java
Co-authored-by: Copilot <[email protected]>
* Refactor logging in Script class to simplify handling of sensitive
arguments
* Improve command logging in Script class to include full command line when
debugging
* Remove unused _passwordCommand flag from Script class to simplify code
* Update utils/src/main/java/com/cloud/utils/script/Script.java
Co-authored-by: Copilot <[email protected]>
* Remove unused import for KeyStoreUtils
* Update utils/src/main/java/com/cloud/utils/script/Script.java
---------
Co-authored-by: [email protected] <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: dahn <[email protected]>
Co-authored-by: dahn <[email protected]>
---
.../LibvirtUpdateHostPasswordCommandWrapper.java | 3 +-
.../CitrixUpdateHostPasswordCommandWrapper.java | 2 +-
.../main/java/com/cloud/utils/script/Script.java | 99 +++++++++++++---------
.../java/com/cloud/utils/script/ScriptTest.java | 30 +++++++
4 files changed, 93 insertions(+), 41 deletions(-)
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUpdateHostPasswordCommandWrapper.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUpdateHostPasswordCommandWrapper.java
index b8fe0ded716..80c723b5a6e 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUpdateHostPasswordCommandWrapper.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUpdateHostPasswordCommandWrapper.java
@@ -37,7 +37,8 @@ public final class LibvirtUpdateHostPasswordCommandWrapper
extends CommandWrappe
final String newPassword = command.getNewPassword();
final Script script =
libvirtUtilitiesHelper.buildScript(libvirtComputingResource.getUpdateHostPasswdPath());
- script.add(username, newPassword);
+ script.add(username);
+ script.addSensitive(newPassword);
final String result = script.execute();
if (result != null) {
diff --git
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java
index af868d8c1c7..e3ee0ca13ca 100644
---
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java
+++
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java
@@ -47,7 +47,7 @@ public final class CitrixUpdateHostPasswordCommandWrapper
extends CommandWrapper
try {
logger.debug("Executing password update command on host: {} for
user: {}", hostIp, username);
final String hostPassword = citrixResourceBase.getPwdFromQueue();
- result = xenServerUtilitiesHelper.executeSshWrapper(hostIp, 22,
username, null, hostPassword, cmdLine.toString());
+ result = xenServerUtilitiesHelper.executeSshWrapper(hostIp, 22,
username, null, hostPassword, cmdLine);
} catch (final Exception e) {
return new Answer(command, false, e.getMessage());
}
diff --git a/utils/src/main/java/com/cloud/utils/script/Script.java
b/utils/src/main/java/com/cloud/utils/script/Script.java
index ffda782edda..09c58dce9a8 100644
--- a/utils/src/main/java/com/cloud/utils/script/Script.java
+++ b/utils/src/main/java/com/cloud/utils/script/Script.java
@@ -30,8 +30,10 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Properties;
+import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
@@ -43,7 +45,6 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
-import org.apache.cloudstack.utils.security.KeyStoreUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
@@ -66,8 +67,8 @@ public class Script implements Callable<String> {
private static final int DEFAULT_TIMEOUT = 3600 * 1000; /* 1 hour */
private volatile boolean _isTimeOut = false;
- private boolean _passwordCommand = false;
private boolean avoidLoggingCommand = false;
+ private final Set<Integer> sensitiveArgIndices = new HashSet<>();
private static final ScheduledExecutorService s_executors =
Executors.newScheduledThreadPool(10, new NamedThreadFactory("Script"));
@@ -145,6 +146,11 @@ public class Script implements Callable<String> {
_command.add(param);
}
+ public void addSensitive(String param) {
+ _command.add(param);
+ sensitiveArgIndices.add(_command.size() - 1);
+ }
+
public Script set(String name, String value) {
_command.add(name);
_command.add(value);
@@ -163,7 +169,7 @@ public class Script implements Callable<String> {
if (sanitizeViCmdParameter(cmd, builder) ||
sanitizeRbdFileFormatCmdParameter(cmd, builder)) {
continue;
}
- if (obscureParam) {
+ if (obscureParam || sensitiveArgIndices.contains(i)) {
builder.append("******").append(" ");
obscureParam = false;
} else {
@@ -172,7 +178,6 @@ public class Script implements Callable<String> {
if ("-y".equals(cmd) || "-z".equals(cmd)) {
obscureParam = true;
- _passwordCommand = true;
}
}
return builder.toString();
@@ -240,8 +245,8 @@ public class Script implements Callable<String> {
public String execute(OutputInterpreter interpreter) {
String[] command = _command.toArray(new String[_command.size()]);
String commandLine = buildCommandLine(command);
- if (_logger.isDebugEnabled() && !avoidLoggingCommand) {
- _logger.debug(String.format("Executing command [%s].",
commandLine.split(KeyStoreUtils.KS_FILENAME)[0]));
+ if (_logger.isDebugEnabled() ) {
+ _logger.debug(String.format("Executing command [%s].",
commandLine));
}
try {
@@ -263,48 +268,62 @@ public class Script implements Callable<String> {
_thread = Thread.currentThread();
ScheduledFuture<String> future = null;
if (_timeout > 0) {
- _logger.trace(String.format("Scheduling the execution of
command [%s] with a timeout of [%s] milliseconds.", commandLine, _timeout));
+ _logger.trace(String.format(
+ "Scheduling the execution of command [%s] with a
timeout of [%s] milliseconds.",
+ commandLine, _timeout));
future = s_executors.schedule(this, _timeout,
TimeUnit.MILLISECONDS);
}
long processPid = _process.pid();
Task task = null;
if (interpreter != null && interpreter.drain()) {
- _logger.trace(String.format("Executing interpreting task of
process [%s] for command [%s].", processPid, commandLine));
+ _logger.trace(String.format("Executing interpreting task of
process [%s] for command [%s].",
+ processPid, commandLine));
task = new Task(interpreter, ir);
s_executors.execute(task);
}
while (true) {
- _logger.trace(String.format("Attempting process [%s] execution
for command [%s] with timeout [%s].", processPid, commandLine, _timeout));
+ _logger.trace(String.format("Attempting process [%s] execution
for command [%s] with timeout [%s].",
+ processPid, commandLine, _timeout));
try {
if (_process.waitFor(_timeout, TimeUnit.MILLISECONDS)) {
- _logger.trace(String.format("Process [%s] execution
for command [%s] completed within timeout period [%s].", processPid,
commandLine,
+ _logger.trace(String.format(
+ "Process [%s] execution for command [%s]
completed within timeout period [%s].",
+ processPid, commandLine,
_timeout));
if (_process.exitValue() == 0) {
- _logger.debug(String.format("Successfully executed
process [%s] for command [%s].", processPid, commandLine));
+ _logger.debug(String.format("Successfully executed
process [%s] for command [%s].",
+ processPid, commandLine));
if (interpreter != null) {
if (interpreter.drain()) {
- _logger.trace(String.format("Returning
task result of process [%s] for command [%s].", processPid, commandLine));
+ _logger.trace(
+ String.format("Returning task
result of process [%s] for command [%s].",
+ processPid, commandLine));
return task.getResult();
}
- _logger.trace(String.format("Returning
interpretation of process [%s] for command [%s].", processPid, commandLine));
+ _logger.trace(
+ String.format("Returning
interpretation of process [%s] for command [%s].",
+ processPid, commandLine));
return interpreter.interpret(ir);
} else {
// null return exitValue apparently
- _logger.trace(String.format("Process [%s] for
command [%s] exited with value [%s].", processPid, commandLine,
+ _logger.trace(String.format("Process [%s] for
command [%s] exited with value [%s].",
+ processPid, commandLine,
_process.exitValue()));
return String.valueOf(_process.exitValue());
}
} else {
- _logger.warn(String.format("Execution of process
[%s] for command [%s] failed.", processPid, commandLine));
+ _logger.warn(String.format("Execution of process
[%s] for command [%s] failed.",
+ processPid, commandLine));
break;
}
}
} catch (InterruptedException e) {
if (!_isTimeOut) {
- _logger.debug(String.format("Exception [%s] occurred;
however, it was not a timeout. Therefore, proceeding with the execution of
process [%s] for command "
- + "[%s].", e.getMessage(), processPid,
commandLine), e);
+ _logger.debug(String.format(
+ "Exception [%s] occurred; however, it was not
a timeout. Therefore, proceeding with the execution of process [%s] for command
[%s].",
+ e.getMessage(), processPid, commandLine), e);
continue;
}
} finally {
@@ -317,18 +336,17 @@ public class Script implements Callable<String> {
TimedOutLogger log = new TimedOutLogger(_process);
Task timedoutTask = new Task(log, ir);
- _logger.trace(String.format("Running timed out task of process
[%s] for command [%s].", processPid, commandLine));
+ _logger.trace(String.format("Running timed out task of process
[%s] for command [%s].", processPid,
+ commandLine));
timedoutTask.run();
- if (!_passwordCommand) {
- _logger.warn(String.format("Process [%s] for command [%s]
timed out. Output is [%s].", processPid, commandLine,
timedoutTask.getResult()));
- } else {
- _logger.warn(String.format("Process [%s] for command [%s]
timed out.", processPid, commandLine));
- }
+ _logger.warn(String.format("Process [%s] for command [%s]
timed out. Output is [%s].", processPid,
+ commandLine, timedoutTask.getResult()));
return ERR_TIMEOUT;
}
- _logger.debug(String.format("Exit value of process [%s] for
command [%s] is [%s].", processPid, commandLine, _process.exitValue()));
+ _logger.debug(String.format("Exit value of process [%s] for
command [%s] is [%s].", processPid,
+ commandLine, _process.exitValue()));
BufferedReader reader = new BufferedReader(new
InputStreamReader(_process.getInputStream()), 128);
@@ -339,19 +357,24 @@ public class Script implements Callable<String> {
error = String.valueOf(_process.exitValue());
}
- _logger.warn(String.format("Process [%s] for command [%s]
encountered the error: [%s].", processPid, commandLine, error));
+ _logger.warn(String.format("Process [%s] for command [%s]
encountered the error: [%s].", processPid,
+ commandLine, error));
return error;
} catch (SecurityException ex) {
- _logger.warn(String.format("Exception [%s] occurred. This may be
due to an attempt of executing command [%s] as non root.", ex.getMessage(),
commandLine),
+ _logger.warn(String.format(
+ "Exception [%s] occurred. This may be due to an attempt of
executing command [%s] as non root.",
+ ex.getMessage(), commandLine),
ex);
return stackTraceAsString(ex);
} catch (Exception ex) {
- _logger.warn(String.format("Exception [%s] occurred when
attempting to run command [%s].", ex.getMessage(), commandLine), ex);
+ _logger.warn(String.format("Exception [%s] occurred when
attempting to run command [%s].",
+ ex.getMessage(), commandLine), ex);
return stackTraceAsString(ex);
} finally {
if (_process != null) {
- _logger.trace(String.format("Destroying process [%s] for
command [%s].", _process.pid(), commandLine));
+ _logger.trace(
+ String.format("Destroying process [%s] for command
[%s].", _process.pid(), commandLine));
IOUtils.closeQuietly(_process.getErrorStream());
IOUtils.closeQuietly(_process.getOutputStream());
IOUtils.closeQuietly(_process.getInputStream());
@@ -362,9 +385,10 @@ public class Script implements Callable<String> {
public String executeIgnoreExitValue(OutputInterpreter interpreter, int
exitValue) {
String[] command = _command.toArray(new String[_command.size()]);
+ String commandLine = buildCommandLine(command);
if (_logger.isDebugEnabled()) {
- _logger.debug(String.format("Executing: %s",
buildCommandLine(command).split(KeyStoreUtils.KS_FILENAME)[0]));
+ _logger.debug(String.format("Executing: %s", commandLine));
}
try {
@@ -375,7 +399,7 @@ public class Script implements Callable<String> {
_process = pb.start();
if (_process == null) {
- _logger.warn(String.format("Unable to execute: %s",
buildCommandLine(command)));
+ _logger.warn(String.format("Unable to execute: %s",
commandLine));
return String.format("Unable to execute the command: %s",
command[0]);
}
@@ -439,11 +463,8 @@ public class Script implements Callable<String> {
Task timedoutTask = new Task(log, ir);
timedoutTask.run();
- if (!_passwordCommand) {
- _logger.warn(String.format("Timed out: %s. Output is:
%s", buildCommandLine(command), timedoutTask.getResult()));
- } else {
- _logger.warn(String.format("Timed out: %s",
buildCommandLine(command)));
- }
+ _logger.warn(String.format("Timed out: %s. Output is: %s",
commandLine,
+ timedoutTask.getResult()));
return ERR_TIMEOUT;
}
@@ -467,7 +488,7 @@ public class Script implements Callable<String> {
_logger.warn("Security Exception....not running as root?", ex);
return stackTraceAsString(ex);
} catch (Exception ex) {
- _logger.warn(String.format("Exception: %s",
buildCommandLine(command)), ex);
+ _logger.warn(String.format("Exception: %s", commandLine), ex);
return stackTraceAsString(ex);
} finally {
if (_process != null) {
@@ -516,9 +537,9 @@ public class Script implements Callable<String> {
} catch (Exception ex) {
result = stackTraceAsString(ex);
} finally {
- done = true;
- notifyAll();
- IOUtils.closeQuietly(reader);
+ done = true;
+ notifyAll();
+ IOUtils.closeQuietly(reader);
}
}
}
diff --git a/utils/src/test/java/com/cloud/utils/script/ScriptTest.java
b/utils/src/test/java/com/cloud/utils/script/ScriptTest.java
index cc6047959da..a52f3840bea 100644
--- a/utils/src/test/java/com/cloud/utils/script/ScriptTest.java
+++ b/utils/src/test/java/com/cloud/utils/script/ScriptTest.java
@@ -78,4 +78,34 @@ public class ScriptTest {
String result = Script.getExecutableAbsolutePath("ls");
Assert.assertTrue(List.of("/usr/bin/ls", "/bin/ls").contains(result));
}
+
+ @Test
+ public void testBuildCommandLineWithSensitiveData() {
+ Script script = new Script("test.sh");
+ script.add("normal-arg");
+ script.addSensitive("sensitive-arg");
+ String commandLine = script.toString();
+ Assert.assertEquals("test.sh normal-arg ****** ", commandLine);
+ }
+
+ @Test
+ public void testBuildCommandLineWithMultipleSensitiveData() {
+ Script script = new Script("test.sh");
+ script.add("normal-arg");
+ script.addSensitive("sensitive-arg1");
+ script.add("another-normal-arg");
+ script.addSensitive("sensitive-arg2");
+ String commandLine = script.toString();
+ Assert.assertEquals("test.sh normal-arg ****** another-normal-arg
****** ", commandLine);
+ }
+
+ @Test
+ public void testBuildCommandLineWithLegacyPasswordOption() {
+ Script script = new Script("test.sh");
+ script.add("-y");
+ script.add("legacy-password");
+ String commandLine = script.toString();
+ Assert.assertEquals("test.sh -y ****** ", commandLine);
+ }
+
}