Hacker News new | ask | show | jobs
by technion 1087 days ago
OK hear me out: a Linux capability like option that removes the .. option from the kernels file name parser.

Like web apps have been seen various bypasses involving somehow smuggling two dots somewhere since we were on dial up modems. It's time to look for a way to close this once and for all, as the Linux kernel has done with several other classes of user land bugs.

6 comments

https://man7.org/linux/man-pages/man2/openat2.2.html RESOLVE_BENEATH

(FreeBSD has this in ordinary openat(2) as O_RESOLVE_BENEATH.)

That would break so many things that it would be insane to do.

You could just run nginx as a separate user with very limited rights, or just run it on Docker. This, plus updating regularly usually fixes 90% of security issues.

Most (I hope all) distributions already run nginx as a separate user. It's best practice.

But that won't help if you alias to "/foo/bar/www" and the the application has a SQLite database at "/foo/bar/db.db", which the nginx user has to have access to. Same if you run it in a container (or lock down permissions using systemd).

There is no reason the web server needs to have access to the database file, the application that needs it should be running under a different user.
If that's an option then that's the right way to go. There is a reason some MTAs have been doing something like this for decades now (I'm thinking of qmail).

To be honest, I'm not sure if it's even possible to run the application/interpreter/cgi (e.g. php) as a child of the nginx process - though with Apache I'm still seeing that occasionally.

But the issue is -- would it break the things a web server is doing? It doesn't have to be a universal solution.

    /some/../path 
should pretty much 100% of the time be disallowed, there is no sensible use case that is not "someone wrote ugly code"

../some/path makes sense sometimes at least

... but I'd imagine it wouldn't as useful as you think it is, because many apps resolve .. before passing it to the OS

I don't agree. Those kinds of paths are often result of concatenation of several configuration options. Like APP_DIR=/some/app/bin; LOG_DIR="$APP_DIR/../logs". And APP_DIR comes to you from distro scripts, so you're not going to fork those scripts and support your own fork across updates, you just build upon those scripts.
The whole point of having an APP_DIR option is so that you can change it and things will just keep working. By doing $APP_DIR/.. you invalidate that by making assumptions about the parent structure. In particular something that could easily happen in the future is that you may not have write access to "$APP_DIR/.." You gotta do what you gotta do, but it is smelly.
Then you have fucked up your app config.

If user gives your app a directory to play with, exiting that dir via ../something is the last thing you should do, it's horrible malpractice that just causes annoyance

"distro scripts" near always just show direct path to /var/lib/something for data and /usr/something for rest.

That makes no difference. Code often normalizes paths before they ever touch the filesystem API
It's something else in the kernel, there we have the permission system which we rely on.

If you are serving files to web from the folder, the web framework should handle not taversing the public root folder it was tasked to serve. If are rolling your own, well now you have to consider all kinds of stuff, including this.

I don't think this would have prevented it. Removing ".." segments from paths is part of URL parsing and required by the HTTP specification. Nginx very likely does this too.