| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Neil Brown <neilb@cse.unsw.edu.au> |
|---|
| 3 | 4 | * J. Bruce Fields <bfields@umich.edu> |
|---|
| .. | .. |
|---|
| 48 | 49 | #include <linux/sunrpc/svcauth.h> |
|---|
| 49 | 50 | #include <linux/sunrpc/svcauth_gss.h> |
|---|
| 50 | 51 | #include <linux/sunrpc/cache.h> |
|---|
| 52 | + |
|---|
| 53 | +#include <trace/events/rpcgss.h> |
|---|
| 54 | + |
|---|
| 51 | 55 | #include "gss_rpc_upcall.h" |
|---|
| 52 | 56 | |
|---|
| 53 | | - |
|---|
| 54 | | -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
|---|
| 55 | | -# define RPCDBG_FACILITY RPCDBG_AUTH |
|---|
| 56 | | -#endif |
|---|
| 57 | 57 | |
|---|
| 58 | 58 | /* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests |
|---|
| 59 | 59 | * into replies. |
|---|
| .. | .. |
|---|
| 76 | 76 | struct xdr_netobj in_handle, in_token; |
|---|
| 77 | 77 | struct xdr_netobj out_handle, out_token; |
|---|
| 78 | 78 | int major_status, minor_status; |
|---|
| 79 | + struct rcu_head rcu_head; |
|---|
| 79 | 80 | }; |
|---|
| 80 | 81 | |
|---|
| 81 | 82 | static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old); |
|---|
| .. | .. |
|---|
| 89 | 90 | kfree(rsii->out_token.data); |
|---|
| 90 | 91 | } |
|---|
| 91 | 92 | |
|---|
| 93 | +static void rsi_free_rcu(struct rcu_head *head) |
|---|
| 94 | +{ |
|---|
| 95 | + struct rsi *rsii = container_of(head, struct rsi, rcu_head); |
|---|
| 96 | + |
|---|
| 97 | + rsi_free(rsii); |
|---|
| 98 | + kfree(rsii); |
|---|
| 99 | +} |
|---|
| 100 | + |
|---|
| 92 | 101 | static void rsi_put(struct kref *ref) |
|---|
| 93 | 102 | { |
|---|
| 94 | 103 | struct rsi *rsii = container_of(ref, struct rsi, h.ref); |
|---|
| 95 | | - rsi_free(rsii); |
|---|
| 96 | | - kfree(rsii); |
|---|
| 104 | + |
|---|
| 105 | + call_rcu(&rsii->rcu_head, rsi_free_rcu); |
|---|
| 97 | 106 | } |
|---|
| 98 | 107 | |
|---|
| 99 | 108 | static inline int rsi_hash(struct rsi *item) |
|---|
| .. | .. |
|---|
| 171 | 180 | return NULL; |
|---|
| 172 | 181 | } |
|---|
| 173 | 182 | |
|---|
| 183 | +static int rsi_upcall(struct cache_detail *cd, struct cache_head *h) |
|---|
| 184 | +{ |
|---|
| 185 | + return sunrpc_cache_pipe_upcall_timeout(cd, h); |
|---|
| 186 | +} |
|---|
| 187 | + |
|---|
| 174 | 188 | static void rsi_request(struct cache_detail *cd, |
|---|
| 175 | 189 | struct cache_head *h, |
|---|
| 176 | 190 | char **bpp, int *blen) |
|---|
| .. | .. |
|---|
| 190 | 204 | char *ep; |
|---|
| 191 | 205 | int len; |
|---|
| 192 | 206 | struct rsi rsii, *rsip = NULL; |
|---|
| 193 | | - time_t expiry; |
|---|
| 207 | + time64_t expiry; |
|---|
| 194 | 208 | int status = -EINVAL; |
|---|
| 195 | 209 | |
|---|
| 196 | 210 | memset(&rsii, 0, sizeof(rsii)); |
|---|
| .. | .. |
|---|
| 269 | 283 | .hash_size = RSI_HASHMAX, |
|---|
| 270 | 284 | .name = "auth.rpcsec.init", |
|---|
| 271 | 285 | .cache_put = rsi_put, |
|---|
| 286 | + .cache_upcall = rsi_upcall, |
|---|
| 272 | 287 | .cache_request = rsi_request, |
|---|
| 273 | 288 | .cache_parse = rsi_parse, |
|---|
| 274 | 289 | .match = rsi_match, |
|---|
| .. | .. |
|---|
| 282 | 297 | struct cache_head *ch; |
|---|
| 283 | 298 | int hash = rsi_hash(item); |
|---|
| 284 | 299 | |
|---|
| 285 | | - ch = sunrpc_cache_lookup(cd, &item->h, hash); |
|---|
| 300 | + ch = sunrpc_cache_lookup_rcu(cd, &item->h, hash); |
|---|
| 286 | 301 | if (ch) |
|---|
| 287 | 302 | return container_of(ch, struct rsi, h); |
|---|
| 288 | 303 | else |
|---|
| .. | .. |
|---|
| 317 | 332 | |
|---|
| 318 | 333 | struct gss_svc_seq_data { |
|---|
| 319 | 334 | /* highest seq number seen so far: */ |
|---|
| 320 | | - int sd_max; |
|---|
| 335 | + u32 sd_max; |
|---|
| 321 | 336 | /* for i such that sd_max-GSS_SEQ_WIN < i <= sd_max, the i-th bit of |
|---|
| 322 | 337 | * sd_win is nonzero iff sequence number i has been seen already: */ |
|---|
| 323 | 338 | unsigned long sd_win[GSS_SEQ_WIN/BITS_PER_LONG]; |
|---|
| .. | .. |
|---|
| 330 | 345 | struct svc_cred cred; |
|---|
| 331 | 346 | struct gss_svc_seq_data seqdata; |
|---|
| 332 | 347 | struct gss_ctx *mechctx; |
|---|
| 348 | + struct rcu_head rcu_head; |
|---|
| 333 | 349 | }; |
|---|
| 334 | 350 | |
|---|
| 335 | 351 | static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old); |
|---|
| .. | .. |
|---|
| 343 | 359 | free_svc_cred(&rsci->cred); |
|---|
| 344 | 360 | } |
|---|
| 345 | 361 | |
|---|
| 362 | +static void rsc_free_rcu(struct rcu_head *head) |
|---|
| 363 | +{ |
|---|
| 364 | + struct rsc *rsci = container_of(head, struct rsc, rcu_head); |
|---|
| 365 | + |
|---|
| 366 | + kfree(rsci->handle.data); |
|---|
| 367 | + kfree(rsci); |
|---|
| 368 | +} |
|---|
| 369 | + |
|---|
| 346 | 370 | static void rsc_put(struct kref *ref) |
|---|
| 347 | 371 | { |
|---|
| 348 | 372 | struct rsc *rsci = container_of(ref, struct rsc, h.ref); |
|---|
| 349 | 373 | |
|---|
| 350 | | - rsc_free(rsci); |
|---|
| 351 | | - kfree(rsci); |
|---|
| 374 | + if (rsci->mechctx) |
|---|
| 375 | + gss_delete_sec_context(&rsci->mechctx); |
|---|
| 376 | + free_svc_cred(&rsci->cred); |
|---|
| 377 | + call_rcu(&rsci->rcu_head, rsc_free_rcu); |
|---|
| 352 | 378 | } |
|---|
| 353 | 379 | |
|---|
| 354 | 380 | static inline int |
|---|
| .. | .. |
|---|
| 404 | 430 | return NULL; |
|---|
| 405 | 431 | } |
|---|
| 406 | 432 | |
|---|
| 433 | +static int rsc_upcall(struct cache_detail *cd, struct cache_head *h) |
|---|
| 434 | +{ |
|---|
| 435 | + return -EINVAL; |
|---|
| 436 | +} |
|---|
| 437 | + |
|---|
| 407 | 438 | static int rsc_parse(struct cache_detail *cd, |
|---|
| 408 | 439 | char *mesg, int mlen) |
|---|
| 409 | 440 | { |
|---|
| .. | .. |
|---|
| 412 | 443 | int id; |
|---|
| 413 | 444 | int len, rv; |
|---|
| 414 | 445 | struct rsc rsci, *rscp = NULL; |
|---|
| 415 | | - time_t expiry; |
|---|
| 446 | + time64_t expiry; |
|---|
| 416 | 447 | int status = -EINVAL; |
|---|
| 417 | 448 | struct gss_api_mech *gm = NULL; |
|---|
| 418 | 449 | |
|---|
| .. | .. |
|---|
| 453 | 484 | * treatment so are checked for validity here.) |
|---|
| 454 | 485 | */ |
|---|
| 455 | 486 | /* uid */ |
|---|
| 456 | | - rsci.cred.cr_uid = make_kuid(&init_user_ns, id); |
|---|
| 487 | + rsci.cred.cr_uid = make_kuid(current_user_ns(), id); |
|---|
| 457 | 488 | |
|---|
| 458 | 489 | /* gid */ |
|---|
| 459 | 490 | if (get_int(&mesg, &id)) |
|---|
| 460 | 491 | goto out; |
|---|
| 461 | | - rsci.cred.cr_gid = make_kgid(&init_user_ns, id); |
|---|
| 492 | + rsci.cred.cr_gid = make_kgid(current_user_ns(), id); |
|---|
| 462 | 493 | |
|---|
| 463 | 494 | /* number of additional gid's */ |
|---|
| 464 | 495 | if (get_int(&mesg, &N)) |
|---|
| .. | .. |
|---|
| 476 | 507 | kgid_t kgid; |
|---|
| 477 | 508 | if (get_int(&mesg, &id)) |
|---|
| 478 | 509 | goto out; |
|---|
| 479 | | - kgid = make_kgid(&init_user_ns, id); |
|---|
| 510 | + kgid = make_kgid(current_user_ns(), id); |
|---|
| 480 | 511 | if (!gid_valid(kgid)) |
|---|
| 481 | 512 | goto out; |
|---|
| 482 | 513 | rsci.cred.cr_group_info->gid[i] = kgid; |
|---|
| .. | .. |
|---|
| 530 | 561 | .hash_size = RSC_HASHMAX, |
|---|
| 531 | 562 | .name = "auth.rpcsec.context", |
|---|
| 532 | 563 | .cache_put = rsc_put, |
|---|
| 564 | + .cache_upcall = rsc_upcall, |
|---|
| 533 | 565 | .cache_parse = rsc_parse, |
|---|
| 534 | 566 | .match = rsc_match, |
|---|
| 535 | 567 | .init = rsc_init, |
|---|
| .. | .. |
|---|
| 542 | 574 | struct cache_head *ch; |
|---|
| 543 | 575 | int hash = rsc_hash(item); |
|---|
| 544 | 576 | |
|---|
| 545 | | - ch = sunrpc_cache_lookup(cd, &item->h, hash); |
|---|
| 577 | + ch = sunrpc_cache_lookup_rcu(cd, &item->h, hash); |
|---|
| 546 | 578 | if (ch) |
|---|
| 547 | 579 | return container_of(ch, struct rsc, h); |
|---|
| 548 | 580 | else |
|---|
| .. | .. |
|---|
| 581 | 613 | return found; |
|---|
| 582 | 614 | } |
|---|
| 583 | 615 | |
|---|
| 584 | | -/* Implements sequence number algorithm as specified in RFC 2203. */ |
|---|
| 585 | | -static int |
|---|
| 586 | | -gss_check_seq_num(struct rsc *rsci, int seq_num) |
|---|
| 616 | +/** |
|---|
| 617 | + * gss_check_seq_num - GSS sequence number window check |
|---|
| 618 | + * @rqstp: RPC Call to use when reporting errors |
|---|
| 619 | + * @rsci: cached GSS context state (updated on return) |
|---|
| 620 | + * @seq_num: sequence number to check |
|---|
| 621 | + * |
|---|
| 622 | + * Implements sequence number algorithm as specified in |
|---|
| 623 | + * RFC 2203, Section 5.3.3.1. "Context Management". |
|---|
| 624 | + * |
|---|
| 625 | + * Return values: |
|---|
| 626 | + * %true: @rqstp's GSS sequence number is inside the window |
|---|
| 627 | + * %false: @rqstp's GSS sequence number is outside the window |
|---|
| 628 | + */ |
|---|
| 629 | +static bool gss_check_seq_num(const struct svc_rqst *rqstp, struct rsc *rsci, |
|---|
| 630 | + u32 seq_num) |
|---|
| 587 | 631 | { |
|---|
| 588 | 632 | struct gss_svc_seq_data *sd = &rsci->seqdata; |
|---|
| 633 | + bool result = false; |
|---|
| 589 | 634 | |
|---|
| 590 | 635 | spin_lock(&sd->sd_lock); |
|---|
| 591 | 636 | if (seq_num > sd->sd_max) { |
|---|
| 592 | 637 | if (seq_num >= sd->sd_max + GSS_SEQ_WIN) { |
|---|
| 593 | | - memset(sd->sd_win,0,sizeof(sd->sd_win)); |
|---|
| 638 | + memset(sd->sd_win, 0, sizeof(sd->sd_win)); |
|---|
| 594 | 639 | sd->sd_max = seq_num; |
|---|
| 595 | 640 | } else while (sd->sd_max < seq_num) { |
|---|
| 596 | 641 | sd->sd_max++; |
|---|
| .. | .. |
|---|
| 598 | 643 | } |
|---|
| 599 | 644 | __set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win); |
|---|
| 600 | 645 | goto ok; |
|---|
| 601 | | - } else if (seq_num <= sd->sd_max - GSS_SEQ_WIN) { |
|---|
| 602 | | - goto drop; |
|---|
| 646 | + } else if (seq_num + GSS_SEQ_WIN <= sd->sd_max) { |
|---|
| 647 | + goto toolow; |
|---|
| 603 | 648 | } |
|---|
| 604 | | - /* sd_max - GSS_SEQ_WIN < seq_num <= sd_max */ |
|---|
| 605 | 649 | if (__test_and_set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win)) |
|---|
| 606 | | - goto drop; |
|---|
| 650 | + goto alreadyseen; |
|---|
| 651 | + |
|---|
| 607 | 652 | ok: |
|---|
| 653 | + result = true; |
|---|
| 654 | +out: |
|---|
| 608 | 655 | spin_unlock(&sd->sd_lock); |
|---|
| 609 | | - return 1; |
|---|
| 610 | | -drop: |
|---|
| 611 | | - spin_unlock(&sd->sd_lock); |
|---|
| 612 | | - return 0; |
|---|
| 656 | + return result; |
|---|
| 657 | + |
|---|
| 658 | +toolow: |
|---|
| 659 | + trace_rpcgss_svc_seqno_low(rqstp, seq_num, |
|---|
| 660 | + sd->sd_max - GSS_SEQ_WIN, |
|---|
| 661 | + sd->sd_max); |
|---|
| 662 | + goto out; |
|---|
| 663 | +alreadyseen: |
|---|
| 664 | + trace_rpcgss_svc_seqno_seen(rqstp, seq_num); |
|---|
| 665 | + goto out; |
|---|
| 613 | 666 | } |
|---|
| 614 | 667 | |
|---|
| 615 | 668 | static inline u32 round_up_to_quad(u32 i) |
|---|
| .. | .. |
|---|
| 689 | 742 | } |
|---|
| 690 | 743 | |
|---|
| 691 | 744 | if (gc->gc_seq > MAXSEQ) { |
|---|
| 692 | | - dprintk("RPC: svcauth_gss: discarding request with " |
|---|
| 693 | | - "large sequence number %d\n", gc->gc_seq); |
|---|
| 745 | + trace_rpcgss_svc_seqno_large(rqstp, gc->gc_seq); |
|---|
| 694 | 746 | *authp = rpcsec_gsserr_ctxproblem; |
|---|
| 695 | 747 | return SVC_DENIED; |
|---|
| 696 | 748 | } |
|---|
| 697 | | - if (!gss_check_seq_num(rsci, gc->gc_seq)) { |
|---|
| 698 | | - dprintk("RPC: svcauth_gss: discarding request with " |
|---|
| 699 | | - "old sequence number %d\n", gc->gc_seq); |
|---|
| 749 | + if (!gss_check_seq_num(rqstp, rsci, gc->gc_seq)) |
|---|
| 700 | 750 | return SVC_DROP; |
|---|
| 701 | | - } |
|---|
| 702 | 751 | return SVC_OK; |
|---|
| 703 | 752 | } |
|---|
| 704 | 753 | |
|---|
| .. | .. |
|---|
| 836 | 885 | static int |
|---|
| 837 | 886 | unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx) |
|---|
| 838 | 887 | { |
|---|
| 888 | + u32 integ_len, rseqno, maj_stat; |
|---|
| 839 | 889 | int stat = -EINVAL; |
|---|
| 840 | | - u32 integ_len, maj_stat; |
|---|
| 841 | 890 | struct xdr_netobj mic; |
|---|
| 842 | 891 | struct xdr_buf integ_buf; |
|---|
| 892 | + |
|---|
| 893 | + mic.data = NULL; |
|---|
| 843 | 894 | |
|---|
| 844 | 895 | /* NFS READ normally uses splice to send data in-place. However |
|---|
| 845 | 896 | * the data in cache can change after the reply's MIC is computed |
|---|
| .. | .. |
|---|
| 855 | 906 | |
|---|
| 856 | 907 | integ_len = svc_getnl(&buf->head[0]); |
|---|
| 857 | 908 | if (integ_len & 3) |
|---|
| 858 | | - return stat; |
|---|
| 909 | + goto unwrap_failed; |
|---|
| 859 | 910 | if (integ_len > buf->len) |
|---|
| 860 | | - return stat; |
|---|
| 861 | | - if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len)) { |
|---|
| 862 | | - WARN_ON_ONCE(1); |
|---|
| 863 | | - return stat; |
|---|
| 864 | | - } |
|---|
| 911 | + goto unwrap_failed; |
|---|
| 912 | + if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len)) |
|---|
| 913 | + goto unwrap_failed; |
|---|
| 914 | + |
|---|
| 865 | 915 | /* copy out mic... */ |
|---|
| 866 | 916 | if (read_u32_from_xdr_buf(buf, integ_len, &mic.len)) |
|---|
| 867 | | - return stat; |
|---|
| 917 | + goto unwrap_failed; |
|---|
| 868 | 918 | if (mic.len > RPC_MAX_AUTH_SIZE) |
|---|
| 869 | | - return stat; |
|---|
| 919 | + goto unwrap_failed; |
|---|
| 870 | 920 | mic.data = kmalloc(mic.len, GFP_KERNEL); |
|---|
| 871 | 921 | if (!mic.data) |
|---|
| 872 | | - return stat; |
|---|
| 922 | + goto unwrap_failed; |
|---|
| 873 | 923 | if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len)) |
|---|
| 874 | | - goto out; |
|---|
| 924 | + goto unwrap_failed; |
|---|
| 875 | 925 | maj_stat = gss_verify_mic(ctx, &integ_buf, &mic); |
|---|
| 876 | 926 | if (maj_stat != GSS_S_COMPLETE) |
|---|
| 877 | | - goto out; |
|---|
| 878 | | - if (svc_getnl(&buf->head[0]) != seq) |
|---|
| 879 | | - goto out; |
|---|
| 927 | + goto bad_mic; |
|---|
| 928 | + rseqno = svc_getnl(&buf->head[0]); |
|---|
| 929 | + if (rseqno != seq) |
|---|
| 930 | + goto bad_seqno; |
|---|
| 880 | 931 | /* trim off the mic and padding at the end before returning */ |
|---|
| 881 | 932 | xdr_buf_trim(buf, round_up_to_quad(mic.len) + 4); |
|---|
| 882 | 933 | stat = 0; |
|---|
| 883 | 934 | out: |
|---|
| 884 | 935 | kfree(mic.data); |
|---|
| 885 | 936 | return stat; |
|---|
| 937 | + |
|---|
| 938 | +unwrap_failed: |
|---|
| 939 | + trace_rpcgss_svc_unwrap_failed(rqstp); |
|---|
| 940 | + goto out; |
|---|
| 941 | +bad_seqno: |
|---|
| 942 | + trace_rpcgss_svc_seqno_bad(rqstp, seq, rseqno); |
|---|
| 943 | + goto out; |
|---|
| 944 | +bad_mic: |
|---|
| 945 | + trace_rpcgss_svc_mic(rqstp, maj_stat); |
|---|
| 946 | + goto out; |
|---|
| 886 | 947 | } |
|---|
| 887 | 948 | |
|---|
| 888 | 949 | static inline int |
|---|
| .. | .. |
|---|
| 906 | 967 | unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx) |
|---|
| 907 | 968 | { |
|---|
| 908 | 969 | u32 priv_len, maj_stat; |
|---|
| 909 | | - int pad, saved_len, remaining_len, offset; |
|---|
| 970 | + int pad, remaining_len, offset; |
|---|
| 971 | + u32 rseqno; |
|---|
| 910 | 972 | |
|---|
| 911 | 973 | clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); |
|---|
| 912 | 974 | |
|---|
| .. | .. |
|---|
| 921 | 983 | * not yet read from the head, so these two values are different: */ |
|---|
| 922 | 984 | remaining_len = total_buf_len(buf); |
|---|
| 923 | 985 | if (priv_len > remaining_len) |
|---|
| 924 | | - return -EINVAL; |
|---|
| 986 | + goto unwrap_failed; |
|---|
| 925 | 987 | pad = remaining_len - priv_len; |
|---|
| 926 | 988 | buf->len -= pad; |
|---|
| 927 | 989 | fix_priv_head(buf, pad); |
|---|
| 928 | 990 | |
|---|
| 929 | | - /* Maybe it would be better to give gss_unwrap a length parameter: */ |
|---|
| 930 | | - saved_len = buf->len; |
|---|
| 931 | | - buf->len = priv_len; |
|---|
| 932 | | - maj_stat = gss_unwrap(ctx, 0, buf); |
|---|
| 991 | + maj_stat = gss_unwrap(ctx, 0, priv_len, buf); |
|---|
| 933 | 992 | pad = priv_len - buf->len; |
|---|
| 934 | | - buf->len = saved_len; |
|---|
| 935 | | - buf->len -= pad; |
|---|
| 936 | 993 | /* The upper layers assume the buffer is aligned on 4-byte boundaries. |
|---|
| 937 | 994 | * In the krb5p case, at least, the data ends up offset, so we need to |
|---|
| 938 | 995 | * move it around. */ |
|---|
| 939 | 996 | /* XXX: This is very inefficient. It would be better to either do |
|---|
| 940 | 997 | * this while we encrypt, or maybe in the receive code, if we can peak |
|---|
| 941 | 998 | * ahead and work out the service and mechanism there. */ |
|---|
| 942 | | - offset = buf->head[0].iov_len % 4; |
|---|
| 999 | + offset = xdr_pad_size(buf->head[0].iov_len); |
|---|
| 943 | 1000 | if (offset) { |
|---|
| 944 | 1001 | buf->buflen = RPCSVC_MAXPAYLOAD; |
|---|
| 945 | 1002 | xdr_shift_buf(buf, offset); |
|---|
| 946 | 1003 | fix_priv_head(buf, pad); |
|---|
| 947 | 1004 | } |
|---|
| 948 | 1005 | if (maj_stat != GSS_S_COMPLETE) |
|---|
| 949 | | - return -EINVAL; |
|---|
| 1006 | + goto bad_unwrap; |
|---|
| 950 | 1007 | out_seq: |
|---|
| 951 | | - if (svc_getnl(&buf->head[0]) != seq) |
|---|
| 952 | | - return -EINVAL; |
|---|
| 1008 | + rseqno = svc_getnl(&buf->head[0]); |
|---|
| 1009 | + if (rseqno != seq) |
|---|
| 1010 | + goto bad_seqno; |
|---|
| 953 | 1011 | return 0; |
|---|
| 1012 | + |
|---|
| 1013 | +unwrap_failed: |
|---|
| 1014 | + trace_rpcgss_svc_unwrap_failed(rqstp); |
|---|
| 1015 | + return -EINVAL; |
|---|
| 1016 | +bad_seqno: |
|---|
| 1017 | + trace_rpcgss_svc_seqno_bad(rqstp, seq, rseqno); |
|---|
| 1018 | + return -EINVAL; |
|---|
| 1019 | +bad_unwrap: |
|---|
| 1020 | + trace_rpcgss_svc_unwrap(rqstp, maj_stat); |
|---|
| 1021 | + return -EINVAL; |
|---|
| 954 | 1022 | } |
|---|
| 955 | 1023 | |
|---|
| 956 | 1024 | struct gss_svc_data { |
|---|
| .. | .. |
|---|
| 1088 | 1156 | return res; |
|---|
| 1089 | 1157 | |
|---|
| 1090 | 1158 | inlen = svc_getnl(argv); |
|---|
| 1091 | | - if (inlen > (argv->iov_len + rqstp->rq_arg.page_len)) |
|---|
| 1159 | + if (inlen > (argv->iov_len + rqstp->rq_arg.page_len)) { |
|---|
| 1160 | + kfree(in_handle->data); |
|---|
| 1092 | 1161 | return SVC_DENIED; |
|---|
| 1162 | + } |
|---|
| 1093 | 1163 | |
|---|
| 1094 | 1164 | pages = DIV_ROUND_UP(inlen, PAGE_SIZE); |
|---|
| 1095 | 1165 | in_token->pages = kcalloc(pages, sizeof(struct page *), GFP_KERNEL); |
|---|
| 1096 | | - if (!in_token->pages) |
|---|
| 1166 | + if (!in_token->pages) { |
|---|
| 1167 | + kfree(in_handle->data); |
|---|
| 1097 | 1168 | return SVC_DENIED; |
|---|
| 1169 | + } |
|---|
| 1098 | 1170 | in_token->page_base = 0; |
|---|
| 1099 | 1171 | in_token->page_len = inlen; |
|---|
| 1100 | 1172 | for (i = 0; i < pages; i++) { |
|---|
| 1101 | 1173 | in_token->pages[i] = alloc_page(GFP_KERNEL); |
|---|
| 1102 | 1174 | if (!in_token->pages[i]) { |
|---|
| 1175 | + kfree(in_handle->data); |
|---|
| 1103 | 1176 | gss_free_in_token_pages(in_token); |
|---|
| 1104 | 1177 | return SVC_DENIED; |
|---|
| 1105 | 1178 | } |
|---|
| .. | .. |
|---|
| 1206 | 1279 | static atomic64_t ctxhctr; |
|---|
| 1207 | 1280 | long long ctxh; |
|---|
| 1208 | 1281 | struct gss_api_mech *gm = NULL; |
|---|
| 1209 | | - time_t expiry; |
|---|
| 1282 | + time64_t expiry; |
|---|
| 1210 | 1283 | int status = -EINVAL; |
|---|
| 1211 | 1284 | |
|---|
| 1212 | 1285 | memset(&rsci, 0, sizeof(rsci)); |
|---|
| .. | .. |
|---|
| 1230 | 1303 | if (!ud->found_creds) { |
|---|
| 1231 | 1304 | /* userspace seem buggy, we should always get at least a |
|---|
| 1232 | 1305 | * mapping to nobody */ |
|---|
| 1233 | | - dprintk("RPC: No creds found!\n"); |
|---|
| 1234 | 1306 | goto out; |
|---|
| 1235 | 1307 | } else { |
|---|
| 1236 | 1308 | struct timespec64 boot; |
|---|
| .. | .. |
|---|
| 1296 | 1368 | if (status) |
|---|
| 1297 | 1369 | goto out; |
|---|
| 1298 | 1370 | |
|---|
| 1299 | | - dprintk("RPC: svcauth_gss: gss major status = %d " |
|---|
| 1300 | | - "minor status = %d\n", |
|---|
| 1301 | | - ud.major_status, ud.minor_status); |
|---|
| 1371 | + trace_rpcgss_svc_accept_upcall(rqstp, ud.major_status, ud.minor_status); |
|---|
| 1302 | 1372 | |
|---|
| 1303 | 1373 | switch (ud.major_status) { |
|---|
| 1304 | 1374 | case GSS_S_CONTINUE_NEEDED: |
|---|
| .. | .. |
|---|
| 1306 | 1376 | break; |
|---|
| 1307 | 1377 | case GSS_S_COMPLETE: |
|---|
| 1308 | 1378 | status = gss_proxy_save_rsc(sn->rsc_cache, &ud, &handle); |
|---|
| 1309 | | - if (status) { |
|---|
| 1310 | | - pr_info("%s: gss_proxy_save_rsc failed (%d)\n", |
|---|
| 1311 | | - __func__, status); |
|---|
| 1379 | + if (status) |
|---|
| 1312 | 1380 | goto out; |
|---|
| 1313 | | - } |
|---|
| 1314 | 1381 | cli_handle.data = (u8 *)&handle; |
|---|
| 1315 | 1382 | cli_handle.len = sizeof(handle); |
|---|
| 1316 | 1383 | break; |
|---|
| 1317 | 1384 | default: |
|---|
| 1318 | | - ret = SVC_CLOSE; |
|---|
| 1319 | 1385 | goto out; |
|---|
| 1320 | 1386 | } |
|---|
| 1321 | 1387 | |
|---|
| 1322 | 1388 | /* Got an answer to the upcall; use it: */ |
|---|
| 1323 | 1389 | if (gss_write_init_verf(sn->rsc_cache, rqstp, |
|---|
| 1324 | | - &cli_handle, &ud.major_status)) { |
|---|
| 1325 | | - pr_info("%s: gss_write_init_verf failed\n", __func__); |
|---|
| 1390 | + &cli_handle, &ud.major_status)) |
|---|
| 1326 | 1391 | goto out; |
|---|
| 1327 | | - } |
|---|
| 1328 | 1392 | if (gss_write_resv(resv, PAGE_SIZE, |
|---|
| 1329 | 1393 | &cli_handle, &ud.out_token, |
|---|
| 1330 | | - ud.major_status, ud.minor_status)) { |
|---|
| 1331 | | - pr_info("%s: gss_write_resv failed\n", __func__); |
|---|
| 1394 | + ud.major_status, ud.minor_status)) |
|---|
| 1332 | 1395 | goto out; |
|---|
| 1333 | | - } |
|---|
| 1334 | 1396 | |
|---|
| 1335 | 1397 | ret = SVC_COMPLETE; |
|---|
| 1336 | 1398 | out: |
|---|
| .. | .. |
|---|
| 1418 | 1480 | return len; |
|---|
| 1419 | 1481 | } |
|---|
| 1420 | 1482 | |
|---|
| 1421 | | -static const struct file_operations use_gss_proxy_ops = { |
|---|
| 1422 | | - .open = nonseekable_open, |
|---|
| 1423 | | - .write = write_gssp, |
|---|
| 1424 | | - .read = read_gssp, |
|---|
| 1483 | +static const struct proc_ops use_gss_proxy_proc_ops = { |
|---|
| 1484 | + .proc_open = nonseekable_open, |
|---|
| 1485 | + .proc_write = write_gssp, |
|---|
| 1486 | + .proc_read = read_gssp, |
|---|
| 1425 | 1487 | }; |
|---|
| 1426 | 1488 | |
|---|
| 1427 | 1489 | static int create_use_gss_proxy_proc_entry(struct net *net) |
|---|
| .. | .. |
|---|
| 1432 | 1494 | sn->use_gss_proxy = -1; |
|---|
| 1433 | 1495 | *p = proc_create_data("use-gss-proxy", S_IFREG | 0600, |
|---|
| 1434 | 1496 | sn->proc_net_rpc, |
|---|
| 1435 | | - &use_gss_proxy_ops, net); |
|---|
| 1497 | + &use_gss_proxy_proc_ops, net); |
|---|
| 1436 | 1498 | if (!*p) |
|---|
| 1437 | 1499 | return -ENOMEM; |
|---|
| 1438 | 1500 | init_gssp_clnt(sn); |
|---|
| .. | .. |
|---|
| 1480 | 1542 | __be32 *reject_stat = resv->iov_base + resv->iov_len; |
|---|
| 1481 | 1543 | int ret; |
|---|
| 1482 | 1544 | struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id); |
|---|
| 1483 | | - |
|---|
| 1484 | | - dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n", |
|---|
| 1485 | | - argv->iov_len); |
|---|
| 1486 | 1545 | |
|---|
| 1487 | 1546 | *authp = rpc_autherr_badcred; |
|---|
| 1488 | 1547 | if (!svcdata) |
|---|
| .. | .. |
|---|
| 1600 | 1659 | GSS_C_QOP_DEFAULT, |
|---|
| 1601 | 1660 | gc->gc_svc); |
|---|
| 1602 | 1661 | ret = SVC_OK; |
|---|
| 1662 | + trace_rpcgss_svc_authenticate(rqstp, gc); |
|---|
| 1603 | 1663 | goto out; |
|---|
| 1604 | 1664 | } |
|---|
| 1605 | 1665 | garbage_args: |
|---|
| .. | .. |
|---|
| 1666 | 1726 | goto out; |
|---|
| 1667 | 1727 | integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base; |
|---|
| 1668 | 1728 | integ_len = resbuf->len - integ_offset; |
|---|
| 1669 | | - BUG_ON(integ_len % 4); |
|---|
| 1729 | + if (integ_len & 3) |
|---|
| 1730 | + goto out; |
|---|
| 1670 | 1731 | *p++ = htonl(integ_len); |
|---|
| 1671 | 1732 | *p++ = htonl(gc->gc_seq); |
|---|
| 1672 | 1733 | if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, integ_len)) { |
|---|
| .. | .. |
|---|
| 1690 | 1751 | resv->iov_len += XDR_QUADLEN(mic.len) << 2; |
|---|
| 1691 | 1752 | /* not strictly required: */ |
|---|
| 1692 | 1753 | resbuf->len += XDR_QUADLEN(mic.len) << 2; |
|---|
| 1693 | | - BUG_ON(resv->iov_len > PAGE_SIZE); |
|---|
| 1754 | + if (resv->iov_len > PAGE_SIZE) |
|---|
| 1755 | + goto out_err; |
|---|
| 1694 | 1756 | out: |
|---|
| 1695 | 1757 | stat = 0; |
|---|
| 1696 | 1758 | out_err: |
|---|
| .. | .. |
|---|
| 1726 | 1788 | * both the head and tail. |
|---|
| 1727 | 1789 | */ |
|---|
| 1728 | 1790 | if (resbuf->tail[0].iov_base) { |
|---|
| 1729 | | - BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base |
|---|
| 1730 | | - + PAGE_SIZE); |
|---|
| 1731 | | - BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base); |
|---|
| 1791 | + if (resbuf->tail[0].iov_base >= |
|---|
| 1792 | + resbuf->head[0].iov_base + PAGE_SIZE) |
|---|
| 1793 | + return -EINVAL; |
|---|
| 1794 | + if (resbuf->tail[0].iov_base < resbuf->head[0].iov_base) |
|---|
| 1795 | + return -EINVAL; |
|---|
| 1732 | 1796 | if (resbuf->tail[0].iov_len + resbuf->head[0].iov_len |
|---|
| 1733 | 1797 | + 2 * RPC_MAX_AUTH_SIZE > PAGE_SIZE) |
|---|
| 1734 | 1798 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 1822 | 1886 | } |
|---|
| 1823 | 1887 | |
|---|
| 1824 | 1888 | static void |
|---|
| 1825 | | -svcauth_gss_domain_release(struct auth_domain *dom) |
|---|
| 1889 | +svcauth_gss_domain_release_rcu(struct rcu_head *head) |
|---|
| 1826 | 1890 | { |
|---|
| 1891 | + struct auth_domain *dom = container_of(head, struct auth_domain, rcu_head); |
|---|
| 1827 | 1892 | struct gss_domain *gd = container_of(dom, struct gss_domain, h); |
|---|
| 1828 | 1893 | |
|---|
| 1829 | 1894 | kfree(dom->name); |
|---|
| 1830 | 1895 | kfree(gd); |
|---|
| 1831 | 1896 | } |
|---|
| 1832 | 1897 | |
|---|
| 1898 | +static void |
|---|
| 1899 | +svcauth_gss_domain_release(struct auth_domain *dom) |
|---|
| 1900 | +{ |
|---|
| 1901 | + call_rcu(&dom->rcu_head, svcauth_gss_domain_release_rcu); |
|---|
| 1902 | +} |
|---|
| 1903 | + |
|---|
| 1833 | 1904 | static struct auth_ops svcauthops_gss = { |
|---|
| 1834 | 1905 | .name = "rpcsec_gss", |
|---|
| 1835 | 1906 | .owner = THIS_MODULE, |
|---|