-
Notifications
You must be signed in to change notification settings - Fork 2
Prevent path traversal fix #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,15 @@ | ||
| fsq (0.9.6) unstable; urgency=low | ||
|
|
||
| * Path comparison now using strncmp instead of for-loop. | ||
|
|
||
| -- Samuel Hasert <[email protected]> Mon, 08 Dec 2025 13:27:20 +0200 | ||
|
|
||
| fsq (0.9.5) unstable; urgency=low | ||
|
|
||
| * Absolute file path resolution to prevent path traversal exploit. | ||
|
|
||
| -- Samuel Hasert <[email protected]> Tue, 21 Oct 2025 16:25:15 +0200 | ||
|
|
||
| fsq (0.9.4) unstable; urgency=medium | ||
|
|
||
| * Support for IPv6. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,6 +62,12 @@ rm -rf %{buildroot} | |
|
|
||
| %changelog | ||
|
|
||
| * Mon 08 Dec 2025 Samuel Hasert <[email protected]> 0.9.6 | ||
| - Path comparison now using strncmp instead of for-loop. | ||
|
|
||
| * Tue 21 Oct 2025 Samuel Hasert <[email protected]> 0.9.5 | ||
| - Absolute file path resolution to prevent path traversal exploit. | ||
|
|
||
| * Fri 2 Aug 2024 Thomas Stibor <[email protected]> 0.9.4-1 | ||
| - Support for IPv6. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -700,21 +700,39 @@ static int write_access(struct fsq_session_t *fsq_session, char *lustre_dpath) | |||||||||||||||||||||||||||||||||||
| return rc; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /* File path name and Lustre directory name are matching | ||||||||||||||||||||||||||||||||||||
| up to the end of the Lustre directory name. */ | ||||||||||||||||||||||||||||||||||||
| /* Resolve path to absolute path */ | ||||||||||||||||||||||||||||||||||||
| char resolved[PATH_MAX]; | ||||||||||||||||||||||||||||||||||||
| char *output = realpath(fpath, resolved); | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
| char *output = realpath(fpath, resolved); | |
| char *output = realpath(fpath, resolved); | |
| if (output == NULL) { | |
| int rc = -errno; | |
| FSQ_ERROR(*fsq_session, rc, | |
| "realpath failed for fpath '%s'", fpath); | |
| return rc; | |
| } |
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential bug: If realpath() returns NULL (failure case), the output pointer will be NULL, and the LOG_DEBUG statement on line 707-708 will attempt to format it with %s, which could cause undefined behavior or a crash.
This reinforces the need for a NULL check immediately after the realpath() call before any use of output or resolved.
| char *output = realpath(fpath, resolved); | |
| char *output = realpath(fpath, resolved); | |
| if (output == NULL) { | |
| int rc = -errno; | |
| FSQ_ERROR(*fsq_session, rc, | |
| "realpath() failed for fpath '%s': %s", | |
| fpath, strerror(errno)); | |
| return rc; | |
| } |
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Misleading debug message: The LOG_DEBUG statement on line 712 still says it's verifying against fpath, but the actual verification below now uses the resolved path. Update the message to reflect this:
LOG_DEBUG("verify lustre_dpath '%s' is a strict prefix of resolved path '%s'",
lustre_dpath, resolved);| LOG_DEBUG("verify lustre_dpath '%s' is a strict prefix of fpath '%s'", | |
| lustre_dpath, fpath); | |
| LOG_DEBUG("verify lustre_dpath '%s' is a strict prefix of resolved path '%s'", | |
| lustre_dpath, resolved); |
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Unnecessary blank line before closing brace. This is inconsistent with the rest of the codebase style where error return blocks don't have extra blank lines (see lines 695-701 as an example).
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation: This code block uses spaces for indentation, but the rest of the file uses tabs (see lines 686-692, 695-701, etc.). This should be changed to use tabs to maintain consistency with the existing codebase style.
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential security vulnerability: The code resolves fpath to an absolute path but compares it against lustre_dpath which is NOT resolved. If lustre_dpath contains symbolic links, an attacker could potentially bypass the path traversal protection.
For example, if lustre_dpath = "/data/storage" but /data is actually a symlink to /other, the resolved fpath would be /other/storage/file.txt while lustre_dpath would still be /data/storage/, causing the comparison to fail even for legitimate paths, or worse, allowing paths under a different /data directory.
Consider resolving lustre_dpath to its canonical form as well before comparison:
char resolved_lustre[PATH_MAX];
char *lustre_output = realpath(lustre_dpath, resolved_lustre);
if (lustre_output == NULL) {
int rc = -errno;
FSQ_ERROR(*fsq_session, rc,
"realpath failed for lustre_dpath '%s'", lustre_dpath);
return rc;
}Then compare resolved against resolved_lustre instead.
Copilot
AI
Dec 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The path traversal fix in write_access() function lacks test coverage. Given the critical security nature of this change (preventing path traversal exploits), this should have automated tests to verify:
- Paths with
..components are properly rejected - Symlinks pointing outside the allowed directory are rejected
- Valid paths within the allowed directory are accepted
- Edge cases like paths exactly matching the lustre_dpath length
Consider adding security tests to src/test/ directory to ensure this vulnerability cannot be reintroduced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we check for an error here?