Skip to content

Commit 2d186af

Browse files
pskrgagtorvalds
authored andcommitted
profiling: fix shift-out-of-bounds bugs
Syzbot reported shift-out-of-bounds bug in profile_init(). The problem was in incorrect prof_shift. Since prof_shift value comes from userspace we need to clamp this value into [0, BITS_PER_LONG -1] boundaries. Second possible shiht-out-of-bounds was found by Tetsuo: sample_step local variable in read_profile() had "unsigned int" type, but prof_shift allows to make a BITS_PER_LONG shift. So, to prevent possible shiht-out-of-bounds sample_step type was changed to "unsigned long". Also, "unsigned short int" will be sufficient for storing [0, BITS_PER_LONG] value, that's why there is no need for "unsigned long" prof_shift. Link: https://lkml.kernel.org/r/20210813140022.5011-1-paskripkin@gmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-and-tested-by: syzbot+e68c89a9510c159d9684@syzkaller.appspotmail.com Suggested-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> Signed-off-by: Pavel Skripkin <paskripkin@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 3c91dda commit 2d186af

File tree

1 file changed

+11
-10
lines changed

1 file changed

+11
-10
lines changed

kernel/profile.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ struct profile_hit {
4141
#define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ)
4242

4343
static atomic_t *prof_buffer;
44-
static unsigned long prof_len, prof_shift;
44+
static unsigned long prof_len;
45+
static unsigned short int prof_shift;
4546

4647
int prof_on __read_mostly;
4748
EXPORT_SYMBOL_GPL(prof_on);
@@ -67,8 +68,8 @@ int profile_setup(char *str)
6768
if (str[strlen(sleepstr)] == ',')
6869
str += strlen(sleepstr) + 1;
6970
if (get_option(&str, &par))
70-
prof_shift = par;
71-
pr_info("kernel sleep profiling enabled (shift: %ld)\n",
71+
prof_shift = clamp(par, 0, BITS_PER_LONG - 1);
72+
pr_info("kernel sleep profiling enabled (shift: %u)\n",
7273
prof_shift);
7374
#else
7475
pr_warn("kernel sleep profiling requires CONFIG_SCHEDSTATS\n");
@@ -78,21 +79,21 @@ int profile_setup(char *str)
7879
if (str[strlen(schedstr)] == ',')
7980
str += strlen(schedstr) + 1;
8081
if (get_option(&str, &par))
81-
prof_shift = par;
82-
pr_info("kernel schedule profiling enabled (shift: %ld)\n",
82+
prof_shift = clamp(par, 0, BITS_PER_LONG - 1);
83+
pr_info("kernel schedule profiling enabled (shift: %u)\n",
8384
prof_shift);
8485
} else if (!strncmp(str, kvmstr, strlen(kvmstr))) {
8586
prof_on = KVM_PROFILING;
8687
if (str[strlen(kvmstr)] == ',')
8788
str += strlen(kvmstr) + 1;
8889
if (get_option(&str, &par))
89-
prof_shift = par;
90-
pr_info("kernel KVM profiling enabled (shift: %ld)\n",
90+
prof_shift = clamp(par, 0, BITS_PER_LONG - 1);
91+
pr_info("kernel KVM profiling enabled (shift: %u)\n",
9192
prof_shift);
9293
} else if (get_option(&str, &par)) {
93-
prof_shift = par;
94+
prof_shift = clamp(par, 0, BITS_PER_LONG - 1);
9495
prof_on = CPU_PROFILING;
95-
pr_info("kernel profiling enabled (shift: %ld)\n",
96+
pr_info("kernel profiling enabled (shift: %u)\n",
9697
prof_shift);
9798
}
9899
return 1;
@@ -468,7 +469,7 @@ read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
468469
unsigned long p = *ppos;
469470
ssize_t read;
470471
char *pnt;
471-
unsigned int sample_step = 1 << prof_shift;
472+
unsigned long sample_step = 1UL << prof_shift;
472473

473474
profile_flip_buffers();
474475
if (p >= (prof_len+1)*sizeof(unsigned int))

0 commit comments

Comments
 (0)