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

ndr.c (9833B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *   Copyright (C) 2021 Samsung Electronics Co., Ltd.
      4 *   Author(s): Namjae Jeon <linkinjeon@kernel.org>
      5 */
      6
      7#include <linux/fs.h>
      8
      9#include "glob.h"
     10#include "ndr.h"
     11
     12static inline char *ndr_get_field(struct ndr *n)
     13{
     14	return n->data + n->offset;
     15}
     16
     17static int try_to_realloc_ndr_blob(struct ndr *n, size_t sz)
     18{
     19	char *data;
     20
     21	data = krealloc(n->data, n->offset + sz + 1024, GFP_KERNEL);
     22	if (!data)
     23		return -ENOMEM;
     24
     25	n->data = data;
     26	n->length += 1024;
     27	memset(n->data + n->offset, 0, 1024);
     28	return 0;
     29}
     30
     31static int ndr_write_int16(struct ndr *n, __u16 value)
     32{
     33	if (n->length <= n->offset + sizeof(value)) {
     34		int ret;
     35
     36		ret = try_to_realloc_ndr_blob(n, sizeof(value));
     37		if (ret)
     38			return ret;
     39	}
     40
     41	*(__le16 *)ndr_get_field(n) = cpu_to_le16(value);
     42	n->offset += sizeof(value);
     43	return 0;
     44}
     45
     46static int ndr_write_int32(struct ndr *n, __u32 value)
     47{
     48	if (n->length <= n->offset + sizeof(value)) {
     49		int ret;
     50
     51		ret = try_to_realloc_ndr_blob(n, sizeof(value));
     52		if (ret)
     53			return ret;
     54	}
     55
     56	*(__le32 *)ndr_get_field(n) = cpu_to_le32(value);
     57	n->offset += sizeof(value);
     58	return 0;
     59}
     60
     61static int ndr_write_int64(struct ndr *n, __u64 value)
     62{
     63	if (n->length <= n->offset + sizeof(value)) {
     64		int ret;
     65
     66		ret = try_to_realloc_ndr_blob(n, sizeof(value));
     67		if (ret)
     68			return ret;
     69	}
     70
     71	*(__le64 *)ndr_get_field(n) = cpu_to_le64(value);
     72	n->offset += sizeof(value);
     73	return 0;
     74}
     75
     76static int ndr_write_bytes(struct ndr *n, void *value, size_t sz)
     77{
     78	if (n->length <= n->offset + sz) {
     79		int ret;
     80
     81		ret = try_to_realloc_ndr_blob(n, sz);
     82		if (ret)
     83			return ret;
     84	}
     85
     86	memcpy(ndr_get_field(n), value, sz);
     87	n->offset += sz;
     88	return 0;
     89}
     90
     91static int ndr_write_string(struct ndr *n, char *value)
     92{
     93	size_t sz;
     94
     95	sz = strlen(value) + 1;
     96	if (n->length <= n->offset + sz) {
     97		int ret;
     98
     99		ret = try_to_realloc_ndr_blob(n, sz);
    100		if (ret)
    101			return ret;
    102	}
    103
    104	memcpy(ndr_get_field(n), value, sz);
    105	n->offset += sz;
    106	n->offset = ALIGN(n->offset, 2);
    107	return 0;
    108}
    109
    110static int ndr_read_string(struct ndr *n, void *value, size_t sz)
    111{
    112	int len;
    113
    114	if (n->offset + sz > n->length)
    115		return -EINVAL;
    116
    117	len = strnlen(ndr_get_field(n), sz);
    118	if (value)
    119		memcpy(value, ndr_get_field(n), len);
    120	len++;
    121	n->offset += len;
    122	n->offset = ALIGN(n->offset, 2);
    123	return 0;
    124}
    125
    126static int ndr_read_bytes(struct ndr *n, void *value, size_t sz)
    127{
    128	if (n->offset + sz > n->length)
    129		return -EINVAL;
    130
    131	if (value)
    132		memcpy(value, ndr_get_field(n), sz);
    133	n->offset += sz;
    134	return 0;
    135}
    136
    137static int ndr_read_int16(struct ndr *n, __u16 *value)
    138{
    139	if (n->offset + sizeof(__u16) > n->length)
    140		return -EINVAL;
    141
    142	if (value)
    143		*value = le16_to_cpu(*(__le16 *)ndr_get_field(n));
    144	n->offset += sizeof(__u16);
    145	return 0;
    146}
    147
    148static int ndr_read_int32(struct ndr *n, __u32 *value)
    149{
    150	if (n->offset + sizeof(__u32) > n->length)
    151		return -EINVAL;
    152
    153	if (value)
    154		*value = le32_to_cpu(*(__le32 *)ndr_get_field(n));
    155	n->offset += sizeof(__u32);
    156	return 0;
    157}
    158
    159static int ndr_read_int64(struct ndr *n, __u64 *value)
    160{
    161	if (n->offset + sizeof(__u64) > n->length)
    162		return -EINVAL;
    163
    164	if (value)
    165		*value = le64_to_cpu(*(__le64 *)ndr_get_field(n));
    166	n->offset += sizeof(__u64);
    167	return 0;
    168}
    169
    170int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
    171{
    172	char hex_attr[12] = {0};
    173	int ret;
    174
    175	n->offset = 0;
    176	n->length = 1024;
    177	n->data = kzalloc(n->length, GFP_KERNEL);
    178	if (!n->data)
    179		return -ENOMEM;
    180
    181	if (da->version == 3) {
    182		snprintf(hex_attr, 10, "0x%x", da->attr);
    183		ret = ndr_write_string(n, hex_attr);
    184	} else {
    185		ret = ndr_write_string(n, "");
    186	}
    187	if (ret)
    188		return ret;
    189
    190	ret = ndr_write_int16(n, da->version);
    191	if (ret)
    192		return ret;
    193
    194	ret = ndr_write_int32(n, da->version);
    195	if (ret)
    196		return ret;
    197
    198	ret = ndr_write_int32(n, da->flags);
    199	if (ret)
    200		return ret;
    201
    202	ret = ndr_write_int32(n, da->attr);
    203	if (ret)
    204		return ret;
    205
    206	if (da->version == 3) {
    207		ret = ndr_write_int32(n, da->ea_size);
    208		if (ret)
    209			return ret;
    210		ret = ndr_write_int64(n, da->size);
    211		if (ret)
    212			return ret;
    213		ret = ndr_write_int64(n, da->alloc_size);
    214	} else {
    215		ret = ndr_write_int64(n, da->itime);
    216	}
    217	if (ret)
    218		return ret;
    219
    220	ret = ndr_write_int64(n, da->create_time);
    221	if (ret)
    222		return ret;
    223
    224	if (da->version == 3)
    225		ret = ndr_write_int64(n, da->change_time);
    226	return ret;
    227}
    228
    229int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
    230{
    231	char hex_attr[12];
    232	unsigned int version2;
    233	int ret;
    234
    235	n->offset = 0;
    236	ret = ndr_read_string(n, hex_attr, sizeof(hex_attr));
    237	if (ret)
    238		return ret;
    239
    240	ret = ndr_read_int16(n, &da->version);
    241	if (ret)
    242		return ret;
    243
    244	if (da->version != 3 && da->version != 4) {
    245		pr_err("v%d version is not supported\n", da->version);
    246		return -EINVAL;
    247	}
    248
    249	ret = ndr_read_int32(n, &version2);
    250	if (ret)
    251		return ret;
    252
    253	if (da->version != version2) {
    254		pr_err("ndr version mismatched(version: %d, version2: %d)\n",
    255		       da->version, version2);
    256		return -EINVAL;
    257	}
    258
    259	ret = ndr_read_int32(n, NULL);
    260	if (ret)
    261		return ret;
    262
    263	ret = ndr_read_int32(n, &da->attr);
    264	if (ret)
    265		return ret;
    266
    267	if (da->version == 4) {
    268		ret = ndr_read_int64(n, &da->itime);
    269		if (ret)
    270			return ret;
    271
    272		ret = ndr_read_int64(n, &da->create_time);
    273	} else {
    274		ret = ndr_read_int32(n, NULL);
    275		if (ret)
    276			return ret;
    277
    278		ret = ndr_read_int64(n, NULL);
    279		if (ret)
    280			return ret;
    281
    282		ret = ndr_read_int64(n, NULL);
    283		if (ret)
    284			return ret;
    285
    286		ret = ndr_read_int64(n, &da->create_time);
    287		if (ret)
    288			return ret;
    289
    290		ret = ndr_read_int64(n, NULL);
    291	}
    292
    293	return ret;
    294}
    295
    296static int ndr_encode_posix_acl_entry(struct ndr *n, struct xattr_smb_acl *acl)
    297{
    298	int i, ret;
    299
    300	ret = ndr_write_int32(n, acl->count);
    301	if (ret)
    302		return ret;
    303
    304	n->offset = ALIGN(n->offset, 8);
    305	ret = ndr_write_int32(n, acl->count);
    306	if (ret)
    307		return ret;
    308
    309	ret = ndr_write_int32(n, 0);
    310	if (ret)
    311		return ret;
    312
    313	for (i = 0; i < acl->count; i++) {
    314		n->offset = ALIGN(n->offset, 8);
    315		ret = ndr_write_int16(n, acl->entries[i].type);
    316		if (ret)
    317			return ret;
    318
    319		ret = ndr_write_int16(n, acl->entries[i].type);
    320		if (ret)
    321			return ret;
    322
    323		if (acl->entries[i].type == SMB_ACL_USER) {
    324			n->offset = ALIGN(n->offset, 8);
    325			ret = ndr_write_int64(n, acl->entries[i].uid);
    326		} else if (acl->entries[i].type == SMB_ACL_GROUP) {
    327			n->offset = ALIGN(n->offset, 8);
    328			ret = ndr_write_int64(n, acl->entries[i].gid);
    329		}
    330		if (ret)
    331			return ret;
    332
    333		/* push permission */
    334		ret = ndr_write_int32(n, acl->entries[i].perm);
    335	}
    336
    337	return ret;
    338}
    339
    340int ndr_encode_posix_acl(struct ndr *n,
    341			 struct user_namespace *user_ns,
    342			 struct inode *inode,
    343			 struct xattr_smb_acl *acl,
    344			 struct xattr_smb_acl *def_acl)
    345{
    346	unsigned int ref_id = 0x00020000;
    347	int ret;
    348
    349	n->offset = 0;
    350	n->length = 1024;
    351	n->data = kzalloc(n->length, GFP_KERNEL);
    352	if (!n->data)
    353		return -ENOMEM;
    354
    355	if (acl) {
    356		/* ACL ACCESS */
    357		ret = ndr_write_int32(n, ref_id);
    358		ref_id += 4;
    359	} else {
    360		ret = ndr_write_int32(n, 0);
    361	}
    362	if (ret)
    363		return ret;
    364
    365	if (def_acl) {
    366		/* DEFAULT ACL ACCESS */
    367		ret = ndr_write_int32(n, ref_id);
    368		ref_id += 4;
    369	} else {
    370		ret = ndr_write_int32(n, 0);
    371	}
    372	if (ret)
    373		return ret;
    374
    375	ret = ndr_write_int64(n, from_kuid(&init_user_ns, i_uid_into_mnt(user_ns, inode)));
    376	if (ret)
    377		return ret;
    378	ret = ndr_write_int64(n, from_kgid(&init_user_ns, i_gid_into_mnt(user_ns, inode)));
    379	if (ret)
    380		return ret;
    381	ret = ndr_write_int32(n, inode->i_mode);
    382	if (ret)
    383		return ret;
    384
    385	if (acl) {
    386		ret = ndr_encode_posix_acl_entry(n, acl);
    387		if (def_acl && !ret)
    388			ret = ndr_encode_posix_acl_entry(n, def_acl);
    389	}
    390	return ret;
    391}
    392
    393int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
    394{
    395	unsigned int ref_id = 0x00020004;
    396	int ret;
    397
    398	n->offset = 0;
    399	n->length = 2048;
    400	n->data = kzalloc(n->length, GFP_KERNEL);
    401	if (!n->data)
    402		return -ENOMEM;
    403
    404	ret = ndr_write_int16(n, acl->version);
    405	if (ret)
    406		return ret;
    407
    408	ret = ndr_write_int32(n, acl->version);
    409	if (ret)
    410		return ret;
    411
    412	ret = ndr_write_int16(n, 2);
    413	if (ret)
    414		return ret;
    415
    416	ret = ndr_write_int32(n, ref_id);
    417	if (ret)
    418		return ret;
    419
    420	/* push hash type and hash 64bytes */
    421	ret = ndr_write_int16(n, acl->hash_type);
    422	if (ret)
    423		return ret;
    424
    425	ret = ndr_write_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
    426	if (ret)
    427		return ret;
    428
    429	ret = ndr_write_bytes(n, acl->desc, acl->desc_len);
    430	if (ret)
    431		return ret;
    432
    433	ret = ndr_write_int64(n, acl->current_time);
    434	if (ret)
    435		return ret;
    436
    437	ret = ndr_write_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
    438	if (ret)
    439		return ret;
    440
    441	/* push ndr for security descriptor */
    442	ret = ndr_write_bytes(n, acl->sd_buf, acl->sd_size);
    443	return ret;
    444}
    445
    446int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
    447{
    448	unsigned int version2;
    449	int ret;
    450
    451	n->offset = 0;
    452	ret = ndr_read_int16(n, &acl->version);
    453	if (ret)
    454		return ret;
    455	if (acl->version != 4) {
    456		pr_err("v%d version is not supported\n", acl->version);
    457		return -EINVAL;
    458	}
    459
    460	ret = ndr_read_int32(n, &version2);
    461	if (ret)
    462		return ret;
    463	if (acl->version != version2) {
    464		pr_err("ndr version mismatched(version: %d, version2: %d)\n",
    465		       acl->version, version2);
    466		return -EINVAL;
    467	}
    468
    469	/* Read Level */
    470	ret = ndr_read_int16(n, NULL);
    471	if (ret)
    472		return ret;
    473
    474	/* Read Ref Id */
    475	ret = ndr_read_int32(n, NULL);
    476	if (ret)
    477		return ret;
    478
    479	ret = ndr_read_int16(n, &acl->hash_type);
    480	if (ret)
    481		return ret;
    482
    483	ret = ndr_read_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
    484	if (ret)
    485		return ret;
    486
    487	ndr_read_bytes(n, acl->desc, 10);
    488	if (strncmp(acl->desc, "posix_acl", 9)) {
    489		pr_err("Invalid acl description : %s\n", acl->desc);
    490		return -EINVAL;
    491	}
    492
    493	/* Read Time */
    494	ret = ndr_read_int64(n, NULL);
    495	if (ret)
    496		return ret;
    497
    498	/* Read Posix ACL hash */
    499	ret = ndr_read_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
    500	if (ret)
    501		return ret;
    502
    503	acl->sd_size = n->length - n->offset;
    504	acl->sd_buf = kzalloc(acl->sd_size, GFP_KERNEL);
    505	if (!acl->sd_buf)
    506		return -ENOMEM;
    507
    508	ret = ndr_read_bytes(n, acl->sd_buf, acl->sd_size);
    509	return ret;
    510}