cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

misc.c (8135B)


      1/*
      2 * misc.c
      3 *
      4 * PURPOSE
      5 *	Miscellaneous routines for the OSTA-UDF(tm) filesystem.
      6 *
      7 * COPYRIGHT
      8 *	This file is distributed under the terms of the GNU General Public
      9 *	License (GPL). Copies of the GPL can be obtained from:
     10 *		ftp://prep.ai.mit.edu/pub/gnu/GPL
     11 *	Each contributing author retains all rights to their own work.
     12 *
     13 *  (C) 1998 Dave Boynton
     14 *  (C) 1998-2004 Ben Fennema
     15 *  (C) 1999-2000 Stelias Computing Inc
     16 *
     17 * HISTORY
     18 *
     19 *  04/19/99 blf  partial support for reading/writing specific EA's
     20 */
     21
     22#include "udfdecl.h"
     23
     24#include <linux/fs.h>
     25#include <linux/string.h>
     26#include <linux/crc-itu-t.h>
     27
     28#include "udf_i.h"
     29#include "udf_sb.h"
     30
     31struct buffer_head *udf_tgetblk(struct super_block *sb, udf_pblk_t block)
     32{
     33	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
     34		return sb_getblk(sb, udf_fixed_to_variable(block));
     35	else
     36		return sb_getblk(sb, block);
     37}
     38
     39struct buffer_head *udf_tread(struct super_block *sb, udf_pblk_t block)
     40{
     41	if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
     42		return sb_bread(sb, udf_fixed_to_variable(block));
     43	else
     44		return sb_bread(sb, block);
     45}
     46
     47struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
     48					   uint32_t type, uint8_t loc)
     49{
     50	uint8_t *ea = NULL, *ad = NULL;
     51	int offset;
     52	uint16_t crclen;
     53	struct udf_inode_info *iinfo = UDF_I(inode);
     54
     55	ea = iinfo->i_data;
     56	if (iinfo->i_lenEAttr) {
     57		ad = iinfo->i_data + iinfo->i_lenEAttr;
     58	} else {
     59		ad = ea;
     60		size += sizeof(struct extendedAttrHeaderDesc);
     61	}
     62
     63	offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
     64		iinfo->i_lenAlloc;
     65
     66	/* TODO - Check for FreeEASpace */
     67
     68	if (loc & 0x01 && offset >= size) {
     69		struct extendedAttrHeaderDesc *eahd;
     70		eahd = (struct extendedAttrHeaderDesc *)ea;
     71
     72		if (iinfo->i_lenAlloc)
     73			memmove(&ad[size], ad, iinfo->i_lenAlloc);
     74
     75		if (iinfo->i_lenEAttr) {
     76			/* check checksum/crc */
     77			if (eahd->descTag.tagIdent !=
     78					cpu_to_le16(TAG_IDENT_EAHD) ||
     79			    le32_to_cpu(eahd->descTag.tagLocation) !=
     80					iinfo->i_location.logicalBlockNum)
     81				return NULL;
     82		} else {
     83			struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
     84
     85			size -= sizeof(struct extendedAttrHeaderDesc);
     86			iinfo->i_lenEAttr +=
     87				sizeof(struct extendedAttrHeaderDesc);
     88			eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
     89			if (sbi->s_udfrev >= 0x0200)
     90				eahd->descTag.descVersion = cpu_to_le16(3);
     91			else
     92				eahd->descTag.descVersion = cpu_to_le16(2);
     93			eahd->descTag.tagSerialNum =
     94					cpu_to_le16(sbi->s_serial_number);
     95			eahd->descTag.tagLocation = cpu_to_le32(
     96					iinfo->i_location.logicalBlockNum);
     97			eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
     98			eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
     99		}
    100
    101		offset = iinfo->i_lenEAttr;
    102		if (type < 2048) {
    103			if (le32_to_cpu(eahd->appAttrLocation) <
    104					iinfo->i_lenEAttr) {
    105				uint32_t aal =
    106					le32_to_cpu(eahd->appAttrLocation);
    107				memmove(&ea[offset - aal + size],
    108					&ea[aal], offset - aal);
    109				offset -= aal;
    110				eahd->appAttrLocation =
    111						cpu_to_le32(aal + size);
    112			}
    113			if (le32_to_cpu(eahd->impAttrLocation) <
    114					iinfo->i_lenEAttr) {
    115				uint32_t ial =
    116					le32_to_cpu(eahd->impAttrLocation);
    117				memmove(&ea[offset - ial + size],
    118					&ea[ial], offset - ial);
    119				offset -= ial;
    120				eahd->impAttrLocation =
    121						cpu_to_le32(ial + size);
    122			}
    123		} else if (type < 65536) {
    124			if (le32_to_cpu(eahd->appAttrLocation) <
    125					iinfo->i_lenEAttr) {
    126				uint32_t aal =
    127					le32_to_cpu(eahd->appAttrLocation);
    128				memmove(&ea[offset - aal + size],
    129					&ea[aal], offset - aal);
    130				offset -= aal;
    131				eahd->appAttrLocation =
    132						cpu_to_le32(aal + size);
    133			}
    134		}
    135		/* rewrite CRC + checksum of eahd */
    136		crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(struct tag);
    137		eahd->descTag.descCRCLength = cpu_to_le16(crclen);
    138		eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
    139						sizeof(struct tag), crclen));
    140		eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
    141		iinfo->i_lenEAttr += size;
    142		return (struct genericFormat *)&ea[offset];
    143	}
    144
    145	return NULL;
    146}
    147
    148struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
    149					   uint8_t subtype)
    150{
    151	struct genericFormat *gaf;
    152	uint8_t *ea = NULL;
    153	uint32_t offset;
    154	struct udf_inode_info *iinfo = UDF_I(inode);
    155
    156	ea = iinfo->i_data;
    157
    158	if (iinfo->i_lenEAttr) {
    159		struct extendedAttrHeaderDesc *eahd;
    160		eahd = (struct extendedAttrHeaderDesc *)ea;
    161
    162		/* check checksum/crc */
    163		if (eahd->descTag.tagIdent !=
    164				cpu_to_le16(TAG_IDENT_EAHD) ||
    165		    le32_to_cpu(eahd->descTag.tagLocation) !=
    166				iinfo->i_location.logicalBlockNum)
    167			return NULL;
    168
    169		if (type < 2048)
    170			offset = sizeof(struct extendedAttrHeaderDesc);
    171		else if (type < 65536)
    172			offset = le32_to_cpu(eahd->impAttrLocation);
    173		else
    174			offset = le32_to_cpu(eahd->appAttrLocation);
    175
    176		while (offset + sizeof(*gaf) < iinfo->i_lenEAttr) {
    177			uint32_t attrLength;
    178
    179			gaf = (struct genericFormat *)&ea[offset];
    180			attrLength = le32_to_cpu(gaf->attrLength);
    181
    182			/* Detect undersized elements and buffer overflows */
    183			if ((attrLength < sizeof(*gaf)) ||
    184			    (attrLength > (iinfo->i_lenEAttr - offset)))
    185				break;
    186
    187			if (le32_to_cpu(gaf->attrType) == type &&
    188					gaf->attrSubtype == subtype)
    189				return gaf;
    190			else
    191				offset += attrLength;
    192		}
    193	}
    194
    195	return NULL;
    196}
    197
    198/*
    199 * udf_read_tagged
    200 *
    201 * PURPOSE
    202 *	Read the first block of a tagged descriptor.
    203 *
    204 * HISTORY
    205 *	July 1, 1997 - Andrew E. Mileski
    206 *	Written, tested, and released.
    207 */
    208struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
    209				    uint32_t location, uint16_t *ident)
    210{
    211	struct tag *tag_p;
    212	struct buffer_head *bh = NULL;
    213	u8 checksum;
    214
    215	/* Read the block */
    216	if (block == 0xFFFFFFFF)
    217		return NULL;
    218
    219	bh = udf_tread(sb, block);
    220	if (!bh) {
    221		udf_err(sb, "read failed, block=%u, location=%u\n",
    222			block, location);
    223		return NULL;
    224	}
    225
    226	tag_p = (struct tag *)(bh->b_data);
    227
    228	*ident = le16_to_cpu(tag_p->tagIdent);
    229
    230	if (location != le32_to_cpu(tag_p->tagLocation)) {
    231		udf_debug("location mismatch block %u, tag %u != %u\n",
    232			  block, le32_to_cpu(tag_p->tagLocation), location);
    233		goto error_out;
    234	}
    235
    236	/* Verify the tag checksum */
    237	checksum = udf_tag_checksum(tag_p);
    238	if (checksum != tag_p->tagChecksum) {
    239		udf_err(sb, "tag checksum failed, block %u: 0x%02x != 0x%02x\n",
    240			block, checksum, tag_p->tagChecksum);
    241		goto error_out;
    242	}
    243
    244	/* Verify the tag version */
    245	if (tag_p->descVersion != cpu_to_le16(0x0002U) &&
    246	    tag_p->descVersion != cpu_to_le16(0x0003U)) {
    247		udf_err(sb, "tag version 0x%04x != 0x0002 || 0x0003, block %u\n",
    248			le16_to_cpu(tag_p->descVersion), block);
    249		goto error_out;
    250	}
    251
    252	/* Verify the descriptor CRC */
    253	if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize ||
    254	    le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
    255					bh->b_data + sizeof(struct tag),
    256					le16_to_cpu(tag_p->descCRCLength)))
    257		return bh;
    258
    259	udf_debug("Crc failure block %u: crc = %u, crclen = %u\n", block,
    260		  le16_to_cpu(tag_p->descCRC),
    261		  le16_to_cpu(tag_p->descCRCLength));
    262error_out:
    263	brelse(bh);
    264	return NULL;
    265}
    266
    267struct buffer_head *udf_read_ptagged(struct super_block *sb,
    268				     struct kernel_lb_addr *loc,
    269				     uint32_t offset, uint16_t *ident)
    270{
    271	return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
    272			       loc->logicalBlockNum + offset, ident);
    273}
    274
    275void udf_update_tag(char *data, int length)
    276{
    277	struct tag *tptr = (struct tag *)data;
    278	length -= sizeof(struct tag);
    279
    280	tptr->descCRCLength = cpu_to_le16(length);
    281	tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(struct tag), length));
    282	tptr->tagChecksum = udf_tag_checksum(tptr);
    283}
    284
    285void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
    286		 uint32_t loc, int length)
    287{
    288	struct tag *tptr = (struct tag *)data;
    289	tptr->tagIdent = cpu_to_le16(ident);
    290	tptr->descVersion = cpu_to_le16(version);
    291	tptr->tagSerialNum = cpu_to_le16(snum);
    292	tptr->tagLocation = cpu_to_le32(loc);
    293	udf_update_tag(data, length);
    294}
    295
    296u8 udf_tag_checksum(const struct tag *t)
    297{
    298	u8 *data = (u8 *)t;
    299	u8 checksum = 0;
    300	int i;
    301	for (i = 0; i < sizeof(struct tag); ++i)
    302		if (i != 4) /* position of checksum */
    303			checksum += data[i];
    304	return checksum;
    305}