summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2018-07-13 19:59:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-07-14 14:11:10 -0400
commitfe10e398e860955bac4d28ec031b701d358465e4 (patch)
tree5f5e31e058796ca818dae8f4bef23afd5aaec062 /fs
parentffe075132af8b7967089c361e506d4fa747efd14 (diff)
reiserfs: fix buffer overflow with long warning messages
ReiserFS prepares log messages into a 1024-byte buffer with no bounds checks. Long messages, such as the "unknown mount option" warning when userspace passes a crafted mount options string, overflow this buffer. This causes KASAN to report a global-out-of-bounds write. Fix it by truncating messages to the buffer size. Link: http://lkml.kernel.org/r/20180707203621.30922-1-ebiggers3@gmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+b890b3335a4d8c608963@syzkaller.appspotmail.com Signed-off-by: Eric Biggers <ebiggers@google.com> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/reiserfs/prints.c141
1 files changed, 81 insertions, 60 deletions
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 7e288d97adcb..9fed1c05f1f4 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -76,83 +76,99 @@ static char *le_type(struct reiserfs_key *key)
76} 76}
77 77
78/* %k */ 78/* %k */
79static void sprintf_le_key(char *buf, struct reiserfs_key *key) 79static int scnprintf_le_key(char *buf, size_t size, struct reiserfs_key *key)
80{ 80{
81 if (key) 81 if (key)
82 sprintf(buf, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id), 82 return scnprintf(buf, size, "[%d %d %s %s]",
83 le32_to_cpu(key->k_objectid), le_offset(key), 83 le32_to_cpu(key->k_dir_id),
84 le_type(key)); 84 le32_to_cpu(key->k_objectid), le_offset(key),
85 le_type(key));
85 else 86 else
86 sprintf(buf, "[NULL]"); 87 return scnprintf(buf, size, "[NULL]");
87} 88}
88 89
89/* %K */ 90/* %K */
90static void sprintf_cpu_key(char *buf, struct cpu_key *key) 91static int scnprintf_cpu_key(char *buf, size_t size, struct cpu_key *key)
91{ 92{
92 if (key) 93 if (key)
93 sprintf(buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id, 94 return scnprintf(buf, size, "[%d %d %s %s]",
94 key->on_disk_key.k_objectid, reiserfs_cpu_offset(key), 95 key->on_disk_key.k_dir_id,
95 cpu_type(key)); 96 key->on_disk_key.k_objectid,
97 reiserfs_cpu_offset(key), cpu_type(key));
96 else 98 else
97 sprintf(buf, "[NULL]"); 99 return scnprintf(buf, size, "[NULL]");
98} 100}
99 101
100static void sprintf_de_head(char *buf, struct reiserfs_de_head *deh) 102static int scnprintf_de_head(char *buf, size_t size,
103 struct reiserfs_de_head *deh)
101{ 104{
102 if (deh) 105 if (deh)
103 sprintf(buf, 106 return scnprintf(buf, size,
104 "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", 107 "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]",
105 deh_offset(deh), deh_dir_id(deh), deh_objectid(deh), 108 deh_offset(deh), deh_dir_id(deh),
106 deh_location(deh), deh_state(deh)); 109 deh_objectid(deh), deh_location(deh),
110 deh_state(deh));
107 else 111 else
108 sprintf(buf, "[NULL]"); 112 return scnprintf(buf, size, "[NULL]");
109 113
110} 114}
111 115
112static void sprintf_item_head(char *buf, struct item_head *ih) 116static int scnprintf_item_head(char *buf, size_t size, struct item_head *ih)
113{ 117{
114 if (ih) { 118 if (ih) {
115 strcpy(buf, 119 char *p = buf;
116 (ih_version(ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*"); 120 char * const end = buf + size;
117 sprintf_le_key(buf + strlen(buf), &(ih->ih_key)); 121
118 sprintf(buf + strlen(buf), ", item_len %d, item_location %d, " 122 p += scnprintf(p, end - p, "%s",
119 "free_space(entry_count) %d", 123 (ih_version(ih) == KEY_FORMAT_3_6) ?
120 ih_item_len(ih), ih_location(ih), ih_free_space(ih)); 124 "*3.6* " : "*3.5*");
125
126 p += scnprintf_le_key(p, end - p, &ih->ih_key);
127
128 p += scnprintf(p, end - p,
129 ", item_len %d, item_location %d, free_space(entry_count) %d",
130 ih_item_len(ih), ih_location(ih),
131 ih_free_space(ih));
132 return p - buf;
121 } else 133 } else
122 sprintf(buf, "[NULL]"); 134 return scnprintf(buf, size, "[NULL]");
123} 135}
124 136
125static void sprintf_direntry(char *buf, struct reiserfs_dir_entry *de) 137static int scnprintf_direntry(char *buf, size_t size,
138 struct reiserfs_dir_entry *de)
126{ 139{
127 char name[20]; 140 char name[20];
128 141
129 memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen); 142 memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen);
130 name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0; 143 name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0;
131 sprintf(buf, "\"%s\"==>[%d %d]", name, de->de_dir_id, de->de_objectid); 144 return scnprintf(buf, size, "\"%s\"==>[%d %d]",
145 name, de->de_dir_id, de->de_objectid);
132} 146}
133 147
134static void sprintf_block_head(char *buf, struct buffer_head *bh) 148static int scnprintf_block_head(char *buf, size_t size, struct buffer_head *bh)
135{ 149{
136 sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ", 150 return scnprintf(buf, size,
137 B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh)); 151 "level=%d, nr_items=%d, free_space=%d rdkey ",
152 B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
138} 153}
139 154
140static void sprintf_buffer_head(char *buf, struct buffer_head *bh) 155static int scnprintf_buffer_head(char *buf, size_t size, struct buffer_head *bh)
141{ 156{
142 sprintf(buf, 157 return scnprintf(buf, size,
143 "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)", 158 "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
144 bh->b_bdev, bh->b_size, 159 bh->b_bdev, bh->b_size,
145 (unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)), 160 (unsigned long long)bh->b_blocknr,
146 bh->b_state, bh->b_page, 161 atomic_read(&(bh->b_count)),
147 buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE", 162 bh->b_state, bh->b_page,
148 buffer_dirty(bh) ? "DIRTY" : "CLEAN", 163 buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
149 buffer_locked(bh) ? "LOCKED" : "UNLOCKED"); 164 buffer_dirty(bh) ? "DIRTY" : "CLEAN",
165 buffer_locked(bh) ? "LOCKED" : "UNLOCKED");
150} 166}
151 167
152static void sprintf_disk_child(char *buf, struct disk_child *dc) 168static int scnprintf_disk_child(char *buf, size_t size, struct disk_child *dc)
153{ 169{
154 sprintf(buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc), 170 return scnprintf(buf, size, "[dc_number=%d, dc_size=%u]",
155 dc_size(dc)); 171 dc_block_number(dc), dc_size(dc));
156} 172}
157 173
158static char *is_there_reiserfs_struct(char *fmt, int *what) 174static char *is_there_reiserfs_struct(char *fmt, int *what)
@@ -189,55 +205,60 @@ static void prepare_error_buf(const char *fmt, va_list args)
189 char *fmt1 = fmt_buf; 205 char *fmt1 = fmt_buf;
190 char *k; 206 char *k;
191 char *p = error_buf; 207 char *p = error_buf;
208 char * const end = &error_buf[sizeof(error_buf)];
192 int what; 209 int what;
193 210
194 spin_lock(&error_lock); 211 spin_lock(&error_lock);
195 212
196 strcpy(fmt1, fmt); 213 if (WARN_ON(strscpy(fmt_buf, fmt, sizeof(fmt_buf)) < 0)) {
214 strscpy(error_buf, "format string too long", end - error_buf);
215 goto out_unlock;
216 }
197 217
198 while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) { 218 while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) {
199 *k = 0; 219 *k = 0;
200 220
201 p += vsprintf(p, fmt1, args); 221 p += vscnprintf(p, end - p, fmt1, args);
202 222
203 switch (what) { 223 switch (what) {
204 case 'k': 224 case 'k':
205 sprintf_le_key(p, va_arg(args, struct reiserfs_key *)); 225 p += scnprintf_le_key(p, end - p,
226 va_arg(args, struct reiserfs_key *));
206 break; 227 break;
207 case 'K': 228 case 'K':
208 sprintf_cpu_key(p, va_arg(args, struct cpu_key *)); 229 p += scnprintf_cpu_key(p, end - p,
230 va_arg(args, struct cpu_key *));
209 break; 231 break;
210 case 'h': 232 case 'h':
211 sprintf_item_head(p, va_arg(args, struct item_head *)); 233 p += scnprintf_item_head(p, end - p,
234 va_arg(args, struct item_head *));
212 break; 235 break;
213 case 't': 236 case 't':
214 sprintf_direntry(p, 237 p += scnprintf_direntry(p, end - p,
215 va_arg(args, 238 va_arg(args, struct reiserfs_dir_entry *));
216 struct reiserfs_dir_entry *));
217 break; 239 break;
218 case 'y': 240 case 'y':
219 sprintf_disk_child(p, 241 p += scnprintf_disk_child(p, end - p,
220 va_arg(args, struct disk_child *)); 242 va_arg(args, struct disk_child *));
221 break; 243 break;
222 case 'z': 244 case 'z':
223 sprintf_block_head(p, 245 p += scnprintf_block_head(p, end - p,
224 va_arg(args, struct buffer_head *)); 246 va_arg(args, struct buffer_head *));
225 break; 247 break;
226 case 'b': 248 case 'b':
227 sprintf_buffer_head(p, 249 p += scnprintf_buffer_head(p, end - p,
228 va_arg(args, struct buffer_head *)); 250 va_arg(args, struct buffer_head *));
229 break; 251 break;
230 case 'a': 252 case 'a':
231 sprintf_de_head(p, 253 p += scnprintf_de_head(p, end - p,
232 va_arg(args, 254 va_arg(args, struct reiserfs_de_head *));
233 struct reiserfs_de_head *));
234 break; 255 break;
235 } 256 }
236 257
237 p += strlen(p);
238 fmt1 = k + 2; 258 fmt1 = k + 2;
239 } 259 }
240 vsprintf(p, fmt1, args); 260 p += vscnprintf(p, end - p, fmt1, args);
261out_unlock:
241 spin_unlock(&error_lock); 262 spin_unlock(&error_lock);
242 263
243} 264}