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 12 static inline char *ndr_get_field(struct ndr *n) 13 { 14 return n->data + n->offset; 15 } 16 17 static 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 31 static 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 46 static 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 61 static 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 76 static 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 91 static 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 110 static 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 126 static 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 137 static 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 148 static 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 159 static 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 170 int 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 229 int 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 296 static 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 340 int 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 397 int 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 450 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.