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}