1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

debug: fix parsing of /proc/self/stat

The code in init_log_file relies on the process name (COMM) to not
contain whitespaces. This change fixes it by looking up the right-most
parenthesis to safely jump past COMM.

For more context see:
https://www.openwall.com/lists/oss-security/2022/12/21/6

Code is only used with testing, so it should have no impact on regular
users.

Reported-by: Hugues Evrard <hevrard@google.com>

mm
This commit is contained in:
Zdenek Kabelac 2023-07-10 21:44:24 +02:00
parent 7ec97ed5f2
commit c38b668fc3

View File

@ -217,6 +217,45 @@ void init_log_fn(lvm2_log_fn_t log_fn)
_lvm2_log_fn = log_fn;
}
/* Read /proc/self/stat to extract pid and starttime */
static int _get_pid_starttime(int *pid, unsigned long long *starttime)
{
static const char statfile[] = "/proc/self/stat";
char buf[1024];
char *p;
int fd;
int e;
if ((fd = open(statfile, O_RDONLY)) == -1) {
log_sys_debug("open", statfile);
return 0;
}
if ((e = read(fd, buf, sizeof(buf) - 1)) <= 0)
log_sys_debug("read", statfile);
if (!close(fd))
log_sys_debug("close", statfile);
if (e <= 0)
return 0;
buf[e] = '\0';
if ((sscanf(buf, "%d ", pid) == 1) &&
/* Jump past COMM, don't use scanf with '%s' since COMM may contain a space. */
(p = strrchr(buf, ')')) &&
(scanf(++p, " %*c %*d %*d %*d %*d " /* tty_nr */
"%*d %*u %*u %*u %*u " /* mjflt */
"%*u %*u %*u %*d %*d " /* cstim */
"%*d %*d %*d %*d " /* itrealvalue */
"%llu", &starttime) == 1))
return 1;
log_debug("Cannot parse content of %s.", statfile);
return 0;
}
/*
* Support envvar LVM_LOG_FILE_EPOCH and allow to attach
* extra keyword (consist of upto 32 alpha chars) to
@ -228,11 +267,9 @@ void init_log_fn(lvm2_log_fn_t log_fn)
*/
void init_log_file(const char *log_file, int append)
{
static const char statfile[] = "/proc/self/stat";
const char *env;
int pid;
unsigned long long starttime;
FILE *st;
int pid = 0;
unsigned long long starttime = 0;
int i = 0;
_log_file_path[0] = '\0';
@ -245,27 +282,17 @@ void init_log_file(const char *log_file, int append)
goto no_epoch;
}
if (!(st = fopen(statfile, "r")))
log_sys_error("fopen", statfile);
else if (fscanf(st, "%d %*s %*c %*d %*d %*d %*d " /* tty_nr */
"%*d %*u %*u %*u %*u " /* mjflt */
"%*u %*u %*u %*d %*d " /* cstim */
"%*d %*d %*d %*d " /* itrealvalue */
"%llu", &pid, &starttime) != 2) {
log_warn("WARNING: Cannot parse content of %s.", statfile);
} else {
if (dm_snprintf(_log_file_path, sizeof(_log_file_path),
"%s_%s_%d_%llu", log_file, env, pid, starttime) < 0) {
log_warn("WARNING: Debug log file path is too long for epoch.");
_log_file_path[0] = '\0';
} else {
log_file = _log_file_path;
append = 1; /* force */
}
}
if (!_get_pid_starttime(&pid, &starttime))
log_debug("Failed to obtain pid and starttime.");
if (st && fclose(st))
log_sys_debug("fclose", statfile);
if (dm_snprintf(_log_file_path, sizeof(_log_file_path),
"%s_%s_%d_%llu", log_file, env, pid, starttime) < 0) {
log_warn("WARNING: Debug log file path is too long for epoch.");
_log_file_path[0] = '\0';
} else {
log_file = _log_file_path;
append = 1; /* force */
}
if ((env = getenv("LVM_LOG_FILE_MAX_LINES"))) {
if (sscanf(env, FMTu64, &_log_file_max_lines) != 1) {
@ -896,4 +923,3 @@ uint32_t log_journal_str_to_val(const char *str)
log_warn("Ignoring unrecognized journal value.");
return 0;
}