diff --git a/src/common/system/linux_headers_utils.cc b/src/common/system/linux_headers_utils.cc new file mode 100644 index 00000000000..2e2ca144c0a --- /dev/null +++ b/src/common/system/linux_headers_utils.cc @@ -0,0 +1,78 @@ +/* + * Copyright 2018- The Pixie Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "src/common/system/linux_headers_utils.h" + +#include +#include +#include +#include + +#include "src/common/base/file.h" +#include "src/common/fs/fs_wrapper.h" +#include "src/common/system/config.h" + +namespace px { +namespace system { + +StatusOr ResolvePossibleSymlinkToHostPath(const std::filesystem::path p) { + // Check if "p" is a symlink. + std::error_code ec; + const bool is_symlink = std::filesystem::is_symlink(p, ec); + if (ec) { + return error::NotFound(absl::Substitute("Did not find the host headers at path: $0, $1.", + p.string(), ec.message())); + } + + if (!is_symlink) { + // Not a symlink, we are good now. + return p; + } + + // Resolve the symlink, and re-convert to a host path.. + const std::filesystem::path resolved = std::filesystem::read_symlink(p, ec); + if (ec) { + return error::Internal(ec.message()); + } + + // Relative paths containing "../" can result in an invalid host mount path when using + // ToHostPath. Therefore, we need to treat the absolute and relative cases differently. + std::filesystem::path resolved_host_path; + if (resolved.is_absolute()) { + resolved_host_path = system::Config::GetInstance().ToHostPath(resolved); + VLOG(1) << absl::Substitute( + "Symlink target is an absolute path. Converting that to host path: $0 -> $1.", + resolved.string(), resolved_host_path.string()); + } else { + resolved_host_path = p.parent_path(); + resolved_host_path /= resolved.string(); + VLOG(1) << absl::Substitute( + "Symlink target is a relative path. Concatenating it to parent directory: $0", + resolved_host_path.string()); + } + + // Downstream won't be ok unless the resolved host path exists; return an error if needed. + if (!fs::Exists(resolved_host_path)) { + return error::NotFound(absl::Substitute("Did not find host headers at resolved path: $0.", + resolved_host_path.string())); + } + return resolved_host_path; +} + +} // namespace system +} // namespace px diff --git a/src/common/system/linux_headers_utils.h b/src/common/system/linux_headers_utils.h new file mode 100644 index 00000000000..28b6018f349 --- /dev/null +++ b/src/common/system/linux_headers_utils.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018- The Pixie Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#include "src/common/base/base.h" + +namespace px { +namespace system { + +/** + * Resolves a possible symlink path to its corresponding host filesystem path. + * + * This function takes a filesystem path and checks if it is a symbolic link. If it is, + * the symlink is resolved to its target path. Depending on whether the target is an absolute + * or relative path, it is further processed to convert it into a valid host path (as in + * Config::ToHostPath(...) path). + * + * If the input path is not a symlink, it is returned as-is. The function ensures that + * the final resolved path exists in the host filesystem before returning it. Errors are + * returned when the path does not exist, the resolution fails, or when there is an issue + * accessing the filesystem. + */ +StatusOr ResolvePossibleSymlinkToHostPath(const std::filesystem::path p); + +} // namespace system +} // namespace px diff --git a/src/stirling/utils/linux_headers.cc b/src/stirling/utils/linux_headers.cc index 75cbff9fe56..e86a996dded 100644 --- a/src/stirling/utils/linux_headers.cc +++ b/src/stirling/utils/linux_headers.cc @@ -31,6 +31,7 @@ #include "src/common/fs/temp_file.h" #include "src/common/minitar/minitar.h" #include "src/common/system/config.h" +#include "src/common/system/linux_headers_utils.h" #include "src/common/system/proc_pid_path.h" #include "src/common/zlib/zlib_wrapper.h" @@ -209,55 +210,11 @@ Status FindLinuxHeadersDirectory(const std::filesystem::path& lib_modules_dir) { return error::NotFound("Could not find 'source' or 'build' under $0.", lib_modules_dir.string()); } -StatusOr ResolvePossibleSymlinkToHostPath(const std::filesystem::path p) { - // Check if "p" is a symlink. - std::error_code ec; - const bool is_symlink = std::filesystem::is_symlink(p, ec); - if (ec) { - return error::NotFound(absl::Substitute("Did not find the host headers at path: $0, $1.", - p.string(), ec.message())); - } - - if (!is_symlink) { - // Not a symlink, we are good now. - return p; - } - - // Resolve the symlink, and re-convert to a host path.. - const std::filesystem::path resolved = std::filesystem::read_symlink(p, ec); - if (ec) { - return error::Internal(ec.message()); - } - - // Relative paths containing "../" can result in an invalid host mount path when using - // ToHostPath. Therefore, we need to treat the absolute and relative cases differently. - std::filesystem::path resolved_host_path; - if (resolved.is_absolute()) { - resolved_host_path = system::Config::GetInstance().ToHostPath(resolved); - VLOG(1) << absl::Substitute( - "Symlink target is an absolute path. Converting that to host path: $0 -> $1.", - resolved.string(), resolved_host_path.string()); - } else { - resolved_host_path = p.parent_path(); - resolved_host_path /= resolved.string(); - VLOG(1) << absl::Substitute( - "Symlink target is a relative path. Concatenating it to parent directory: $0", - resolved_host_path.string()); - } - - // Downstream won't be ok unless the resolved host path exists; return an error if needed. - if (!fs::Exists(resolved_host_path)) { - return error::NotFound(absl::Substitute("Did not find host headers at resolved path: $0.", - resolved_host_path.string())); - } - return resolved_host_path; -} - Status LinkHostLinuxHeadersKernel(const std::filesystem::path& lib_modules_dir) { const auto host_path = system::Config::GetInstance().ToHostPath(lib_modules_dir); LOG(INFO) << absl::Substitute("Looking for host Linux headers at $0.", host_path.string()); - PX_ASSIGN_OR_RETURN(const auto resolved_host_path, ResolvePossibleSymlinkToHostPath(host_path)); + PX_ASSIGN_OR_RETURN(const auto resolved_host_path, system::ResolvePossibleSymlinkToHostPath(host_path)); PX_RETURN_IF_ERROR(fs::CreateSymlinkIfNotExists(resolved_host_path, lib_modules_dir)); LOG(INFO) << absl::Substitute("Linked host headers at $0 to symlink in pem namespace at $1.", resolved_host_path.string(), lib_modules_dir.string());