pstore: Do not duplicate record metadata

This switches the inode-private data from carrying duplicate metadata to
keeping the record passed in during pstore_mkfile().

Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
Kees Cook 2017-03-04 23:12:24 -08:00
parent 2a2b0acf76
commit 83f70f0769
2 changed files with 30 additions and 33 deletions

View File

@ -47,12 +47,8 @@ static LIST_HEAD(allpstore);
struct pstore_private { struct pstore_private {
struct list_head list; struct list_head list;
struct pstore_info *psi; struct pstore_record *record;
enum pstore_type_id type; size_t total_size;
u64 id;
int count;
ssize_t size;
char *buf;
}; };
struct pstore_ftrace_seq_data { struct pstore_ftrace_seq_data {
@ -67,7 +63,10 @@ static void free_pstore_private(struct pstore_private *private)
{ {
if (!private) if (!private)
return; return;
kfree(private->buf); if (private->record) {
kfree(private->record->buf);
kfree(private->record);
}
kfree(private); kfree(private);
} }
@ -80,9 +79,9 @@ static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos)
if (!data) if (!data)
return NULL; return NULL;
data->off = ps->size % REC_SIZE; data->off = ps->total_size % REC_SIZE;
data->off += *pos * REC_SIZE; data->off += *pos * REC_SIZE;
if (data->off + REC_SIZE > ps->size) { if (data->off + REC_SIZE > ps->total_size) {
kfree(data); kfree(data);
return NULL; return NULL;
} }
@ -102,7 +101,7 @@ static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos)
struct pstore_ftrace_seq_data *data = v; struct pstore_ftrace_seq_data *data = v;
data->off += REC_SIZE; data->off += REC_SIZE;
if (data->off + REC_SIZE > ps->size) if (data->off + REC_SIZE > ps->total_size)
return NULL; return NULL;
(*pos)++; (*pos)++;
@ -113,7 +112,9 @@ static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
{ {
struct pstore_private *ps = s->private; struct pstore_private *ps = s->private;
struct pstore_ftrace_seq_data *data = v; struct pstore_ftrace_seq_data *data = v;
struct pstore_ftrace_record *rec = (void *)(ps->buf + data->off); struct pstore_ftrace_record *rec;
rec = (struct pstore_ftrace_record *)(ps->record->buf + data->off);
seq_printf(s, "CPU:%d ts:%llu %08lx %08lx %pf <- %pF\n", seq_printf(s, "CPU:%d ts:%llu %08lx %08lx %pf <- %pF\n",
pstore_ftrace_decode_cpu(rec), pstore_ftrace_decode_cpu(rec),
@ -133,7 +134,7 @@ static const struct seq_operations pstore_ftrace_seq_ops = {
static int pstore_check_syslog_permissions(struct pstore_private *ps) static int pstore_check_syslog_permissions(struct pstore_private *ps)
{ {
switch (ps->type) { switch (ps->record->type) {
case PSTORE_TYPE_DMESG: case PSTORE_TYPE_DMESG:
case PSTORE_TYPE_CONSOLE: case PSTORE_TYPE_CONSOLE:
return check_syslog_permissions(SYSLOG_ACTION_READ_ALL, return check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
@ -149,9 +150,10 @@ static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
struct seq_file *sf = file->private_data; struct seq_file *sf = file->private_data;
struct pstore_private *ps = sf->private; struct pstore_private *ps = sf->private;
if (ps->type == PSTORE_TYPE_FTRACE) if (ps->record->type == PSTORE_TYPE_FTRACE)
return seq_read(file, userbuf, count, ppos); return seq_read(file, userbuf, count, ppos);
return simple_read_from_buffer(userbuf, count, ppos, ps->buf, ps->size); return simple_read_from_buffer(userbuf, count, ppos,
ps->record->buf, ps->total_size);
} }
static int pstore_file_open(struct inode *inode, struct file *file) static int pstore_file_open(struct inode *inode, struct file *file)
@ -165,7 +167,7 @@ static int pstore_file_open(struct inode *inode, struct file *file)
if (err) if (err)
return err; return err;
if (ps->type == PSTORE_TYPE_FTRACE) if (ps->record->type == PSTORE_TYPE_FTRACE)
sops = &pstore_ftrace_seq_ops; sops = &pstore_ftrace_seq_ops;
err = seq_open(file, sops); err = seq_open(file, sops);
@ -201,17 +203,18 @@ static const struct file_operations pstore_file_operations = {
static int pstore_unlink(struct inode *dir, struct dentry *dentry) static int pstore_unlink(struct inode *dir, struct dentry *dentry)
{ {
struct pstore_private *p = d_inode(dentry)->i_private; struct pstore_private *p = d_inode(dentry)->i_private;
struct pstore_record *record = p->record;
int err; int err;
err = pstore_check_syslog_permissions(p); err = pstore_check_syslog_permissions(p);
if (err) if (err)
return err; return err;
if (p->psi->erase) { if (record->psi->erase) {
mutex_lock(&p->psi->read_mutex); mutex_lock(&record->psi->read_mutex);
p->psi->erase(p->type, p->id, p->count, record->psi->erase(record->type, record->id, record->count,
d_inode(dentry)->i_ctime, p->psi); d_inode(dentry)->i_ctime, record->psi);
mutex_unlock(&p->psi->read_mutex); mutex_unlock(&record->psi->read_mutex);
} else { } else {
return -EPERM; return -EPERM;
} }
@ -323,9 +326,9 @@ int pstore_mkfile(struct pstore_record *record)
spin_lock_irqsave(&allpstore_lock, flags); spin_lock_irqsave(&allpstore_lock, flags);
list_for_each_entry(pos, &allpstore, list) { list_for_each_entry(pos, &allpstore, list) {
if (pos->type == record->type && if (pos->record->type == record->type &&
pos->id == record->id && pos->record->id == record->id &&
pos->psi == record->psi) { pos->record->psi == record->psi) {
rc = -EEXIST; rc = -EEXIST;
break; break;
} }
@ -343,10 +346,7 @@ int pstore_mkfile(struct pstore_record *record)
private = kzalloc(sizeof(*private), GFP_KERNEL); private = kzalloc(sizeof(*private), GFP_KERNEL);
if (!private) if (!private)
goto fail_alloc; goto fail_alloc;
private->type = record->type; private->record = record;
private->id = record->id;
private->count = record->count;
private->psi = record->psi;
switch (record->type) { switch (record->type) {
case PSTORE_TYPE_DMESG: case PSTORE_TYPE_DMESG:
@ -402,8 +402,7 @@ int pstore_mkfile(struct pstore_record *record)
if (!dentry) if (!dentry)
goto fail_lockedalloc; goto fail_lockedalloc;
private->buf = record->buf; inode->i_size = private->total_size = size;
inode->i_size = private->size = size;
inode->i_private = private; inode->i_private = private;

View File

@ -852,14 +852,12 @@ void pstore_get_records(int quiet)
decompress_record(record); decompress_record(record);
rc = pstore_mkfile(record); rc = pstore_mkfile(record);
if (rc) { if (rc) {
/* pstore_mkfile() did not take buf, so free it. */ /* pstore_mkfile() did not take record, so free it. */
kfree(record->buf); kfree(record->buf);
kfree(record);
if (rc != -EEXIST || !quiet) if (rc != -EEXIST || !quiet)
failed++; failed++;
} }
/* Reset for next record. */
kfree(record);
} }
if (psi->close) if (psi->close)
psi->close(psi); psi->close(psi);