Skip to content

Commit 08e23d0

Browse files
Ansuelchanwoochoi
authored andcommitted
PM / devfreq: Fix buffer overflow in trans_stat_show
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/20231024183016.14648-2-ansuelsmth@gmail.com/ Cc: stable@vger.kernel.org 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 <ansuelsmth@gmail.com> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
1 parent b85ea95 commit 08e23d0

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
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 <nm@ti.com>

drivers/devfreq/devfreq.c

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,7 +1688,7 @@ static ssize_t trans_stat_show(struct device *dev,
16881688
struct device_attribute *attr, char *buf)
16891689
{
16901690
struct devfreq *df = to_devfreq(dev);
1691-
ssize_t len;
1691+
ssize_t len = 0;
16921692
int i, j;
16931693
unsigned int max_state;
16941694

@@ -1697,7 +1697,7 @@ static ssize_t trans_stat_show(struct device *dev,
16971697
max_state = df->max_state;
16981698

16991699
if (max_state == 0)
1700-
return sprintf(buf, "Not Supported.\n");
1700+
return scnprintf(buf, PAGE_SIZE, "Not Supported.\n");
17011701

17021702
mutex_lock(&df->lock);
17031703
if (!df->stop_polling &&
@@ -1707,31 +1707,52 @@ static ssize_t trans_stat_show(struct device *dev,
17071707
}
17081708
mutex_unlock(&df->lock);
17091709

1710-
len = sprintf(buf, " From : To\n");
1711-
len += sprintf(buf + len, " :");
1712-
for (i = 0; i < max_state; i++)
1713-
len += sprintf(buf + len, "%10lu",
1714-
df->freq_table[i]);
1710+
len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n");
1711+
len += scnprintf(buf + len, PAGE_SIZE - len, " :");
1712+
for (i = 0; i < max_state; i++) {
1713+
if (len >= PAGE_SIZE - 1)
1714+
break;
1715+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu",
1716+
df->freq_table[i]);
1717+
}
1718+
if (len >= PAGE_SIZE - 1)
1719+
return PAGE_SIZE - 1;
17151720

1716-
len += sprintf(buf + len, " time(ms)\n");
1721+
len += scnprintf(buf + len, PAGE_SIZE - len, " time(ms)\n");
17171722

17181723
for (i = 0; i < max_state; i++) {
1724+
if (len >= PAGE_SIZE - 1)
1725+
break;
17191726
if (df->freq_table[i] == df->previous_freq)
1720-
len += sprintf(buf + len, "*");
1727+
len += scnprintf(buf + len, PAGE_SIZE - len, "*");
17211728
else
1722-
len += sprintf(buf + len, " ");
1729+
len += scnprintf(buf + len, PAGE_SIZE - len, " ");
1730+
if (len >= PAGE_SIZE - 1)
1731+
break;
1732+
1733+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu:",
1734+
df->freq_table[i]);
1735+
for (j = 0; j < max_state; j++) {
1736+
if (len >= PAGE_SIZE - 1)
1737+
break;
1738+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10u",
1739+
df->stats.trans_table[(i * max_state) + j]);
1740+
}
1741+
if (len >= PAGE_SIZE - 1)
1742+
break;
1743+
len += scnprintf(buf + len, PAGE_SIZE - len, "%10llu\n", (u64)
1744+
jiffies64_to_msecs(df->stats.time_in_state[i]));
1745+
}
17231746

1724-
len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
1725-
for (j = 0; j < max_state; j++)
1726-
len += sprintf(buf + len, "%10u",
1727-
df->stats.trans_table[(i * max_state) + j]);
1747+
if (len < PAGE_SIZE - 1)
1748+
len += scnprintf(buf + len, PAGE_SIZE - len, "Total transition : %u\n",
1749+
df->stats.total_trans);
17281750

1729-
len += sprintf(buf + len, "%10llu\n", (u64)
1730-
jiffies64_to_msecs(df->stats.time_in_state[i]));
1751+
if (len >= PAGE_SIZE - 1) {
1752+
pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n");
1753+
return -EFBIG;
17311754
}
17321755

1733-
len += sprintf(buf + len, "Total transition : %u\n",
1734-
df->stats.total_trans);
17351756
return len;
17361757
}
17371758

0 commit comments

Comments
 (0)