Skip to content

Commit 35e6d7c

Browse files
YLChen-007cyl-authCopilotDaanHoogland
authored
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 <175728472+Copilot@users.noreply.github.com> * 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 <175728472+Copilot@users.noreply.github.com> * Remove unused import for KeyStoreUtils * Update utils/src/main/java/com/cloud/utils/script/Script.java --------- Co-authored-by: chenyoulong20g@ict.ac.cn <chenyoulong20g@ict.ac.cn> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: dahn <daan@onecht.net> Co-authored-by: dahn <daan.hoogland@gmail.com>
1 parent 83ce006 commit 35e6d7c

File tree

4 files changed

+93
-41
lines changed

4 files changed

+93
-41
lines changed

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUpdateHostPasswordCommandWrapper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public Answer execute(final UpdateHostPasswordCommand command, final LibvirtComp
3737
final String newPassword = command.getNewPassword();
3838

3939
final Script script = libvirtUtilitiesHelper.buildScript(libvirtComputingResource.getUpdateHostPasswdPath());
40-
script.add(username, newPassword);
40+
script.add(username);
41+
script.addSensitive(newPassword);
4142
final String result = script.execute();
4243

4344
if (result != null) {

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixUpdateHostPasswordCommandWrapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public Answer execute(final UpdateHostPasswordCommand command, final CitrixResou
4747
try {
4848
logger.debug("Executing password update command on host: {} for user: {}", hostIp, username);
4949
final String hostPassword = citrixResourceBase.getPwdFromQueue();
50-
result = xenServerUtilitiesHelper.executeSshWrapper(hostIp, 22, username, null, hostPassword, cmdLine.toString());
50+
result = xenServerUtilitiesHelper.executeSshWrapper(hostIp, 22, username, null, hostPassword, cmdLine);
5151
} catch (final Exception e) {
5252
return new Answer(command, false, e.getMessage());
5353
}

utils/src/main/java/com/cloud/utils/script/Script.java

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
import java.net.URL;
3131
import java.util.ArrayList;
3232
import java.util.Arrays;
33+
import java.util.HashSet;
3334
import java.util.List;
3435
import java.util.Properties;
36+
import java.util.Set;
3537
import java.util.concurrent.Callable;
3638
import java.util.concurrent.ExecutionException;
3739
import java.util.concurrent.Executors;
@@ -43,7 +45,6 @@
4345
import java.util.concurrent.atomic.AtomicReference;
4446
import java.util.stream.Collectors;
4547

46-
import org.apache.cloudstack.utils.security.KeyStoreUtils;
4748
import org.apache.commons.collections.CollectionUtils;
4849
import org.apache.commons.io.IOUtils;
4950
import org.apache.logging.log4j.LogManager;
@@ -66,8 +67,8 @@ public class Script implements Callable<String> {
6667
private static final int DEFAULT_TIMEOUT = 3600 * 1000; /* 1 hour */
6768
private volatile boolean _isTimeOut = false;
6869

69-
private boolean _passwordCommand = false;
7070
private boolean avoidLoggingCommand = false;
71+
private final Set<Integer> sensitiveArgIndices = new HashSet<>();
7172

7273
private static final ScheduledExecutorService s_executors = Executors.newScheduledThreadPool(10, new NamedThreadFactory("Script"));
7374

@@ -145,6 +146,11 @@ public void add(String param) {
145146
_command.add(param);
146147
}
147148

149+
public void addSensitive(String param) {
150+
_command.add(param);
151+
sensitiveArgIndices.add(_command.size() - 1);
152+
}
153+
148154
public Script set(String name, String value) {
149155
_command.add(name);
150156
_command.add(value);
@@ -163,7 +169,7 @@ protected String buildCommandLine(String[] command) {
163169
if (sanitizeViCmdParameter(cmd, builder) || sanitizeRbdFileFormatCmdParameter(cmd, builder)) {
164170
continue;
165171
}
166-
if (obscureParam) {
172+
if (obscureParam || sensitiveArgIndices.contains(i)) {
167173
builder.append("******").append(" ");
168174
obscureParam = false;
169175
} else {
@@ -172,7 +178,6 @@ protected String buildCommandLine(String[] command) {
172178

173179
if ("-y".equals(cmd) || "-z".equals(cmd)) {
174180
obscureParam = true;
175-
_passwordCommand = true;
176181
}
177182
}
178183
return builder.toString();
@@ -240,8 +245,8 @@ static String stackTraceAsString(Throwable throwable) {
240245
public String execute(OutputInterpreter interpreter) {
241246
String[] command = _command.toArray(new String[_command.size()]);
242247
String commandLine = buildCommandLine(command);
243-
if (_logger.isDebugEnabled() && !avoidLoggingCommand) {
244-
_logger.debug(String.format("Executing command [%s].", commandLine.split(KeyStoreUtils.KS_FILENAME)[0]));
248+
if (_logger.isDebugEnabled() ) {
249+
_logger.debug(String.format("Executing command [%s].", commandLine));
245250
}
246251

247252
try {
@@ -263,48 +268,62 @@ public String execute(OutputInterpreter interpreter) {
263268
_thread = Thread.currentThread();
264269
ScheduledFuture<String> future = null;
265270
if (_timeout > 0) {
266-
_logger.trace(String.format("Scheduling the execution of command [%s] with a timeout of [%s] milliseconds.", commandLine, _timeout));
271+
_logger.trace(String.format(
272+
"Scheduling the execution of command [%s] with a timeout of [%s] milliseconds.",
273+
commandLine, _timeout));
267274
future = s_executors.schedule(this, _timeout, TimeUnit.MILLISECONDS);
268275
}
269276

270277
long processPid = _process.pid();
271278
Task task = null;
272279
if (interpreter != null && interpreter.drain()) {
273-
_logger.trace(String.format("Executing interpreting task of process [%s] for command [%s].", processPid, commandLine));
280+
_logger.trace(String.format("Executing interpreting task of process [%s] for command [%s].",
281+
processPid, commandLine));
274282
task = new Task(interpreter, ir);
275283
s_executors.execute(task);
276284
}
277285

278286
while (true) {
279-
_logger.trace(String.format("Attempting process [%s] execution for command [%s] with timeout [%s].", processPid, commandLine, _timeout));
287+
_logger.trace(String.format("Attempting process [%s] execution for command [%s] with timeout [%s].",
288+
processPid, commandLine, _timeout));
280289
try {
281290
if (_process.waitFor(_timeout, TimeUnit.MILLISECONDS)) {
282-
_logger.trace(String.format("Process [%s] execution for command [%s] completed within timeout period [%s].", processPid, commandLine,
291+
_logger.trace(String.format(
292+
"Process [%s] execution for command [%s] completed within timeout period [%s].",
293+
processPid, commandLine,
283294
_timeout));
284295
if (_process.exitValue() == 0) {
285-
_logger.debug(String.format("Successfully executed process [%s] for command [%s].", processPid, commandLine));
296+
_logger.debug(String.format("Successfully executed process [%s] for command [%s].",
297+
processPid, commandLine));
286298
if (interpreter != null) {
287299
if (interpreter.drain()) {
288-
_logger.trace(String.format("Returning task result of process [%s] for command [%s].", processPid, commandLine));
300+
_logger.trace(
301+
String.format("Returning task result of process [%s] for command [%s].",
302+
processPid, commandLine));
289303
return task.getResult();
290304
}
291-
_logger.trace(String.format("Returning interpretation of process [%s] for command [%s].", processPid, commandLine));
305+
_logger.trace(
306+
String.format("Returning interpretation of process [%s] for command [%s].",
307+
processPid, commandLine));
292308
return interpreter.interpret(ir);
293309
} else {
294310
// null return exitValue apparently
295-
_logger.trace(String.format("Process [%s] for command [%s] exited with value [%s].", processPid, commandLine,
311+
_logger.trace(String.format("Process [%s] for command [%s] exited with value [%s].",
312+
processPid, commandLine,
296313
_process.exitValue()));
297314
return String.valueOf(_process.exitValue());
298315
}
299316
} else {
300-
_logger.warn(String.format("Execution of process [%s] for command [%s] failed.", processPid, commandLine));
317+
_logger.warn(String.format("Execution of process [%s] for command [%s] failed.",
318+
processPid, commandLine));
301319
break;
302320
}
303321
}
304322
} catch (InterruptedException e) {
305323
if (!_isTimeOut) {
306-
_logger.debug(String.format("Exception [%s] occurred; however, it was not a timeout. Therefore, proceeding with the execution of process [%s] for command "
307-
+ "[%s].", e.getMessage(), processPid, commandLine), e);
324+
_logger.debug(String.format(
325+
"Exception [%s] occurred; however, it was not a timeout. Therefore, proceeding with the execution of process [%s] for command [%s].",
326+
e.getMessage(), processPid, commandLine), e);
308327
continue;
309328
}
310329
} finally {
@@ -317,18 +336,17 @@ public String execute(OutputInterpreter interpreter) {
317336
TimedOutLogger log = new TimedOutLogger(_process);
318337
Task timedoutTask = new Task(log, ir);
319338

320-
_logger.trace(String.format("Running timed out task of process [%s] for command [%s].", processPid, commandLine));
339+
_logger.trace(String.format("Running timed out task of process [%s] for command [%s].", processPid,
340+
commandLine));
321341
timedoutTask.run();
322-
if (!_passwordCommand) {
323-
_logger.warn(String.format("Process [%s] for command [%s] timed out. Output is [%s].", processPid, commandLine, timedoutTask.getResult()));
324-
} else {
325-
_logger.warn(String.format("Process [%s] for command [%s] timed out.", processPid, commandLine));
326-
}
342+
_logger.warn(String.format("Process [%s] for command [%s] timed out. Output is [%s].", processPid,
343+
commandLine, timedoutTask.getResult()));
327344

328345
return ERR_TIMEOUT;
329346
}
330347

331-
_logger.debug(String.format("Exit value of process [%s] for command [%s] is [%s].", processPid, commandLine, _process.exitValue()));
348+
_logger.debug(String.format("Exit value of process [%s] for command [%s] is [%s].", processPid,
349+
commandLine, _process.exitValue()));
332350

333351
BufferedReader reader = new BufferedReader(new InputStreamReader(_process.getInputStream()), 128);
334352

@@ -339,19 +357,24 @@ public String execute(OutputInterpreter interpreter) {
339357
error = String.valueOf(_process.exitValue());
340358
}
341359

342-
_logger.warn(String.format("Process [%s] for command [%s] encountered the error: [%s].", processPid, commandLine, error));
360+
_logger.warn(String.format("Process [%s] for command [%s] encountered the error: [%s].", processPid,
361+
commandLine, error));
343362

344363
return error;
345364
} catch (SecurityException ex) {
346-
_logger.warn(String.format("Exception [%s] occurred. This may be due to an attempt of executing command [%s] as non root.", ex.getMessage(), commandLine),
365+
_logger.warn(String.format(
366+
"Exception [%s] occurred. This may be due to an attempt of executing command [%s] as non root.",
367+
ex.getMessage(), commandLine),
347368
ex);
348369
return stackTraceAsString(ex);
349370
} catch (Exception ex) {
350-
_logger.warn(String.format("Exception [%s] occurred when attempting to run command [%s].", ex.getMessage(), commandLine), ex);
371+
_logger.warn(String.format("Exception [%s] occurred when attempting to run command [%s].",
372+
ex.getMessage(), commandLine), ex);
351373
return stackTraceAsString(ex);
352374
} finally {
353375
if (_process != null) {
354-
_logger.trace(String.format("Destroying process [%s] for command [%s].", _process.pid(), commandLine));
376+
_logger.trace(
377+
String.format("Destroying process [%s] for command [%s].", _process.pid(), commandLine));
355378
IOUtils.closeQuietly(_process.getErrorStream());
356379
IOUtils.closeQuietly(_process.getOutputStream());
357380
IOUtils.closeQuietly(_process.getInputStream());
@@ -362,9 +385,10 @@ public String execute(OutputInterpreter interpreter) {
362385

363386
public String executeIgnoreExitValue(OutputInterpreter interpreter, int exitValue) {
364387
String[] command = _command.toArray(new String[_command.size()]);
388+
String commandLine = buildCommandLine(command);
365389

366390
if (_logger.isDebugEnabled()) {
367-
_logger.debug(String.format("Executing: %s", buildCommandLine(command).split(KeyStoreUtils.KS_FILENAME)[0]));
391+
_logger.debug(String.format("Executing: %s", commandLine));
368392
}
369393

370394
try {
@@ -375,7 +399,7 @@ public String executeIgnoreExitValue(OutputInterpreter interpreter, int exitValu
375399

376400
_process = pb.start();
377401
if (_process == null) {
378-
_logger.warn(String.format("Unable to execute: %s", buildCommandLine(command)));
402+
_logger.warn(String.format("Unable to execute: %s", commandLine));
379403
return String.format("Unable to execute the command: %s", command[0]);
380404
}
381405

@@ -439,11 +463,8 @@ public String executeIgnoreExitValue(OutputInterpreter interpreter, int exitValu
439463
Task timedoutTask = new Task(log, ir);
440464

441465
timedoutTask.run();
442-
if (!_passwordCommand) {
443-
_logger.warn(String.format("Timed out: %s. Output is: %s", buildCommandLine(command), timedoutTask.getResult()));
444-
} else {
445-
_logger.warn(String.format("Timed out: %s", buildCommandLine(command)));
446-
}
466+
_logger.warn(String.format("Timed out: %s. Output is: %s", commandLine,
467+
timedoutTask.getResult()));
447468

448469
return ERR_TIMEOUT;
449470
}
@@ -467,7 +488,7 @@ public String executeIgnoreExitValue(OutputInterpreter interpreter, int exitValu
467488
_logger.warn("Security Exception....not running as root?", ex);
468489
return stackTraceAsString(ex);
469490
} catch (Exception ex) {
470-
_logger.warn(String.format("Exception: %s", buildCommandLine(command)), ex);
491+
_logger.warn(String.format("Exception: %s", commandLine), ex);
471492
return stackTraceAsString(ex);
472493
} finally {
473494
if (_process != null) {
@@ -516,9 +537,9 @@ public void run() {
516537
} catch (Exception ex) {
517538
result = stackTraceAsString(ex);
518539
} finally {
519-
done = true;
520-
notifyAll();
521-
IOUtils.closeQuietly(reader);
540+
done = true;
541+
notifyAll();
542+
IOUtils.closeQuietly(reader);
522543
}
523544
}
524545
}

utils/src/test/java/com/cloud/utils/script/ScriptTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,34 @@ public void testGetExecutableAbsolutePath() {
7878
String result = Script.getExecutableAbsolutePath("ls");
7979
Assert.assertTrue(List.of("/usr/bin/ls", "/bin/ls").contains(result));
8080
}
81+
82+
@Test
83+
public void testBuildCommandLineWithSensitiveData() {
84+
Script script = new Script("test.sh");
85+
script.add("normal-arg");
86+
script.addSensitive("sensitive-arg");
87+
String commandLine = script.toString();
88+
Assert.assertEquals("test.sh normal-arg ****** ", commandLine);
89+
}
90+
91+
@Test
92+
public void testBuildCommandLineWithMultipleSensitiveData() {
93+
Script script = new Script("test.sh");
94+
script.add("normal-arg");
95+
script.addSensitive("sensitive-arg1");
96+
script.add("another-normal-arg");
97+
script.addSensitive("sensitive-arg2");
98+
String commandLine = script.toString();
99+
Assert.assertEquals("test.sh normal-arg ****** another-normal-arg ****** ", commandLine);
100+
}
101+
102+
@Test
103+
public void testBuildCommandLineWithLegacyPasswordOption() {
104+
Script script = new Script("test.sh");
105+
script.add("-y");
106+
script.add("legacy-password");
107+
String commandLine = script.toString();
108+
Assert.assertEquals("test.sh -y ****** ", commandLine);
109+
}
110+
81111
}

0 commit comments

Comments
 (0)