diff --git a/History.md b/History.md index d7f8562537..927fe4a1b5 100644 --- a/History.md +++ b/History.md @@ -10,6 +10,7 @@ * Increases maximum URI path length from 2048 to 8196 bytes (#2167) * Force shutdown responses can be overridden by using the `lowlevel_error_handler` config (#2203) * Faster phased restart and worker timeout (#2121) + * New configuration option to set state file permissions (#2238) * Deprecations, Removals and Breaking API Changes * `Puma.stats` now returns a Hash instead of a JSON string (#2086) @@ -49,6 +50,8 @@ * JSON parse cluster worker stats instead of regex (#2124) * Support parallel tests in verbose progress reporting (#2223) +* Security + ## 4.3.3 and 3.12.4 / 2020-02-28 * Bugfixes diff --git a/lib/puma/dsl.rb b/lib/puma/dsl.rb index 9bc51f77aa..4ad135eea4 100644 --- a/lib/puma/dsl.rb +++ b/lib/puma/dsl.rb @@ -399,6 +399,14 @@ def state_path(path) @options[:state] = path.to_s end + # Use +permission+ to restrict permissions for the state file. + # + # @example + # state_permission 0600 + def state_permission(permission) + @options[:state_permission] = permission + end + # How many worker processes to run. Typically this is set to # the number of available cores. # diff --git a/lib/puma/launcher.rb b/lib/puma/launcher.rb index 241546b36d..0c4e1dd304 100644 --- a/lib/puma/launcher.rb +++ b/lib/puma/launcher.rb @@ -102,6 +102,7 @@ def write_state write_pid path = @options[:state] + permission = @options[:state_permission] return unless path require 'puma/state_file' @@ -111,7 +112,7 @@ def write_state sf.control_url = @options[:control_url] sf.control_auth_token = @options[:control_auth_token] - sf.save path + sf.save path, permission end # Delete the configured pidfile diff --git a/lib/puma/state_file.rb b/lib/puma/state_file.rb index e49f7e5a74..53a2bfeaf9 100644 --- a/lib/puma/state_file.rb +++ b/lib/puma/state_file.rb @@ -8,8 +8,9 @@ def initialize @options = {} end - def save(path) + def save(path, permission = nil) File.write path, YAML.dump(@options) + File.chmod(permission, path) if permission end def load(path)