@@ -184,27 +184,73 @@ ext4_xattr_handler(int name_index)
184184}
185185
186186static int
187- ext4_xattr_check_entries (struct ext4_xattr_entry * entry , void * end ,
188- void * value_start )
187+ check_xattrs (struct inode * inode , struct buffer_head * bh ,
188+ struct ext4_xattr_entry * entry , void * end , void * value_start ,
189+ const char * function , unsigned int line )
189190{
190191 struct ext4_xattr_entry * e = entry ;
192+ int err = - EFSCORRUPTED ;
193+ char * err_str ;
194+
195+ if (bh ) {
196+ if (BHDR (bh )-> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC ) ||
197+ BHDR (bh )-> h_blocks != cpu_to_le32 (1 )) {
198+ err_str = "invalid header" ;
199+ goto errout ;
200+ }
201+ if (buffer_verified (bh ))
202+ return 0 ;
203+ if (!ext4_xattr_block_csum_verify (inode , bh )) {
204+ err = - EFSBADCRC ;
205+ err_str = "invalid checksum" ;
206+ goto errout ;
207+ }
208+ } else {
209+ struct ext4_xattr_ibody_header * header = value_start ;
210+
211+ header -= 1 ;
212+ if (end - (void * )header < sizeof (* header ) + sizeof (u32 )) {
213+ err_str = "in-inode xattr block too small" ;
214+ goto errout ;
215+ }
216+ if (header -> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC )) {
217+ err_str = "bad magic number in in-inode xattr" ;
218+ goto errout ;
219+ }
220+ }
191221
192222 /* Find the end of the names list */
193223 while (!IS_LAST_ENTRY (e )) {
194224 struct ext4_xattr_entry * next = EXT4_XATTR_NEXT (e );
195- if ((void * )next >= end )
196- return - EFSCORRUPTED ;
197- if (strnlen (e -> e_name , e -> e_name_len ) != e -> e_name_len )
198- return - EFSCORRUPTED ;
225+ if ((void * )next >= end ) {
226+ err_str = "e_name out of bounds" ;
227+ goto errout ;
228+ }
229+ if (strnlen (e -> e_name , e -> e_name_len ) != e -> e_name_len ) {
230+ err_str = "bad e_name length" ;
231+ goto errout ;
232+ }
199233 e = next ;
200234 }
201235
202236 /* Check the values */
203237 while (!IS_LAST_ENTRY (entry )) {
204238 u32 size = le32_to_cpu (entry -> e_value_size );
239+ unsigned long ea_ino = le32_to_cpu (entry -> e_value_inum );
205240
206- if (size > EXT4_XATTR_SIZE_MAX )
207- return - EFSCORRUPTED ;
241+ if (!ext4_has_feature_ea_inode (inode -> i_sb ) && ea_ino ) {
242+ err_str = "ea_inode specified without ea_inode feature enabled" ;
243+ goto errout ;
244+ }
245+ if (ea_ino && ((ea_ino == EXT4_ROOT_INO ) ||
246+ !ext4_valid_inum (inode -> i_sb , ea_ino ))) {
247+ err_str = "invalid ea_ino" ;
248+ goto errout ;
249+ }
250+ if (size > EXT4_XATTR_SIZE_MAX ) {
251+ err_str = "e_value size too large" ;
252+ goto errout ;
253+ }
208254
209255 if (size != 0 && entry -> e_value_inum == 0 ) {
210256 u16 offs = le16_to_cpu (entry -> e_value_offs );
@@ -216,66 +262,54 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
216262 * the padded and unpadded sizes, since the size may
217263 * overflow to 0 when adding padding.
218264 */
219- if (offs > end - value_start )
220- return - EFSCORRUPTED ;
265+ if (offs > end - value_start ) {
266+ err_str = "e_value out of bounds" ;
267+ goto errout ;
268+ }
221269 value = value_start + offs ;
222270 if (value < (void * )e + sizeof (u32 ) ||
223271 size > end - value ||
224- EXT4_XATTR_SIZE (size ) > end - value )
225- return - EFSCORRUPTED ;
272+ EXT4_XATTR_SIZE (size ) > end - value ) {
273+ err_str = "overlapping e_value " ;
274+ goto errout ;
275+ }
226276 }
227277 entry = EXT4_XATTR_NEXT (entry );
228278 }
229-
279+ if (bh )
280+ set_buffer_verified (bh );
230281 return 0 ;
282+
283+ errout :
284+ if (bh )
285+ __ext4_error_inode (inode , function , line , 0 , - err ,
286+ "corrupted xattr block %llu: %s" ,
287+ (unsigned long long ) bh -> b_blocknr ,
288+ err_str );
289+ else
290+ __ext4_error_inode (inode , function , line , 0 , - err ,
291+ "corrupted in-inode xattr: %s" , err_str );
292+ return err ;
231293}
232294
233295static inline int
234296__ext4_xattr_check_block (struct inode * inode , struct buffer_head * bh ,
235297 const char * function , unsigned int line )
236298{
237- int error = - EFSCORRUPTED ;
238-
239- if (BHDR (bh )-> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC ) ||
240- BHDR (bh )-> h_blocks != cpu_to_le32 (1 ))
241- goto errout ;
242- if (buffer_verified (bh ))
243- return 0 ;
244-
245- error = - EFSBADCRC ;
246- if (!ext4_xattr_block_csum_verify (inode , bh ))
247- goto errout ;
248- error = ext4_xattr_check_entries (BFIRST (bh ), bh -> b_data + bh -> b_size ,
249- bh -> b_data );
250- errout :
251- if (error )
252- __ext4_error_inode (inode , function , line , 0 , - error ,
253- "corrupted xattr block %llu" ,
254- (unsigned long long ) bh -> b_blocknr );
255- else
256- set_buffer_verified (bh );
257- return error ;
299+ return check_xattrs (inode , bh , BFIRST (bh ), bh -> b_data + bh -> b_size ,
300+ bh -> b_data , function , line );
258301}
259302
260303#define ext4_xattr_check_block (inode , bh ) \
261304 __ext4_xattr_check_block((inode), (bh), __func__, __LINE__)
262305
263306
264- static int
307+ static inline int
265308__xattr_check_inode (struct inode * inode , struct ext4_xattr_ibody_header * header ,
266309 void * end , const char * function , unsigned int line )
267310{
268- int error = - EFSCORRUPTED ;
269-
270- if (end - (void * )header < sizeof (* header ) + sizeof (u32 ) ||
271- (header -> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC )))
272- goto errout ;
273- error = ext4_xattr_check_entries (IFIRST (header ), end , IFIRST (header ));
274- errout :
275- if (error )
276- __ext4_error_inode (inode , function , line , 0 , - error ,
277- "corrupted in-inode xattr" );
278- return error ;
311+ return check_xattrs (inode , NULL , IFIRST (header ), end , IFIRST (header ),
312+ function , line );
279313}
280314
281315#define xattr_check_inode (inode , header , end ) \
0 commit comments