-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
fix(cli) handle race condition in changing env perms #3057
Conversation
kong/cmd/utils/prefix_handler.lua
Outdated
if not ok then | ||
log.warn("Unable to set kong env permissions: ", err) | ||
return false, err |
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.
This function returns nil
on error. Could we preserve this behavior?
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.
Ah yep, my mistake.
kong/plugins/file-log/handler.lua
Outdated
@@ -17,10 +17,6 @@ local S_IROTH = system_constants.S_IROTH() | |||
local oflags = bit.bor(O_WRONLY, O_CREAT, O_APPEND) | |||
local mode = bit.bor(S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH) | |||
|
|||
ffi.cdef[[ | |||
int write(int fd, const void * ptr, int numbytes); |
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.
It is a bold bet to move this away from this plugin and into a remote "utility" module. A future change could easily break this, say if the core splits the utils.lua
module and the FFI cdef
isn't loaded anymore on the code path followed by the core up to the file-log
plugin execution... Ideally this would be standardized and implemented in a more robust fashion (Plugins API?) so that the core comes with an FFI cdef
definition that other plugins are assured they can use.
Thoughts?
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.
There is precedent for moving FFI cdefs into this module (we did this when we update the random bytes function to read from urandom). Having said that, I'm not opposed to moving all cdefs into a separate module. Currently we only call ffi.cdef
in this module. I'm sure this could be standardized and implemented robustly as part of a plugins API. Is that the scope here? I can create a separate module like kong/tools/cdefs.lua
or some such if that would help assuage your concerns here.
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.
Could we just ffi.cdef
the write
function is both places and avoid this issue altogether? Makes the plugin more self-contained (and we'll revisit the topic of exported functionality anyway when we do the Plugin API and do the eventual cleanup if it's the case). AFAIK (and my quick tests showed) LuaJIT doesn't have a problem with duplicated cdefs.
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.
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.
Ouch, is it? I didn't find it in the docs and didn't seem to bark on my tests, but I know all safety guarantees are off the window when it comes to the FFI.
Still, this looks real odd: this means when using two third-party FFI-based modules, one can only hope that they are not using the same C functions internally? Ew.
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.
Ok, I must be sniffing glue. calling cdef
in the module scope lets require
take care of not executing the def multiple times. I swear I didn't (did) have the problem before... ill revert this change and do some more digging
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.
calling cdef in the module scope lets require take care of not executing the def multiple times.
What I meant was not two modules calling the same FFI-using module, but two modules calling two different third-party FFI modules which happen to declare open
(require
won't protect that).
b835a91
to
6e82457
Compare
(update PR name and synopsis based on rv comments) |
kong/tools/utils.lua
Outdated
@@ -48,6 +48,7 @@ const char *ERR_reason_error_string(unsigned long e); | |||
|
|||
int open(const char * filename, int flags, int mode); | |||
size_t read(int fd, void *buf, size_t count); | |||
int write(int fd, const void * ptr, int numbytes); |
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.
Slightly pedantic, but eventually we should probably agree upon asterisk placement for pointers in the function prototypes we put in ffi.cdef
.
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.
Ah yep. This was a copypasta. I agree, I don't like the whitespace between the defer op and the symbol. Fixed.
6e82457
to
932ec4c
Compare
local c = require "lua_system_constants" | ||
|
||
local flags = bit.bor(c.O_CREAT(), c.O_WRONLY()) | ||
local mode = bit.bor(c.S_IRUSR(), c.S_IWUSR(), c.S_IRGRP()) |
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.
pedantic as well since we are dealing with cold code path for now, but since we are doing a require
and identical bitwise computation on every call, maybe we could cache those in a lexical do .. end
block around the function. Not a blocker though of course...
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.
So this should be compared as a performance vs. readability condition. I'd argue the current format is more readable (what I was going for); performance is not a concern here at all. Happy to adjust this this if needed.
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.
Oh really? I personally find it more readable if the function's body is only executing code based on its input, and if all invariant code is left out. But no, no performance concern here, so I think this is fine as is if you prefer this form 👍
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.
Pedantic comment:
maybe we could cache those in a lexical
do .. end
block around the function
This is not a cache, but a localization trick for the compiler (transpiler?), to my understanding. To get a bit pedantic, I would say a do ... end
block is harder to read, mentally, so the current form is acceptable. But, I am 100% on board with writing referential code, e.g., code that can be used for style/perf references in the future, so I'm happy to make adjustments. We're getting quite "weedy" here? A good point for discussions, though 👍 I have no strong feeling either way, given this is a cold path and we are noting non-functional differences.
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.
But, I am 100% on board with writing referential code
Yep, this is very much my goal most of the time when pointing those out.
kong/cmd/utils/prefix_handler.lua
Outdated
local fd = ffi.C.open(path, flags, mode) | ||
if fd < 0 then | ||
local errno = ffi.errno() | ||
return nil, "Unable to open env path " .. path .. " (" .. |
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.
Ok, this is going to be very pedantic, but: this is the only capitalized error message returned by this function. Other messages are lower-cased (as are or should be all other error messages in the codebase).
I said it would be pedantic! 😁
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.
Fixed! Nice 👀. We should indeed be consistent. Solid review 👍
This commit handles a potential vulnerability in how we secured the Kong env file. Previously we chmod'd the file after writing the contents via penlight's wrapper of the Lua io lib, which in turn uses stdio. This allowed for a miniscule window in which the file contents could be read (fopen() creates files with 0666 octal permissions, as modified by the processes's umask). The new behavior is to leverage the open() libc wrapper directly via FFI, which allows us to create the file with appropriate permissions from the outset.
932ec4c
to
fada84e
Compare
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.
LGTM!
Merging. I think the comments here serve as a good reference point for discussion. Glad to see this in :) |
Summary
Handle a potential vulnerability in how we secured the Kong env file. Previously we chmod'd the file after writing the contents via penlight's wrapper of the Lua io lib, which in turn uses stdio. This allowed for a miniscule window in which the file contents could be read (fopen() creates files with 0666 octal permissions, as modified by the processes's umask).
The new behavior is to leverage the open() libc wrapper directly via FFI, which allows us to create the file with appropriate permissions from the outset.
Full changelog
.kong_env
file via libc wrappers around open/write/read syscalls (via FFI)