Skip to content

Commit 146c129

Browse files
Ansuelsmb49
authored andcommitted
PM / devfreq: Fix buffer overflow in trans_stat_show
BugLink: https://bugs.launchpad.net/bugs/2059014 [ Upstream commit 08e23d0 ] Fix buffer overflow in trans_stat_show(). Convert simple snprintf to the more secure scnprintf with size of PAGE_SIZE. Add condition checking if we are exceeding PAGE_SIZE and exit early from loop. Also add at the end a warning that we exceeded PAGE_SIZE and that stats is disabled. Return -EFBIG in the case where we don't have enough space to write the full transition table. Also document in the ABI that this function can return -EFBIG error. Link: https://lore.kernel.org/all/[email protected]/ Cc: [email protected] Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218041 Fixes: e552bba ("PM / devfreq: Add sysfs node for representing frequency transition information.") Signed-off-by: Christian Marangi <[email protected]> Signed-off-by: Chanwoo Choi <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Manuel Diewald <[email protected]> Signed-off-by: Stefan Bader <[email protected]>
1 parent f43fa36 commit 146c129

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

Documentation/ABI/testing/sysfs-class-devfreq

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ Description:
5252

5353
echo 0 > /sys/class/devfreq/.../trans_stat
5454

55+
If the transition table is bigger than PAGE_SIZE, reading
56+
this will return an -EFBIG error.
57+
5558
What: /sys/class/devfreq/.../available_frequencies
5659
Date: October 2012
5760
Contact: Nishanth Menon <[email protected]>

drivers/devfreq/devfreq.c

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,7 +1653,7 @@ static ssize_t trans_stat_show(struct device *dev,
16531653
struct device_attribute *attr, char *buf)
16541654
{
16551655
struct devfreq *df = to_devfreq(dev);
1656-
ssize_t len;
1656+
ssize_t len = 0;
16571657
int i, j;
16581658
unsigned int max_state;
16591659

@@ -1662,7 +1662,7 @@ static ssize_t trans_stat_show(struct device *dev,
16621662
max_state = df->profile->max_state;
16631663

16641664
if (max_state == 0)
1665-
return sprintf(buf, "Not Supported.\n");
1665+
return scnprintf(buf, PAGE_SIZE, "Not Supported.\n");
16661666

16671667
mutex_lock(&df->lock);
16681668
if (!df->stop_polling &&
@@ -1672,33 +1672,54 @@ static ssize_t trans_stat_show(struct device *dev,
16721672
}
16731673
mutex_unlock(&df->lock);
16741674

1675-
len = sprintf(buf, " From : To\n");
1676-
len += sprintf(buf + len, " :");
1677-
for (i = 0; i < max_state; i++)
1678-
len += sprintf(buf + len, "%10lu",
1679-
df->profile->freq_table[i]);
1675+
len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n");
1676+
len += scnprintf(buf + len, PAGE_SIZE - len, " :");
1677+
for (i = 0; i < max_state; i++) {
1678+
if (len >= PAGE_SIZE - 1)
1679+
break;
1680+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu",
1681+
df->profile->freq_table[i]);
1682+
}
1683+
if (len >= PAGE_SIZE - 1)
1684+
return PAGE_SIZE - 1;
16801685

1681-
len += sprintf(buf + len, " time(ms)\n");
1686+
len += scnprintf(buf + len, PAGE_SIZE - len, " time(ms)\n");
16821687

16831688
for (i = 0; i < max_state; i++) {
1689+
if (len >= PAGE_SIZE - 1)
1690+
break;
16841691
if (df->profile->freq_table[i]
16851692
== df->previous_freq) {
1686-
len += sprintf(buf + len, "*");
1693+
len += scnprintf(buf + len, PAGE_SIZE - len, "*");
16871694
} else {
1688-
len += sprintf(buf + len, " ");
1695+
len += scnprintf(buf + len, PAGE_SIZE - len, " ");
1696+
}
1697+
if (len >= PAGE_SIZE - 1)
1698+
break;
1699+
1700+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu:",
1701+
df->profile->freq_table[i]);
1702+
for (j = 0; j < max_state; j++) {
1703+
if (len >= PAGE_SIZE - 1)
1704+
break;
1705+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10u",
1706+
df->stats.trans_table[(i * max_state) + j]);
16891707
}
1690-
len += sprintf(buf + len, "%10lu:",
1691-
df->profile->freq_table[i]);
1692-
for (j = 0; j < max_state; j++)
1693-
len += sprintf(buf + len, "%10u",
1694-
df->stats.trans_table[(i * max_state) + j]);
1708+
if (len >= PAGE_SIZE - 1)
1709+
break;
1710+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10llu\n", (u64)
1711+
jiffies64_to_msecs(df->stats.time_in_state[i]));
1712+
}
1713+
1714+
if (len < PAGE_SIZE - 1)
1715+
len += scnprintf(buf + len, PAGE_SIZE - len, "Total transition : %u\n",
1716+
df->stats.total_trans);
16951717

1696-
len += sprintf(buf + len, "%10llu\n", (u64)
1697-
jiffies64_to_msecs(df->stats.time_in_state[i]));
1718+
if (len >= PAGE_SIZE - 1) {
1719+
pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n");
1720+
return -EFBIG;
16981721
}
16991722

1700-
len += sprintf(buf + len, "Total transition : %u\n",
1701-
df->stats.total_trans);
17021723
return len;
17031724
}
17041725

0 commit comments

Comments
 (0)