3df8c3
diff -up util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak util-linux-2.23.2/libblkid/src/superblocks/xfs.c
3df8c3
--- util-linux-2.23.2/libblkid/src/superblocks/xfs.c.kzak	2014-09-24 10:59:39.548315524 +0200
3df8c3
+++ util-linux-2.23.2/libblkid/src/superblocks/xfs.c	2014-09-24 11:02:55.595186026 +0200
3df8c3
@@ -20,20 +20,143 @@
3df8c3
 #include "superblocks.h"
3df8c3
 
3df8c3
 struct xfs_super_block {
3df8c3
-	unsigned char	xs_magic[4];
3df8c3
-	uint32_t	xs_blocksize;
3df8c3
-	uint64_t	xs_dblocks;
3df8c3
-	uint64_t	xs_rblocks;
3df8c3
-	uint32_t	xs_dummy1[2];
3df8c3
-	unsigned char	xs_uuid[16];
3df8c3
-	uint32_t	xs_dummy2[15];
3df8c3
-	char		xs_fname[12];
3df8c3
-	uint32_t	xs_dummy3[2];
3df8c3
-	uint64_t	xs_icount;
3df8c3
-	uint64_t	xs_ifree;
3df8c3
-	uint64_t	xs_fdblocks;
3df8c3
+	uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
3df8c3
+	uint32_t	sb_blocksize;	/* logical block size, bytes */
3df8c3
+	uint64_t	sb_dblocks;	/* number of data blocks */
3df8c3
+	uint64_t	sb_rblocks;	/* number of realtime blocks */
3df8c3
+	uint64_t	sb_rextents;	/* number of realtime extents */
3df8c3
+	unsigned char	sb_uuid[16];	/* file system unique id */
3df8c3
+	uint64_t	sb_logstart;	/* starting block of log if internal */
3df8c3
+	uint64_t	sb_rootino;	/* root inode number */
3df8c3
+	uint64_t	sb_rbmino;	/* bitmap inode for realtime extents */
3df8c3
+	uint64_t	sb_rsumino;	/* summary inode for rt bitmap */
3df8c3
+	uint32_t	sb_rextsize;	/* realtime extent size, blocks */
3df8c3
+	uint32_t	sb_agblocks;	/* size of an allocation group */
3df8c3
+	uint32_t	sb_agcount;	/* number of allocation groups */
3df8c3
+	uint32_t	sb_rbmblocks;	/* number of rt bitmap blocks */
3df8c3
+	uint32_t	sb_logblocks;	/* number of log blocks */
3df8c3
+
3df8c3
+	uint16_t	sb_versionnum;	/* header version == XFS_SB_VERSION */
3df8c3
+	uint16_t	sb_sectsize;	/* volume sector size, bytes */
3df8c3
+	uint16_t	sb_inodesize;	/* inode size, bytes */
3df8c3
+	uint16_t	sb_inopblock;	/* inodes per block */
3df8c3
+	char		sb_fname[12];	/* file system name */
3df8c3
+	uint8_t		sb_blocklog;	/* log2 of sb_blocksize */
3df8c3
+	uint8_t		sb_sectlog;	/* log2 of sb_sectsize */
3df8c3
+	uint8_t		sb_inodelog;	/* log2 of sb_inodesize */
3df8c3
+	uint8_t		sb_inopblog;	/* log2 of sb_inopblock */
3df8c3
+	uint8_t		sb_agblklog;	/* log2 of sb_agblocks (rounded up) */
3df8c3
+	uint8_t		sb_rextslog;	/* log2 of sb_rextents */
3df8c3
+	uint8_t		sb_inprogress;	/* mkfs is in progress, don't mount */
3df8c3
+	uint8_t		sb_imax_pct;	/* max % of fs for inode space */
3df8c3
+					/* statistics */
3df8c3
+	uint64_t	sb_icount;	/* allocated inodes */
3df8c3
+	uint64_t	sb_ifree;	/* free inodes */
3df8c3
+	uint64_t	sb_fdblocks;	/* free data blocks */
3df8c3
+	uint64_t	sb_frextents;	/* free realtime extents */
3df8c3
+
3df8c3
+	/* this is not all... but enough for libblkid */
3df8c3
+
3df8c3
 } __attribute__((packed));
3df8c3
 
3df8c3
+#define XFS_MIN_BLOCKSIZE_LOG	9	/* i.e. 512 bytes */
3df8c3
+#define XFS_MAX_BLOCKSIZE_LOG	16	/* i.e. 65536 bytes */
3df8c3
+#define XFS_MIN_BLOCKSIZE	(1 << XFS_MIN_BLOCKSIZE_LOG)
3df8c3
+#define XFS_MAX_BLOCKSIZE	(1 << XFS_MAX_BLOCKSIZE_LOG)
3df8c3
+#define XFS_MIN_SECTORSIZE_LOG	9	/* i.e. 512 bytes */
3df8c3
+#define XFS_MAX_SECTORSIZE_LOG	15	/* i.e. 32768 bytes */
3df8c3
+#define XFS_MIN_SECTORSIZE	(1 << XFS_MIN_SECTORSIZE_LOG)
3df8c3
+#define XFS_MAX_SECTORSIZE	(1 << XFS_MAX_SECTORSIZE_LOG)
3df8c3
+
3df8c3
+#define	XFS_DINODE_MIN_LOG	8
3df8c3
+#define	XFS_DINODE_MAX_LOG	11
3df8c3
+#define	XFS_DINODE_MIN_SIZE	(1 << XFS_DINODE_MIN_LOG)
3df8c3
+#define	XFS_DINODE_MAX_SIZE	(1 << XFS_DINODE_MAX_LOG)
3df8c3
+
3df8c3
+#define	XFS_MAX_RTEXTSIZE	(1024 * 1024 * 1024)	/* 1GB */
3df8c3
+#define	XFS_DFL_RTEXTSIZE	(64 * 1024)	        /* 64kB */
3df8c3
+#define	XFS_MIN_RTEXTSIZE	(4 * 1024)		/* 4kB */
3df8c3
+
3df8c3
+#define XFS_MIN_AG_BLOCKS	64
3df8c3
+#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks)
3df8c3
+#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) *	\
3df8c3
+			 (s)->sb_agblocks + XFS_MIN_AG_BLOCKS)
3df8c3
+
3df8c3
+
3df8c3
+static void sb_from_disk(struct xfs_super_block *from,
3df8c3
+			 struct xfs_super_block *to)
3df8c3
+{
3df8c3
+
3df8c3
+	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
3df8c3
+	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
3df8c3
+	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
3df8c3
+	to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
3df8c3
+	to->sb_rextents = be64_to_cpu(from->sb_rextents);
3df8c3
+	to->sb_logstart = be64_to_cpu(from->sb_logstart);
3df8c3
+	to->sb_rootino = be64_to_cpu(from->sb_rootino);
3df8c3
+	to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
3df8c3
+	to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
3df8c3
+	to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
3df8c3
+	to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
3df8c3
+	to->sb_agcount = be32_to_cpu(from->sb_agcount);
3df8c3
+	to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
3df8c3
+	to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
3df8c3
+	to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
3df8c3
+	to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
3df8c3
+	to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
3df8c3
+	to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
3df8c3
+	to->sb_blocklog = from->sb_blocklog;
3df8c3
+	to->sb_sectlog = from->sb_sectlog;
3df8c3
+	to->sb_inodelog = from->sb_inodelog;
3df8c3
+	to->sb_inopblog = from->sb_inopblog;
3df8c3
+	to->sb_agblklog = from->sb_agblklog;
3df8c3
+	to->sb_rextslog = from->sb_rextslog;
3df8c3
+	to->sb_inprogress = from->sb_inprogress;
3df8c3
+	to->sb_imax_pct = from->sb_imax_pct;
3df8c3
+	to->sb_icount = be64_to_cpu(from->sb_icount);
3df8c3
+	to->sb_ifree = be64_to_cpu(from->sb_ifree);
3df8c3
+	to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
3df8c3
+	to->sb_frextents = be64_to_cpu(from->sb_frextents);
3df8c3
+}
3df8c3
+
3df8c3
+static int xfs_verify_sb(struct xfs_super_block *ondisk)
3df8c3
+{
3df8c3
+	struct xfs_super_block sb, *sbp = &sb;
3df8c3
+
3df8c3
+	/* beXX_to_cpu(), but don't convert UUID and fsname! */
3df8c3
+	sb_from_disk(ondisk, sbp);
3df8c3
+
3df8c3
+	/* sanity checks, we don't want to rely on magic string only */
3df8c3
+	if (sbp->sb_agcount <= 0					||
3df8c3
+	    sbp->sb_sectsize < XFS_MIN_SECTORSIZE			||
3df8c3
+	    sbp->sb_sectsize > XFS_MAX_SECTORSIZE			||
3df8c3
+	    sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG			||
3df8c3
+	    sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG			||
3df8c3
+	    sbp->sb_sectsize != (1 << sbp->sb_sectlog)			||
3df8c3
+	    sbp->sb_blocksize < XFS_MIN_BLOCKSIZE			||
3df8c3
+	    sbp->sb_blocksize > XFS_MAX_BLOCKSIZE			||
3df8c3
+	    sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG			||
3df8c3
+	    sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG			||
3df8c3
+	    sbp->sb_blocksize != (1 << sbp->sb_blocklog)		||
3df8c3
+	    sbp->sb_inodesize < XFS_DINODE_MIN_SIZE			||
3df8c3
+	    sbp->sb_inodesize > XFS_DINODE_MAX_SIZE			||
3df8c3
+	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||
3df8c3
+	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||
3df8c3
+	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		||
3df8c3
+	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||
3df8c3
+	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||
3df8c3
+	    (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)	||
3df8c3
+	    (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)	||
3df8c3
+	    sbp->sb_dblocks == 0					||
3df8c3
+	    sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)			||
3df8c3
+	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))
3df8c3
+		return 0;
3df8c3
+
3df8c3
+	/* TODO: version 5 has also checksum CRC32, maybe we can check it too */
3df8c3
+
3df8c3
+	return 1;
3df8c3
+}
3df8c3
+
3df8c3
 static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag)
3df8c3
 {
3df8c3
 	struct xfs_super_block *xs;
3df8c3
@@ -42,10 +165,13 @@ static int probe_xfs(blkid_probe pr, con
3df8c3
 	if (!xs)
3df8c3
 		return errno ? -errno : 1;
3df8c3
 
3df8c3
-	if (strlen(xs->xs_fname))
3df8c3
-		blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname,
3df8c3
-				sizeof(xs->xs_fname));
3df8c3
-	blkid_probe_set_uuid(pr, xs->xs_uuid);
3df8c3
+	if (!xfs_verify_sb(xs))
3df8c3
+		return 1;
3df8c3
+
3df8c3
+	if (strlen(xs->sb_fname))
3df8c3
+		blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname,
3df8c3
+				sizeof(xs->sb_fname));
3df8c3
+	blkid_probe_set_uuid(pr, xs->sb_uuid);
3df8c3
 	return 0;
3df8c3
 }
3df8c3