1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * GSS Proxy upcall module 4 * 5 * Copyright (C) 2012 Simo Sorce <simo@redhat.com> 6 */ 7 8 #include <linux/sunrpc/svcauth.h> 9 #include "gss_rpc_xdr.h" 10 11 static int gssx_enc_bool(struct xdr_stream *xdr, int v) 12 { 13 __be32 *p; 14 15 p = xdr_reserve_space(xdr, 4); 16 if (unlikely(p == NULL)) 17 return -ENOSPC; 18 *p = v ? xdr_one : xdr_zero; 19 return 0; 20 } 21 22 static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v) 23 { 24 __be32 *p; 25 26 p = xdr_inline_decode(xdr, 4); 27 if (unlikely(p == NULL)) 28 return -ENOSPC; 29 *v = be32_to_cpu(*p); 30 return 0; 31 } 32 33 static int gssx_enc_buffer(struct xdr_stream *xdr, 34 const gssx_buffer *buf) 35 { 36 __be32 *p; 37 38 p = xdr_reserve_space(xdr, sizeof(u32) + buf->len); 39 if (!p) 40 return -ENOSPC; 41 xdr_encode_opaque(p, buf->data, buf->len); 42 return 0; 43 } 44 45 static int gssx_enc_in_token(struct xdr_stream *xdr, 46 const struct gssp_in_token *in) 47 { 48 __be32 *p; 49 50 p = xdr_reserve_space(xdr, 4); 51 if (!p) 52 return -ENOSPC; 53 *p = cpu_to_be32(in->page_len); 54 55 /* all we need to do is to write pages */ 56 xdr_write_pages(xdr, in->pages, in->page_base, in->page_len); 57 58 return 0; 59 } 60 61 62 static int gssx_dec_buffer(struct xdr_stream *xdr, 63 gssx_buffer *buf) 64 { 65 u32 length; 66 __be32 *p; 67 68 p = xdr_inline_decode(xdr, 4); 69 if (unlikely(p == NULL)) 70 return -ENOSPC; 71 72 length = be32_to_cpup(p); 73 p = xdr_inline_decode(xdr, length); 74 if (unlikely(p == NULL)) 75 return -ENOSPC; 76 77 if (buf->len == 0) { 78 /* we intentionally are not interested in this buffer */ 79 return 0; 80 } 81 if (length > buf->len) 82 return -ENOSPC; 83 84 if (!buf->data) { 85 buf->data = kmemdup(p, length, GFP_KERNEL); 86 if (!buf->data) 87 return -ENOMEM; 88 } else { 89 memcpy(buf->data, p, length); 90 } 91 buf->len = length; 92 return 0; 93 } 94 95 static int gssx_enc_option(struct xdr_stream *xdr, 96 struct gssx_option *opt) 97 { 98 int err; 99 100 err = gssx_enc_buffer(xdr, &opt->option); 101 if (err) 102 return err; 103 err = gssx_enc_buffer(xdr, &opt->value); 104 return err; 105 } 106 107 static int gssx_dec_option(struct xdr_stream *xdr, 108 struct gssx_option *opt) 109 { 110 int err; 111 112 err = gssx_dec_buffer(xdr, &opt->option); 113 if (err) 114 return err; 115 err = gssx_dec_buffer(xdr, &opt->value); 116 return err; 117 } 118 119 static int dummy_enc_opt_array(struct xdr_stream *xdr, 120 const struct gssx_option_array *oa) 121 { 122 __be32 *p; 123 124 if (oa->count != 0) 125 return -EINVAL; 126 127 p = xdr_reserve_space(xdr, 4); 128 if (!p) 129 return -ENOSPC; 130 *p = 0; 131 132 return 0; 133 } 134 135 static int dummy_dec_opt_array(struct xdr_stream *xdr, 136 struct gssx_option_array *oa) 137 { 138 struct gssx_option dummy; 139 u32 count, i; 140 __be32 *p; 141 142 p = xdr_inline_decode(xdr, 4); 143 if (unlikely(p == NULL)) 144 return -ENOSPC; 145 count = be32_to_cpup(p++); 146 memset(&dummy, 0, sizeof(dummy)); 147 for (i = 0; i < count; i++) { 148 gssx_dec_option(xdr, &dummy); 149 } 150 151 oa->count = 0; 152 oa->data = NULL; 153 return 0; 154 } 155 156 static int get_host_u32(struct xdr_stream *xdr, u32 *res) 157 { 158 __be32 *p; 159 160 p = xdr_inline_decode(xdr, 4); 161 if (!p) 162 return -EINVAL; 163 /* Contents of linux creds are all host-endian: */ 164 memcpy(res, p, sizeof(u32)); 165 return 0; 166 } 167 168 static int gssx_dec_linux_creds(struct xdr_stream *xdr, 169 struct svc_cred *creds) 170 { 171 u32 length; 172 __be32 *p; 173 u32 tmp; 174 u32 N; 175 int i, err; 176 177 p = xdr_inline_decode(xdr, 4); 178 if (unlikely(p == NULL)) 179 return -ENOSPC; 180 181 length = be32_to_cpup(p); 182 183 if (length > (3 + NGROUPS_MAX) * sizeof(u32)) 184 return -ENOSPC; 185 186 /* uid */ 187 err = get_host_u32(xdr, &tmp); 188 if (err) 189 return err; 190 creds->cr_uid = make_kuid(&init_user_ns, tmp); 191 192 /* gid */ 193 err = get_host_u32(xdr, &tmp); 194 if (err) 195 return err; 196 creds->cr_gid = make_kgid(&init_user_ns, tmp); 197 198 /* number of additional gid's */ 199 err = get_host_u32(xdr, &tmp); 200 if (err) 201 return err; 202 N = tmp; 203 if ((3 + N) * sizeof(u32) != length) 204 return -EINVAL; 205 creds->cr_group_info = groups_alloc(N); 206 if (creds->cr_group_info == NULL) 207 return -ENOMEM; 208 209 /* gid's */ 210 for (i = 0; i < N; i++) { 211 kgid_t kgid; 212 err = get_host_u32(xdr, &tmp); 213 if (err) 214 goto out_free_groups; 215 err = -EINVAL; 216 kgid = make_kgid(&init_user_ns, tmp); 217 if (!gid_valid(kgid)) 218 goto out_free_groups; 219 creds->cr_group_info->gid[i] = kgid; 220 } 221 groups_sort(creds->cr_group_info); 222 223 return 0; 224 out_free_groups: 225 groups_free(creds->cr_group_info); 226 return err; 227 } 228 229 static int gssx_dec_option_array(struct xdr_stream *xdr, 230 struct gssx_option_array *oa) 231 { 232 struct svc_cred *creds; 233 u32 count, i; 234 __be32 *p; 235 int err; 236 237 p = xdr_inline_decode(xdr, 4); 238 if (unlikely(p == NULL)) 239 return -ENOSPC; 240 count = be32_to_cpup(p++); 241 if (!count) 242 return 0; 243 244 /* we recognize only 1 currently: CREDS_VALUE */ 245 oa->count = 1; 246 247 oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL); 248 if (!oa->data) 249 return -ENOMEM; 250 251 creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL); 252 if (!creds) { 253 err = -ENOMEM; 254 goto free_oa; 255 } 256 257 oa->data[0].option.data = CREDS_VALUE; 258 oa->data[0].option.len = sizeof(CREDS_VALUE); 259 oa->data[0].value.data = (void *)creds; 260 oa->data[0].value.len = 0; 261 262 for (i = 0; i < count; i++) { 263 gssx_buffer dummy = { 0, NULL }; 264 u32 length; 265 266 /* option buffer */ 267 p = xdr_inline_decode(xdr, 4); 268 if (unlikely(p == NULL)) { 269 err = -ENOSPC; 270 goto free_creds; 271 } 272 273 length = be32_to_cpup(p); 274 p = xdr_inline_decode(xdr, length); 275 if (unlikely(p == NULL)) { 276 err = -ENOSPC; 277 goto free_creds; 278 } 279 280 if (length == sizeof(CREDS_VALUE) && 281 memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { 282 /* We have creds here. parse them */ 283 err = gssx_dec_linux_creds(xdr, creds); 284 if (err) 285 goto free_creds; 286 oa->data[0].value.len = 1; /* presence */ 287 } else { 288 /* consume uninteresting buffer */ 289 err = gssx_dec_buffer(xdr, &dummy); 290 if (err) 291 goto free_creds; 292 } 293 } 294 return 0; 295 296 free_creds: 297 kfree(creds); 298 free_oa: 299 kfree(oa->data); 300 oa->data = NULL; 301 return err; 302 } 303 304 static int gssx_dec_status(struct xdr_stream *xdr, 305 struct gssx_status *status) 306 { 307 __be32 *p; 308 int err; 309 310 /* status->major_status */ 311 p = xdr_inline_decode(xdr, 8); 312 if (unlikely(p == NULL)) 313 return -ENOSPC; 314 p = xdr_decode_hyper(p, &status->major_status); 315 316 /* status->mech */ 317 err = gssx_dec_buffer(xdr, &status->mech); 318 if (err) 319 return err; 320 321 /* status->minor_status */ 322 p = xdr_inline_decode(xdr, 8); 323 if (unlikely(p == NULL)) 324 return -ENOSPC; 325 p = xdr_decode_hyper(p, &status->minor_status); 326 327 /* status->major_status_string */ 328 err = gssx_dec_buffer(xdr, &status->major_status_string); 329 if (err) 330 return err; 331 332 /* status->minor_status_string */ 333 err = gssx_dec_buffer(xdr, &status->minor_status_string); 334 if (err) 335 return err; 336 337 /* status->server_ctx */ 338 err = gssx_dec_buffer(xdr, &status->server_ctx); 339 if (err) 340 return err; 341 342 /* we assume we have no options for now, so simply consume them */ 343 /* status->options */ 344 err = dummy_dec_opt_array(xdr, &status->options); 345 346 return err; 347 } 348 349 static int gssx_enc_call_ctx(struct xdr_stream *xdr, 350 const struct gssx_call_ctx *ctx) 351 { 352 struct gssx_option opt; 353 __be32 *p; 354 int err; 355 356 /* ctx->locale */ 357 err = gssx_enc_buffer(xdr, &ctx->locale); 358 if (err) 359 return err; 360 361 /* ctx->server_ctx */ 362 err = gssx_enc_buffer(xdr, &ctx->server_ctx); 363 if (err) 364 return err; 365 366 /* we always want to ask for lucid contexts */ 367 /* ctx->options */ 368 p = xdr_reserve_space(xdr, 4); 369 *p = cpu_to_be32(2); 370 371 /* we want a lucid_v1 context */ 372 opt.option.data = LUCID_OPTION; 373 opt.option.len = sizeof(LUCID_OPTION); 374 opt.value.data = LUCID_VALUE; 375 opt.value.len = sizeof(LUCID_VALUE); 376 err = gssx_enc_option(xdr, &opt); 377 378 /* ..and user creds */ 379 opt.option.data = CREDS_OPTION; 380 opt.option.len = sizeof(CREDS_OPTION); 381 opt.value.data = CREDS_VALUE; 382 opt.value.len = sizeof(CREDS_VALUE); 383 err = gssx_enc_option(xdr, &opt); 384 385 return err; 386 } 387 388 static int gssx_dec_name_attr(struct xdr_stream *xdr, 389 struct gssx_name_attr *attr) 390 { 391 int err; 392 393 /* attr->attr */ 394 err = gssx_dec_buffer(xdr, &attr->attr); 395 if (err) 396 return err; 397 398 /* attr->value */ 399 err = gssx_dec_buffer(xdr, &attr->value); 400 if (err) 401 return err; 402 403 /* attr->extensions */ 404 err = dummy_dec_opt_array(xdr, &attr->extensions); 405 406 return err; 407 } 408 409 static int dummy_enc_nameattr_array(struct xdr_stream *xdr, 410 struct gssx_name_attr_array *naa) 411 { 412 __be32 *p; 413 414 if (naa->count != 0) 415 return -EINVAL; 416 417 p = xdr_reserve_space(xdr, 4); 418 if (!p) 419 return -ENOSPC; 420 *p = 0; 421 422 return 0; 423 } 424 425 static int dummy_dec_nameattr_array(struct xdr_stream *xdr, 426 struct gssx_name_attr_array *naa) 427 { 428 struct gssx_name_attr dummy = { .attr = {.len = 0} }; 429 u32 count, i; 430 __be32 *p; 431 432 p = xdr_inline_decode(xdr, 4); 433 if (unlikely(p == NULL)) 434 return -ENOSPC; 435 count = be32_to_cpup(p++); 436 for (i = 0; i < count; i++) { 437 gssx_dec_name_attr(xdr, &dummy); 438 } 439 440 naa->count = 0; 441 naa->data = NULL; 442 return 0; 443 } 444 445 static struct xdr_netobj zero_netobj = {}; 446 447 static struct gssx_name_attr_array zero_name_attr_array = {}; 448 449 static struct gssx_option_array zero_option_array = {}; 450 451 static int gssx_enc_name(struct xdr_stream *xdr, 452 struct gssx_name *name) 453 { 454 int err; 455 456 /* name->display_name */ 457 err = gssx_enc_buffer(xdr, &name->display_name); 458 if (err) 459 return err; 460 461 /* name->name_type */ 462 err = gssx_enc_buffer(xdr, &zero_netobj); 463 if (err) 464 return err; 465 466 /* name->exported_name */ 467 err = gssx_enc_buffer(xdr, &zero_netobj); 468 if (err) 469 return err; 470 471 /* name->exported_composite_name */ 472 err = gssx_enc_buffer(xdr, &zero_netobj); 473 if (err) 474 return err; 475 476 /* leave name_attributes empty for now, will add once we have any 477 * to pass up at all */ 478 /* name->name_attributes */ 479 err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array); 480 if (err) 481 return err; 482 483 /* leave options empty for now, will add once we have any options 484 * to pass up at all */ 485 /* name->extensions */ 486 err = dummy_enc_opt_array(xdr, &zero_option_array); 487 488 return err; 489 } 490 491 492 static int gssx_dec_name(struct xdr_stream *xdr, 493 struct gssx_name *name) 494 { 495 struct xdr_netobj dummy_netobj = { .len = 0 }; 496 struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 }; 497 struct gssx_option_array dummy_option_array = { .count = 0 }; 498 int err; 499 500 /* name->display_name */ 501 err = gssx_dec_buffer(xdr, &name->display_name); 502 if (err) 503 return err; 504 505 /* name->name_type */ 506 err = gssx_dec_buffer(xdr, &dummy_netobj); 507 if (err) 508 return err; 509 510 /* name->exported_name */ 511 err = gssx_dec_buffer(xdr, &dummy_netobj); 512 if (err) 513 return err; 514 515 /* name->exported_composite_name */ 516 err = gssx_dec_buffer(xdr, &dummy_netobj); 517 if (err) 518 return err; 519 520 /* we assume we have no attributes for now, so simply consume them */ 521 /* name->name_attributes */ 522 err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array); 523 if (err) 524 return err; 525 526 /* we assume we have no options for now, so simply consume them */ 527 /* name->extensions */ 528 err = dummy_dec_opt_array(xdr, &dummy_option_array); 529 530 return err; 531 } 532 533 static int dummy_enc_credel_array(struct xdr_stream *xdr, 534 struct gssx_cred_element_array *cea) 535 { 536 __be32 *p; 537 538 if (cea->count != 0) 539 return -EINVAL; 540 541 p = xdr_reserve_space(xdr, 4); 542 if (!p) 543 return -ENOSPC; 544 *p = 0; 545 546 return 0; 547 } 548 549 static int gssx_enc_cred(struct xdr_stream *xdr, 550 struct gssx_cred *cred) 551 { 552 int err; 553 554 /* cred->desired_name */ 555 err = gssx_enc_name(xdr, &cred->desired_name); 556 if (err) 557 return err; 558 559 /* cred->elements */ 560 err = dummy_enc_credel_array(xdr, &cred->elements); 561 if (err) 562 return err; 563 564 /* cred->cred_handle_reference */ 565 err = gssx_enc_buffer(xdr, &cred->cred_handle_reference); 566 if (err) 567 return err; 568 569 /* cred->needs_release */ 570 err = gssx_enc_bool(xdr, cred->needs_release); 571 572 return err; 573 } 574 575 static int gssx_enc_ctx(struct xdr_stream *xdr, 576 struct gssx_ctx *ctx) 577 { 578 __be32 *p; 579 int err; 580 581 /* ctx->exported_context_token */ 582 err = gssx_enc_buffer(xdr, &ctx->exported_context_token); 583 if (err) 584 return err; 585 586 /* ctx->state */ 587 err = gssx_enc_buffer(xdr, &ctx->state); 588 if (err) 589 return err; 590 591 /* ctx->need_release */ 592 err = gssx_enc_bool(xdr, ctx->need_release); 593 if (err) 594 return err; 595 596 /* ctx->mech */ 597 err = gssx_enc_buffer(xdr, &ctx->mech); 598 if (err) 599 return err; 600 601 /* ctx->src_name */ 602 err = gssx_enc_name(xdr, &ctx->src_name); 603 if (err) 604 return err; 605 606 /* ctx->targ_name */ 607 err = gssx_enc_name(xdr, &ctx->targ_name); 608 if (err) 609 return err; 610 611 /* ctx->lifetime */ 612 p = xdr_reserve_space(xdr, 8+8); 613 if (!p) 614 return -ENOSPC; 615 p = xdr_encode_hyper(p, ctx->lifetime); 616 617 /* ctx->ctx_flags */ 618 p = xdr_encode_hyper(p, ctx->ctx_flags); 619 620 /* ctx->locally_initiated */ 621 err = gssx_enc_bool(xdr, ctx->locally_initiated); 622 if (err) 623 return err; 624 625 /* ctx->open */ 626 err = gssx_enc_bool(xdr, ctx->open); 627 if (err) 628 return err; 629 630 /* leave options empty for now, will add once we have any options 631 * to pass up at all */ 632 /* ctx->options */ 633 err = dummy_enc_opt_array(xdr, &ctx->options); 634 635 return err; 636 } 637 638 static int gssx_dec_ctx(struct xdr_stream *xdr, 639 struct gssx_ctx *ctx) 640 { 641 __be32 *p; 642 int err; 643 644 /* ctx->exported_context_token */ 645 err = gssx_dec_buffer(xdr, &ctx->exported_context_token); 646 if (err) 647 return err; 648 649 /* ctx->state */ 650 err = gssx_dec_buffer(xdr, &ctx->state); 651 if (err) 652 return err; 653 654 /* ctx->need_release */ 655 err = gssx_dec_bool(xdr, &ctx->need_release); 656 if (err) 657 return err; 658 659 /* ctx->mech */ 660 err = gssx_dec_buffer(xdr, &ctx->mech); 661 if (err) 662 return err; 663 664 /* ctx->src_name */ 665 err = gssx_dec_name(xdr, &ctx->src_name); 666 if (err) 667 return err; 668 669 /* ctx->targ_name */ 670 err = gssx_dec_name(xdr, &ctx->targ_name); 671 if (err) 672 return err; 673 674 /* ctx->lifetime */ 675 p = xdr_inline_decode(xdr, 8+8); 676 if (unlikely(p == NULL)) 677 return -ENOSPC; 678 p = xdr_decode_hyper(p, &ctx->lifetime); 679 680 /* ctx->ctx_flags */ 681 p = xdr_decode_hyper(p, &ctx->ctx_flags); 682 683 /* ctx->locally_initiated */ 684 err = gssx_dec_bool(xdr, &ctx->locally_initiated); 685 if (err) 686 return err; 687 688 /* ctx->open */ 689 err = gssx_dec_bool(xdr, &ctx->open); 690 if (err) 691 return err; 692 693 /* we assume we have no options for now, so simply consume them */ 694 /* ctx->options */ 695 err = dummy_dec_opt_array(xdr, &ctx->options); 696 697 return err; 698 } 699 700 static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb) 701 { 702 __be32 *p; 703 int err; 704 705 /* cb->initiator_addrtype */ 706 p = xdr_reserve_space(xdr, 8); 707 if (!p) 708 return -ENOSPC; 709 p = xdr_encode_hyper(p, cb->initiator_addrtype); 710 711 /* cb->initiator_address */ 712 err = gssx_enc_buffer(xdr, &cb->initiator_address); 713 if (err) 714 return err; 715 716 /* cb->acceptor_addrtype */ 717 p = xdr_reserve_space(xdr, 8); 718 if (!p) 719 return -ENOSPC; 720 p = xdr_encode_hyper(p, cb->acceptor_addrtype); 721 722 /* cb->acceptor_address */ 723 err = gssx_enc_buffer(xdr, &cb->acceptor_address); 724 if (err) 725 return err; 726 727 /* cb->application_data */ 728 err = gssx_enc_buffer(xdr, &cb->application_data); 729 730 return err; 731 } 732 733 void gssx_enc_accept_sec_context(struct rpc_rqst *req, 734 struct xdr_stream *xdr, 735 const void *data) 736 { 737 const struct gssx_arg_accept_sec_context *arg = data; 738 int err; 739 740 err = gssx_enc_call_ctx(xdr, &arg->call_ctx); 741 if (err) 742 goto done; 743 744 /* arg->context_handle */ 745 if (arg->context_handle) 746 err = gssx_enc_ctx(xdr, arg->context_handle); 747 else 748 err = gssx_enc_bool(xdr, 0); 749 if (err) 750 goto done; 751 752 /* arg->cred_handle */ 753 if (arg->cred_handle) 754 err = gssx_enc_cred(xdr, arg->cred_handle); 755 else 756 err = gssx_enc_bool(xdr, 0); 757 if (err) 758 goto done; 759 760 /* arg->input_token */ 761 err = gssx_enc_in_token(xdr, &arg->input_token); 762 if (err) 763 goto done; 764 765 /* arg->input_cb */ 766 if (arg->input_cb) 767 err = gssx_enc_cb(xdr, arg->input_cb); 768 else 769 err = gssx_enc_bool(xdr, 0); 770 if (err) 771 goto done; 772 773 err = gssx_enc_bool(xdr, arg->ret_deleg_cred); 774 if (err) 775 goto done; 776 777 /* leave options empty for now, will add once we have any options 778 * to pass up at all */ 779 /* arg->options */ 780 err = dummy_enc_opt_array(xdr, &arg->options); 781 782 xdr_inline_pages(&req->rq_rcv_buf, 783 PAGE_SIZE/2 /* pretty arbitrary */, 784 arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); 785 done: 786 if (err) 787 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); 788 } 789 790 int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, 791 struct xdr_stream *xdr, 792 void *data) 793 { 794 struct gssx_res_accept_sec_context *res = data; 795 u32 value_follows; 796 int err; 797 struct page *scratch; 798 799 scratch = alloc_page(GFP_KERNEL); 800 if (!scratch) 801 return -ENOMEM; 802 xdr_set_scratch_page(xdr, scratch); 803 804 /* res->status */ 805 err = gssx_dec_status(xdr, &res->status); 806 if (err) 807 goto out_free; 808 809 /* res->context_handle */ 810 err = gssx_dec_bool(xdr, &value_follows); 811 if (err) 812 goto out_free; 813 if (value_follows) { 814 err = gssx_dec_ctx(xdr, res->context_handle); 815 if (err) 816 goto out_free; 817 } else { 818 res->context_handle = NULL; 819 } 820 821 /* res->output_token */ 822 err = gssx_dec_bool(xdr, &value_follows); 823 if (err) 824 goto out_free; 825 if (value_follows) { 826 err = gssx_dec_buffer(xdr, res->output_token); 827 if (err) 828 goto out_free; 829 } else { 830 res->output_token = NULL; 831 } 832 833 /* res->delegated_cred_handle */ 834 err = gssx_dec_bool(xdr, &value_follows); 835 if (err) 836 goto out_free; 837 if (value_follows) { 838 /* we do not support upcall servers sending this data. */ 839 err = -EINVAL; 840 goto out_free; 841 } 842 843 /* res->options */ 844 err = gssx_dec_option_array(xdr, &res->options); 845 846 out_free: 847 __free_page(scratch); 848 return err; 849 } 850