Unverified Commit 69b480cb authored by debing.sun's avatar debing.sun Committed by GitHub
Browse files

Hide user data from log (#13400)



This PR is based on the commits from PR #11747.

In the event of an assertion failure, hide command arguments from the
operator.

In some cases, private client information can be voluntarily exposed
when a redis instance crashes due to an assertion failure.
This commit prevent וnintentional client info exposure.
Operators can still access the hidden data, but they must actively
request it.
Any of the client info commands remains the unchanged.

### Config
Add a new config `hide-user-data-from-log` to turn this feature on and
off, default off.

---------
Co-authored-by: default avatarnaglera <anagler123@gmail.com>
Co-authored-by: default avatarnaglera <58042354+naglera@users.noreply.github.com>
parent b699e8bf
...@@ -389,6 +389,11 @@ databases 16 ...@@ -389,6 +389,11 @@ databases 16
# ASCII art logo in startup logs by setting the following option to yes. # ASCII art logo in startup logs by setting the following option to yes.
always-show-logo no always-show-logo no
# To avoid logging personal identifiable information (PII) into server log file,
# uncomment the following:
#
# hide-user-data-from-log yes
# By default, Redis modifies the process title (as seen in 'top' and 'ps') to # By default, Redis modifies the process title (as seen in 'top' and 'ps') to
# provide some runtime information. It is possible to disable this and leave # provide some runtime information. It is possible to disable this and leave
# the process name as executed by setting the following to no. # the process name as executed by setting the following to no.
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
* *
* Licensed under your choice of the Redis Source Available License 2.0 * Licensed under your choice of the Redis Source Available License 2.0
* (RSALv2) or the Server Side Public License v1 (SSPLv1). * (RSALv2) or the Server Side Public License v1 (SSPLv1).
*
* Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information.
*/ */
#include "server.h" #include "server.h"
...@@ -3090,6 +3092,7 @@ standardConfig static_configs[] = { ...@@ -3090,6 +3092,7 @@ standardConfig static_configs[] = {
createBoolConfig("latency-tracking", NULL, MODIFIABLE_CONFIG, server.latency_tracking_enabled, 1, NULL, NULL), createBoolConfig("latency-tracking", NULL, MODIFIABLE_CONFIG, server.latency_tracking_enabled, 1, NULL, NULL),
createBoolConfig("aof-disable-auto-gc", NULL, MODIFIABLE_CONFIG | HIDDEN_CONFIG, server.aof_disable_auto_gc, 0, NULL, updateAofAutoGCEnabled), createBoolConfig("aof-disable-auto-gc", NULL, MODIFIABLE_CONFIG | HIDDEN_CONFIG, server.aof_disable_auto_gc, 0, NULL, updateAofAutoGCEnabled),
createBoolConfig("replica-ignore-disk-write-errors", NULL, MODIFIABLE_CONFIG, server.repl_ignore_disk_write_error, 0, NULL, NULL), createBoolConfig("replica-ignore-disk-write-errors", NULL, MODIFIABLE_CONFIG, server.repl_ignore_disk_write_error, 0, NULL, NULL),
createBoolConfig("hide-user-data-from-log", NULL, MODIFIABLE_CONFIG, server.hide_user_data_from_log, 0, NULL, NULL),
/* String Configs */ /* String Configs */
createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL), createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL),
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* *
* Licensed under your choice of the Redis Source Available License 2.0 * Licensed under your choice of the Redis Source Available License 2.0
* (RSALv2) or the Server Side Public License v1 (SSPLv1). * (RSALv2) or the Server Side Public License v1 (SSPLv1).
*
* Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information.
*/ */
#include "server.h" #include "server.h"
...@@ -1067,6 +1069,11 @@ void _serverAssert(const char *estr, const char *file, int line) { ...@@ -1067,6 +1069,11 @@ void _serverAssert(const char *estr, const char *file, int line) {
bugReportEnd(0, 0); bugReportEnd(0, 0);
} }
/* Returns the amount of client's command arguments we allow logging */
int clientArgsToLog(const client *c) {
return server.hide_user_data_from_log ? 1 : c->argc;
}
void _serverAssertPrintClientInfo(const client *c) { void _serverAssertPrintClientInfo(const client *c) {
int j; int j;
char conninfo[CONN_INFO_LEN]; char conninfo[CONN_INFO_LEN];
...@@ -1077,6 +1084,10 @@ void _serverAssertPrintClientInfo(const client *c) { ...@@ -1077,6 +1084,10 @@ void _serverAssertPrintClientInfo(const client *c) {
serverLog(LL_WARNING,"client->conn = %s", connGetInfo(c->conn, conninfo, sizeof(conninfo))); serverLog(LL_WARNING,"client->conn = %s", connGetInfo(c->conn, conninfo, sizeof(conninfo)));
serverLog(LL_WARNING,"client->argc = %d", c->argc); serverLog(LL_WARNING,"client->argc = %d", c->argc);
for (j=0; j < c->argc; j++) { for (j=0; j < c->argc; j++) {
if (j >= clientArgsToLog(c)) {
serverLog(LL_WARNING,"client->argv[%d] = *redacted*",j);
continue;
}
char buf[128]; char buf[128];
char *arg; char *arg;
...@@ -1275,6 +1286,10 @@ static void* getAndSetMcontextEip(ucontext_t *uc, void *eip) { ...@@ -1275,6 +1286,10 @@ static void* getAndSetMcontextEip(ucontext_t *uc, void *eip) {
REDIS_NO_SANITIZE("address") REDIS_NO_SANITIZE("address")
void logStackContent(void **sp) { void logStackContent(void **sp) {
if (server.hide_user_data_from_log) {
serverLog(LL_NOTICE,"hide-user-data-from-log is on, skip logging stack content to avoid spilling PII.");
return;
}
int i; int i;
for (i = 15; i >= 0; i--) { for (i = 15; i >= 0; i--) {
unsigned long addr = (unsigned long) sp+i; unsigned long addr = (unsigned long) sp+i;
...@@ -2050,6 +2065,10 @@ void logCurrentClient(client *cc, const char *title) { ...@@ -2050,6 +2065,10 @@ void logCurrentClient(client *cc, const char *title) {
sdsfree(client); sdsfree(client);
serverLog(LL_WARNING|LL_RAW,"argc: '%d'\n", cc->argc); serverLog(LL_WARNING|LL_RAW,"argc: '%d'\n", cc->argc);
for (j = 0; j < cc->argc; j++) { for (j = 0; j < cc->argc; j++) {
if (j >= clientArgsToLog(cc)) {
serverLog(LL_WARNING|LL_RAW,"argv[%d]: *redacted*\n",j);
continue;
}
robj *decoded; robj *decoded;
decoded = getDecodedObject(cc->argv[j]); decoded = getDecodedObject(cc->argv[j]);
sds repr = sdscatrepr(sdsempty(),decoded->ptr, min(sdslen(decoded->ptr), 128)); sds repr = sdscatrepr(sdsempty(),decoded->ptr, min(sdslen(decoded->ptr), 128));
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
* *
* Licensed under your choice of the Redis Source Available License 2.0 * Licensed under your choice of the Redis Source Available License 2.0
* (RSALv2) or the Server Side Public License v1 (SSPLv1). * (RSALv2) or the Server Side Public License v1 (SSPLv1).
*
* Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information.
*/ */
...@@ -506,6 +508,10 @@ void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) { ...@@ -506,6 +508,10 @@ void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) {
void showLatestBacklog(void) { void showLatestBacklog(void) {
if (server.repl_backlog == NULL) return; if (server.repl_backlog == NULL) return;
if (listLength(server.repl_buffer_blocks) == 0) return; if (listLength(server.repl_buffer_blocks) == 0) return;
if (server.hide_user_data_from_log) {
serverLog(LL_NOTICE,"hide-user-data-from-log is on, skip logging backlog content to avoid spilling PII.");
return;
}
size_t dumplen = 256; size_t dumplen = 256;
if (server.repl_backlog->histlen < (long long)dumplen) if (server.repl_backlog->histlen < (long long)dumplen)
...@@ -535,16 +541,6 @@ void showLatestBacklog(void) { ...@@ -535,16 +541,6 @@ void showLatestBacklog(void) {
* to our sub-slaves. */ * to our sub-slaves. */
#include <ctype.h> #include <ctype.h>
void replicationFeedStreamFromMasterStream(char *buf, size_t buflen) { void replicationFeedStreamFromMasterStream(char *buf, size_t buflen) {
/* Debugging: this is handy to see the stream sent from master
* to slaves. Disabled with if(0). */
if (0) {
printf("%zu:",buflen);
for (size_t j = 0; j < buflen; j++) {
printf("%c", isprint(buf[j]) ? buf[j] : '.');
}
printf("\n");
}
/* There must be replication backlog if having attached slaves. */ /* There must be replication backlog if having attached slaves. */
if (listLength(server.slaves)) serverAssert(server.repl_backlog != NULL); if (listLength(server.slaves)) serverAssert(server.repl_backlog != NULL);
if (server.repl_backlog) { if (server.repl_backlog) {
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* *
* Licensed under your choice of the Redis Source Available License 2.0 * Licensed under your choice of the Redis Source Available License 2.0
* (RSALv2) or the Server Side Public License v1 (SSPLv1). * (RSALv2) or the Server Side Public License v1 (SSPLv1).
*
* Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information.
*/ */
#ifndef __REDIS_H #ifndef __REDIS_H
...@@ -1731,6 +1733,7 @@ struct redisServer { ...@@ -1731,6 +1733,7 @@ struct redisServer {
/* Configuration */ /* Configuration */
int verbosity; /* Loglevel in redis.conf */ int verbosity; /* Loglevel in redis.conf */
int hide_user_data_from_log; /* In the event of an assertion failure, hide command arguments from the operator */
int maxidletime; /* Client timeout in seconds */ int maxidletime; /* Client timeout in seconds */
int tcpkeepalive; /* Set SO_KEEPALIVE if non-zero. */ int tcpkeepalive; /* Set SO_KEEPALIVE if non-zero. */
int active_expire_enabled; /* Can be disabled for testing purposes. */ int active_expire_enabled; /* Can be disabled for testing purposes. */
......
...@@ -123,4 +123,32 @@ if {$backtrace_supported} { ...@@ -123,4 +123,32 @@ if {$backtrace_supported} {
} }
} }
# Tests that when `hide-user-data-from-log` is enabled, user information from logs is hidden
if {$backtrace_supported} {
if {!$::valgrind} {
set server_path [tmpdir server5.log]
start_server [list overrides [list dir $server_path crash-memcheck-enabled no]] {
test "Crash report generated on DEBUG SEGFAULT with user data hidden when 'hide-user-data-from-log' is enabled" {
r config set hide-user-data-from-log yes
catch {r debug segfault}
check_log_backtrace_for_debug "*crashed by signal*"
check_log_backtrace_for_debug "*argv*0*: *debug*"
check_log_backtrace_for_debug "*argv*1*: *redacted*"
check_log_backtrace_for_debug "*hide-user-data-from-log is on, skip logging stack content to avoid spilling PII*"
}
}
}
set server_path [tmpdir server6.log]
start_server [list overrides [list dir $server_path use-exit-on-panic yes crash-memcheck-enabled no]] {
test "Generate stacktrace on assertion with user data hidden when 'hide-user-data-from-log' is enabled" {
r config set hide-user-data-from-log yes
catch {r debug assert}
check_log_backtrace_for_debug "*ASSERTION FAILED*"
check_log_backtrace_for_debug "*argv*0* = *debug*"
check_log_backtrace_for_debug "*argv*1* = *redacted*"
}
}
}
} }
...@@ -1154,8 +1154,7 @@ proc system_backtrace_supported {} { ...@@ -1154,8 +1154,7 @@ proc system_backtrace_supported {} {
# libmusl does not support backtrace. Also return 0 on # libmusl does not support backtrace. Also return 0 on
# static binaries (ldd exit code 1) where we can't detect libmusl # static binaries (ldd exit code 1) where we can't detect libmusl
catch { if {![catch {set ldd [exec ldd src/redis-server]}]} {
set ldd [exec ldd src/redis-server]
if {![string match {*libc.*musl*} $ldd]} { if {![string match {*libc.*musl*} $ldd]} {
return 1 return 1
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment