brintos

brintos / linux-shallow public Read only

0
0
Text · 9.7 KiB · 3507d8f Raw
515 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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		ksmbd_debug(VFS, "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		ksmbd_debug(VFS, "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 mnt_idmap *idmap,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	vfsuid_t vfsuid;349	vfsgid_t vfsgid;350 351	n->offset = 0;352	n->length = 1024;353	n->data = kzalloc(n->length, GFP_KERNEL);354	if (!n->data)355		return -ENOMEM;356 357	if (acl) {358		/* ACL ACCESS */359		ret = ndr_write_int32(n, ref_id);360		ref_id += 4;361	} else {362		ret = ndr_write_int32(n, 0);363	}364	if (ret)365		return ret;366 367	if (def_acl) {368		/* DEFAULT ACL ACCESS */369		ret = ndr_write_int32(n, ref_id);370		ref_id += 4;371	} else {372		ret = ndr_write_int32(n, 0);373	}374	if (ret)375		return ret;376 377	vfsuid = i_uid_into_vfsuid(idmap, inode);378	ret = ndr_write_int64(n, from_kuid(&init_user_ns, vfsuid_into_kuid(vfsuid)));379	if (ret)380		return ret;381	vfsgid = i_gid_into_vfsgid(idmap, inode);382	ret = ndr_write_int64(n, from_kgid(&init_user_ns, vfsgid_into_kgid(vfsgid)));383	if (ret)384		return ret;385	ret = ndr_write_int32(n, inode->i_mode);386	if (ret)387		return ret;388 389	if (acl) {390		ret = ndr_encode_posix_acl_entry(n, acl);391		if (def_acl && !ret)392			ret = ndr_encode_posix_acl_entry(n, def_acl);393	}394	return ret;395}396 397int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)398{399	unsigned int ref_id = 0x00020004;400	int ret;401 402	n->offset = 0;403	n->length = 2048;404	n->data = kzalloc(n->length, GFP_KERNEL);405	if (!n->data)406		return -ENOMEM;407 408	ret = ndr_write_int16(n, acl->version);409	if (ret)410		return ret;411 412	ret = ndr_write_int32(n, acl->version);413	if (ret)414		return ret;415 416	ret = ndr_write_int16(n, 2);417	if (ret)418		return ret;419 420	ret = ndr_write_int32(n, ref_id);421	if (ret)422		return ret;423 424	/* push hash type and hash 64bytes */425	ret = ndr_write_int16(n, acl->hash_type);426	if (ret)427		return ret;428 429	ret = ndr_write_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);430	if (ret)431		return ret;432 433	ret = ndr_write_bytes(n, acl->desc, acl->desc_len);434	if (ret)435		return ret;436 437	ret = ndr_write_int64(n, acl->current_time);438	if (ret)439		return ret;440 441	ret = ndr_write_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);442	if (ret)443		return ret;444 445	/* push ndr for security descriptor */446	ret = ndr_write_bytes(n, acl->sd_buf, acl->sd_size);447	return ret;448}449 450int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)451{452	unsigned int version2;453	int ret;454 455	n->offset = 0;456	ret = ndr_read_int16(n, &acl->version);457	if (ret)458		return ret;459	if (acl->version != 4) {460		ksmbd_debug(VFS, "v%d version is not supported\n", acl->version);461		return -EINVAL;462	}463 464	ret = ndr_read_int32(n, &version2);465	if (ret)466		return ret;467	if (acl->version != version2) {468		ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n",469		       acl->version, version2);470		return -EINVAL;471	}472 473	/* Read Level */474	ret = ndr_read_int16(n, NULL);475	if (ret)476		return ret;477 478	/* Read Ref Id */479	ret = ndr_read_int32(n, NULL);480	if (ret)481		return ret;482 483	ret = ndr_read_int16(n, &acl->hash_type);484	if (ret)485		return ret;486 487	ret = ndr_read_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);488	if (ret)489		return ret;490 491	ndr_read_bytes(n, acl->desc, 10);492	if (strncmp(acl->desc, "posix_acl", 9)) {493		pr_err("Invalid acl description : %s\n", acl->desc);494		return -EINVAL;495	}496 497	/* Read Time */498	ret = ndr_read_int64(n, NULL);499	if (ret)500		return ret;501 502	/* Read Posix ACL hash */503	ret = ndr_read_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);504	if (ret)505		return ret;506 507	acl->sd_size = n->length - n->offset;508	acl->sd_buf = kzalloc(acl->sd_size, GFP_KERNEL);509	if (!acl->sd_buf)510		return -ENOMEM;511 512	ret = ndr_read_bytes(n, acl->sd_buf, acl->sd_size);513	return ret;514}515