Skip to content
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

Fixes #24631 - httpboot module #605

Merged
merged 1 commit into from
Aug 24, 2018
Merged

Conversation

lzap
Copy link
Member

@lzap lzap commented Aug 16, 2018

New module for nicer UEFI HTTP BOOT implementation:

theforeman/foreman#5950

Please pay extra attention to security during review. I tested with paths like '/EFI/../../../etc/passwd' or similar. Directory listing is not allowed. Symlinks are followed by design and they are followed even outside of TFTP directory. Not sure if this is a problem, we can limit that tho if needed.

Copy link
Member

@stbenjam stbenjam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tried end-to-end yet, but the proxy module looks good itself. I couldn't get it to do any nefarious traversals using the common tricks, sinatra seems pretty smart.


get "/*" do
file = Pathname.new(params[:splat].first).cleanpath
real_file = Pathname.new(File.join(Proxy::TFTP::Plugin.settings.tftproot, file)).realpath
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be Proxy::Httpboot::Plugin.settings.root_dir instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if you get /EFI or a non-existent file, we return 500. It'd be nice if we return the right http error codes, 404, 503, etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, yeah absolutely 404. Changing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I am implementing extra verbose checks just to be sure.

Copy link
Member

@timogoebel timogoebel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Note, that tests are missing.

helpers ::Proxy::Helpers

get "/*" do
file = Pathname.new(params[:splat].first).cleanpath
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this safe to prevent ../../../etc/shadow ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sinatra filters it out, among other tricky ways to do path traversal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep I tested this, but I was wondering if we should allow following symlinks outside of TFTP root directory.

I can prevent from both possible security issues by comparing absolute file path with root directory - if it's not the same then we have an error. You know what, let me do that, just for case. I don't want my name on a CVE like this :-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am doing this, we can't be sure if e.g. older version of Sinatra does this.

@lzap
Copy link
Member Author

lzap commented Aug 17, 2018

I have amended the last commit, thank you for review.

@stbenjam
Copy link
Member

stbenjam commented Aug 21, 2018

Looks good, but a few notes. First, smart Proxy is returning a Server header with no value:

[vagrant@centos7-devel ~]$ curl -I http://192.168.73.1:7000/httpboot/grub2/grubx64.efi
HTTP/1.1 200 OK 
Content-Type: application/octet-stream
Server: 
Last-Modified: Tue, 21 Aug 2018 20:59:12 GMT
Content-Length: 1107968
X-Content-Type-Options: nosniff
Date: Tue, 21 Aug 2018 21:06:26 GMT
Connection: Keep-Alive

This is not valid although most things seem happy to accept it except the edk2 firmware which causes it to freeze. That took a better part of the afternoon to figure out why my vm was locking up.

Can you add that to the smart proxy somewhere?

@stbenjam
Copy link
Member

stbenjam commented Aug 21, 2018

The other thing is how grub2 doesn't handle relative paths (https://bugzilla.redhat.com/show_bug.cgi?id=1616395). I have a proposed fix to grub2, but even then relative paths (e.g. boot/centos7-vmlinuz or whatever) will be relative to the EFI image, e.g. the grub2 folder in our default set up. Users will need a symlink /var/lib/tftpboot/grub2/boot -> /var/lib/tftpboot/boot (which the installer can do unless you have another idea).

@lzap
Copy link
Member Author

lzap commented Aug 23, 2018

Thanks rebased, it was intentionally set to blank but I explained why we add this back: https://projects.theforeman.org/issues/14394

Copy link
Member

@stbenjam stbenjam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested, works great

---
# Enable publishing of a given directory under /EFI and /httpboot paths.
# Directory listing is not possible, symlinks are followed but not outside
# of the rood directory specified in this file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: typoroot

@@ -50,7 +50,7 @@ def http_app(http_port, plugins = http_plugins)
:DoNotListen => true,
:Port => http_port, # only being used to correctly log http port being used
:Logger => ::Proxy::LogBuffer::Decorator.instance,
:ServerSoftware => '',
:ServerSoftware => "foreman-proxy/#{Proxy::VERSION}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's common security practice to not publish the software versions. Do we need this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a common practice in the enterprise, not in the open source world I'd say. But to the point - we do advertise the same via /features endpoint anyway. And we must not remove this - Foreman now checks foreman version and shows you a warning for compatibility.

If this is a major concern, please file a RM issue to encrypt the version or something like that. But I guess all we can do is obscurity not security in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, fair enough.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to see it as a separate commit. It's not obvious that this is part of the httpboot and I wouldn't look at this commit in git log if I was looking for the change.

# Directory listing is not possible, symlinks are followed but not outside
# of the rood directory specified in this file.

# Enables the module, make sure to enable TFTP module as well to allow
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use requires in the plugin spec to make sure the tftp module is loaded.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh cool this one was exactly what I was looking for. Thanks.

@lzap
Copy link
Member Author

lzap commented Aug 24, 2018

Thanks amended the two things.

@timogoebel timogoebel merged commit 8af0137 into theforeman:develop Aug 24, 2018
@timogoebel
Copy link
Member

Thanks, @lzap and @stbenjam.

@@ -50,7 +50,7 @@ def http_app(http_port, plugins = http_plugins)
:DoNotListen => true,
:Port => http_port, # only being used to correctly log http port being used
:Logger => ::Proxy::LogBuffer::Decorator.instance,
:ServerSoftware => '',
:ServerSoftware => "foreman-proxy/#{Proxy::VERSION}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to see it as a separate commit. It's not obvious that this is part of the httpboot and I wouldn't look at this commit in git log if I was looking for the change.

require 'httpboot/httpboot_plugin'
require 'httpboot/httpboot_api'

ENV['RACK_ENV'] = 'test'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels weird to set an env var here. Is this needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy pasted from other file, thought it's required.

@lzap
Copy link
Member Author

lzap commented Aug 27, 2018

I did not want to do this in a separate commit, this might be backported (as it's new module and there cannot be regressions). The feature does not work end-to-end without this.

@lzap lzap deleted the httpboot-24631 branch August 27, 2018 15:29
@ekohl
Copy link
Member

ekohl commented Aug 27, 2018

How does the code not work without it? Does the client reject empty server strings?

@stbenjam
Copy link
Member

stbenjam commented Aug 27, 2018

How does the code not work without it? Does the client reject empty server strings?

It would work fine without it (or at least I would guess so), but Sinatra sends Server: as the header. This breaks the UEFI firmware that Qemu uses: https://bugzilla.tianocore.org/show_bug.cgi?id=1102.

I didn't look at the code, but I would guess the HTTP client does a strchr on space or something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants