1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 10:57:35 +00:00

Shell: Fix a TOCTOU in popd by simplifying it

This builtin was doing a lot of redundant work, including doing a stat()
followed by a chdir(), when just a chdir() would suffice.

SonarCloud: https://sonarcloud.io/project/issues?id=SerenityOS_serenity&issues=AXuVPAHNk92xXUF3qTNb&open=AXuVPAHNk92xXUF3qTNb
This commit is contained in:
Andreas Kling 2021-08-30 13:16:48 +02:00
parent 69d3bf0d12
commit 47420e72b8

View file

@ -663,54 +663,23 @@ int Shell::builtin_popd(int argc, const char** argv)
}
bool should_not_switch = false;
String path = directory_stack.take_last();
Core::ArgsParser parser;
parser.add_option(should_not_switch, "Do not switch dirs", "no-switch", 'n');
if (!parser.parse(argc, const_cast<char**>(argv), Core::ArgsParser::FailureBehavior::PrintUsage))
return 1;
bool should_switch = !should_not_switch;
auto popped_path = directory_stack.take_last();
// When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory.
if (argc == 1) {
int rc = chdir(path.characters());
if (rc < 0) {
warnln("chdir({}) failed: {}", path, strerror(errno));
return 1;
}
cwd = path;
if (should_not_switch)
return 0;
}
LexicalPath lexical_path(path.characters());
const char* real_path = lexical_path.string().characters();
struct stat st;
int rc = stat(real_path, &st);
if (rc < 0) {
warnln("stat({}) failed: {}", real_path, strerror(errno));
auto new_path = LexicalPath::canonicalized_path(popped_path);
if (chdir(new_path.characters()) < 0) {
warnln("chdir({}) failed: {}", new_path, strerror(errno));
return 1;
}
if (!S_ISDIR(st.st_mode)) {
warnln("Not a directory: {}", real_path);
return 1;
}
if (should_switch) {
int rc = chdir(real_path);
if (rc < 0) {
warnln("chdir({}) failed: {}", real_path, strerror(errno));
return 1;
}
cwd = lexical_path.string();
}
cwd = new_path;
return 0;
}