Conversation
|
|
||
| async def parse_remote(url: str): | ||
| async with httpx.AsyncClient() as c: | ||
| file = await c.get(url) |
Check failure
Code scanning / CodeQL
Full server-side request forgery
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 9 months ago
To fix this SSRF vulnerability, you should restrict the set of URLs that can be accessed via the url parameter. The best way is to maintain a whitelist of allowed domains or base URLs, and only allow requests to those. If the set of allowed domains is small and known (e.g., trusted update servers), you can check that the parsed domain of the user-provided URL matches one of the allowed domains before making the request. If you must allow arbitrary domains, you should at least block requests to private IP ranges and sensitive endpoints (such as localhost, 127.0.0.1, 169.254.169.254, etc.).
The changes should be made in goosebit/updates/swdesc/__init__.py, specifically in the parse_remote function. You will need to:
- Parse the URL and check that its hostname is in a whitelist (e.g., a list of allowed domains).
- If not, raise an exception and do not make the request.
- Add any necessary imports for URL parsing (e.g.,
urllib.parse).
You should also add a whitelist definition at the top of the file, or as a constant, and use it in the validation.
| @@ -3,21 +3,35 @@ | ||
| import aiofiles | ||
| import httpx | ||
| from anyio import Path, open_file | ||
| from urllib.parse import urlparse | ||
|
|
||
| from ...db.models import SoftwareImageFormat | ||
| from . import rauc, swu | ||
|
|
||
| # Whitelist of allowed domains for remote software updates | ||
| ALLOWED_DOMAINS = { | ||
| "trusted-updates.example.com", | ||
| "updates.example.org", | ||
| # Add other trusted domains here | ||
| } | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| async def parse_remote(url: str): | ||
| parsed = urlparse(url) | ||
| if parsed.scheme not in ("http", "https"): | ||
| logger.warning(f"Blocked non-http(s) scheme in remote URL: {url}") | ||
| raise ValueError("Only http(s) URLs are allowed for remote software updates") | ||
| if parsed.hostname not in ALLOWED_DOMAINS: | ||
| logger.warning(f"Blocked remote URL with disallowed domain: {parsed.hostname}") | ||
| raise ValueError("Remote software update URL domain is not allowed") | ||
| async with httpx.AsyncClient() as c: | ||
| file = await c.get(url) | ||
| async with aiofiles.tempfile.NamedTemporaryFile("w+b") as f: | ||
| await f.write(file.content) | ||
| return await parse_file(Path(str(f.name))) | ||
|
|
||
|
|
||
| async def parse_file(file: Path): | ||
| async with await open_file(file, "r+b") as f: | ||
| magic = await f.read(4) |
tsagadar
left a comment
There was a problem hiding this comment.
Not sure if it is a bit too aggressive to already add RAUC support. It is not only about the file format but also about being able to document / test its usage. I'd expect minor differences in comparison with SWUpdate.
Some more open things
- Adding db migrations (as discussed in #133)
- Adjusting documentation
- Exposing image type in UI? Currently the type is stored but never used
- Squash the "[pre-commit.ci]" commit? Or is the idea not to run the code formatting tools and have a lot of those commits on main?
4a48a30 to
ff3f48e
Compare
|
I think it is a good idea to support RAUC as long as we don’t have to completely refactor the application at this point. IMHO we should focus on making what we have production-ready and then go from there. |
I agree here. This was relatively easy to throw together, so if we don't want to add this right now I will leave as a draft for reference. |
|
Another thing I realized today: goosebit does log message parsing (to detect download progress / update status) - this also would require adjustments. However, the parsing ideally gets reduced to only extract the progress. |
|
Hello! |
Not entirely sure. Our main goal was to ensure that gooseBit as a whole is production ready before we attempt to add complexity with something like this. If you are able to provide log examples that I can work on parsing with this we likely could add it, but I think there also needs to be consideration made as to how we track which files are which types, and which devices want what type of updates. |
I understand. However isn't it the job of the update manager to know what files are supported by what devices? Since goosebit is really just a way to bring that file to the device / decide what devices will receive what updates. The only time it has to do something with the file type is when it tries to read the header for information about the uploaded update, nothing more; which was accounted for in those two commits here. |
I think partially, yes. I worry about edge cases, like what if a user has 2 devices, one which supports RAUC and one which supports SWUpdate, and the user uploads 2 files with the same versioning? It's a good idea to be at least partially aware of this information, if we can save the user from having the device download invalid updates I think that is a good idea. Curious what others think here though, I have no opposition to merging this as-is, but we should deliberate. |
|
I think it is fine to push this forward. I have started to whip up a device Docker image for RAUC, so we could even have E2E tests. |
ff3f48e to
57a5ab0
Compare
57a5ab0 to
3d60c98
Compare
3d60c98 to
c3407de
Compare
With my Docker-based demo setup this seems to work out of the box. I see the following: Here the container's log output during an update: |
|
If you are happy with my changes, feel free to squash all 3 commits into 1. |
|
The RAUC docs use |
4da243e to
2d1875b
Compare
|
This all looks good to me, we can add log parsing at a later time. I won't be able to do anything on this until next week, as I am away this week, but this seems good to merge. |
OK, I will finish the PR then. As mentioned here, log parsing seems to work just fine. |
2d1875b to
338d694
Compare
|
@b-rowan needs your approval to merge |
338d694 to
01f3f2e
Compare
|
Allow parsing of RAUC files using `PySquashFsImage`.
01f3f2e to
3dbc788
Compare
easybe
left a comment
There was a problem hiding this comment.
Moved the test to the correct location and adapted it to my latest changes.
|
@Tristoris, with the latest release we now have RAUC support. Let us know if that works for you. |
Hello. I am sorry, I did not see the notification and missed the message, I will get onto testing rightaway! |

Allow parsing of RAUC files using
PySquashFsImage.Closes #131