@@ -182,27 +182,73 @@ ext4_xattr_handler(int name_index)
182182}
183183
184184static int
185- ext4_xattr_check_entries (struct ext4_xattr_entry * entry , void * end ,
186- void * value_start )
185+ check_xattrs (struct inode * inode , struct buffer_head * bh ,
186+ struct ext4_xattr_entry * entry , void * end , void * value_start ,
187+ const char * function , unsigned int line )
187188{
188189 struct ext4_xattr_entry * e = entry ;
190+ int err = - EFSCORRUPTED ;
191+ char * err_str ;
192+
193+ if (bh ) {
194+ if (BHDR (bh )-> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC ) ||
195+ BHDR (bh )-> h_blocks != cpu_to_le32 (1 )) {
196+ err_str = "invalid header" ;
197+ goto errout ;
198+ }
199+ if (buffer_verified (bh ))
200+ return 0 ;
201+ if (!ext4_xattr_block_csum_verify (inode , bh )) {
202+ err = - EFSBADCRC ;
203+ err_str = "invalid checksum" ;
204+ goto errout ;
205+ }
206+ } else {
207+ struct ext4_xattr_ibody_header * header = value_start ;
208+
209+ header -= 1 ;
210+ if (end - (void * )header < sizeof (* header ) + sizeof (u32 )) {
211+ err_str = "in-inode xattr block too small" ;
212+ goto errout ;
213+ }
214+ if (header -> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC )) {
215+ err_str = "bad magic number in in-inode xattr" ;
216+ goto errout ;
217+ }
218+ }
189219
190220 /* Find the end of the names list */
191221 while (!IS_LAST_ENTRY (e )) {
192222 struct ext4_xattr_entry * next = EXT4_XATTR_NEXT (e );
193- if ((void * )next >= end )
194- return - EFSCORRUPTED ;
195- if (strnlen (e -> e_name , e -> e_name_len ) != e -> e_name_len )
196- return - EFSCORRUPTED ;
223+ if ((void * )next >= end ) {
224+ err_str = "e_name out of bounds" ;
225+ goto errout ;
226+ }
227+ if (strnlen (e -> e_name , e -> e_name_len ) != e -> e_name_len ) {
228+ err_str = "bad e_name length" ;
229+ goto errout ;
230+ }
197231 e = next ;
198232 }
199233
200234 /* Check the values */
201235 while (!IS_LAST_ENTRY (entry )) {
202236 u32 size = le32_to_cpu (entry -> e_value_size );
237+ unsigned long ea_ino = le32_to_cpu (entry -> e_value_inum );
203238
204- if (size > EXT4_XATTR_SIZE_MAX )
205- return - EFSCORRUPTED ;
239+ if (!ext4_has_feature_ea_inode (inode -> i_sb ) && ea_ino ) {
240+ err_str = "ea_inode specified without ea_inode feature enabled" ;
241+ goto errout ;
242+ }
243+ if (ea_ino && ((ea_ino == EXT4_ROOT_INO ) ||
244+ !ext4_valid_inum (inode -> i_sb , ea_ino ))) {
245+ err_str = "invalid ea_ino" ;
246+ goto errout ;
247+ }
248+ if (size > EXT4_XATTR_SIZE_MAX ) {
249+ err_str = "e_value size too large" ;
250+ goto errout ;
251+ }
206252
207253 if (size != 0 && entry -> e_value_inum == 0 ) {
208254 u16 offs = le16_to_cpu (entry -> e_value_offs );
@@ -214,66 +260,54 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
214260 * the padded and unpadded sizes, since the size may
215261 * overflow to 0 when adding padding.
216262 */
217- if (offs > end - value_start )
218- return - EFSCORRUPTED ;
263+ if (offs > end - value_start ) {
264+ err_str = "e_value out of bounds" ;
265+ goto errout ;
266+ }
219267 value = value_start + offs ;
220268 if (value < (void * )e + sizeof (u32 ) ||
221269 size > end - value ||
222- EXT4_XATTR_SIZE (size ) > end - value )
223- return - EFSCORRUPTED ;
270+ EXT4_XATTR_SIZE (size ) > end - value ) {
271+ err_str = "overlapping e_value " ;
272+ goto errout ;
273+ }
224274 }
225275 entry = EXT4_XATTR_NEXT (entry );
226276 }
227-
277+ if (bh )
278+ set_buffer_verified (bh );
228279 return 0 ;
280+
281+ errout :
282+ if (bh )
283+ __ext4_error_inode (inode , function , line , 0 , - err ,
284+ "corrupted xattr block %llu: %s" ,
285+ (unsigned long long ) bh -> b_blocknr ,
286+ err_str );
287+ else
288+ __ext4_error_inode (inode , function , line , 0 , - err ,
289+ "corrupted in-inode xattr: %s" , err_str );
290+ return err ;
229291}
230292
231293static inline int
232294__ext4_xattr_check_block (struct inode * inode , struct buffer_head * bh ,
233295 const char * function , unsigned int line )
234296{
235- int error = - EFSCORRUPTED ;
236-
237- if (BHDR (bh )-> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC ) ||
238- BHDR (bh )-> h_blocks != cpu_to_le32 (1 ))
239- goto errout ;
240- if (buffer_verified (bh ))
241- return 0 ;
242-
243- error = - EFSBADCRC ;
244- if (!ext4_xattr_block_csum_verify (inode , bh ))
245- goto errout ;
246- error = ext4_xattr_check_entries (BFIRST (bh ), bh -> b_data + bh -> b_size ,
247- bh -> b_data );
248- errout :
249- if (error )
250- __ext4_error_inode (inode , function , line , 0 , - error ,
251- "corrupted xattr block %llu" ,
252- (unsigned long long ) bh -> b_blocknr );
253- else
254- set_buffer_verified (bh );
255- return error ;
297+ return check_xattrs (inode , bh , BFIRST (bh ), bh -> b_data + bh -> b_size ,
298+ bh -> b_data , function , line );
256299}
257300
258301#define ext4_xattr_check_block (inode , bh ) \
259302 __ext4_xattr_check_block((inode), (bh), __func__, __LINE__)
260303
261304
262- static int
305+ static inline int
263306__xattr_check_inode (struct inode * inode , struct ext4_xattr_ibody_header * header ,
264307 void * end , const char * function , unsigned int line )
265308{
266- int error = - EFSCORRUPTED ;
267-
268- if (end - (void * )header < sizeof (* header ) + sizeof (u32 ) ||
269- (header -> h_magic != cpu_to_le32 (EXT4_XATTR_MAGIC )))
270- goto errout ;
271- error = ext4_xattr_check_entries (IFIRST (header ), end , IFIRST (header ));
272- errout :
273- if (error )
274- __ext4_error_inode (inode , function , line , 0 , - error ,
275- "corrupted in-inode xattr" );
276- return error ;
309+ return check_xattrs (inode , NULL , IFIRST (header ), end , IFIRST (header ),
310+ function , line );
277311}
278312
279313#define xattr_check_inode (inode , header , end ) \
0 commit comments