.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Generic PPP layer for Linux. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright 1999-2002 Paul Mackerras. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public License |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the License, or (at your option) any later version. |
---|
10 | 6 | * |
---|
11 | 7 | * The generic PPP layer handles the PPP network interfaces, the |
---|
12 | 8 | * /dev/ppp device, packet and VJ compression, and multilink. |
---|
.. | .. |
---|
276 | 272 | static struct sk_buff *ppp_mp_reconstruct(struct ppp *ppp); |
---|
277 | 273 | static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb); |
---|
278 | 274 | #endif /* CONFIG_PPP_MULTILINK */ |
---|
279 | | -static int ppp_set_compress(struct ppp *ppp, unsigned long arg); |
---|
| 275 | +static int ppp_set_compress(struct ppp *ppp, struct ppp_option_data *data); |
---|
280 | 276 | static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); |
---|
281 | 277 | static void ppp_ccp_closed(struct ppp *ppp); |
---|
282 | 278 | static struct compressor *find_compressor(int type); |
---|
.. | .. |
---|
302 | 298 | /* per net-namespace data */ |
---|
303 | 299 | static inline struct ppp_net *ppp_pernet(struct net *net) |
---|
304 | 300 | { |
---|
305 | | - BUG_ON(!net); |
---|
306 | | - |
---|
307 | 301 | return net_generic(net, ppp_net_id); |
---|
308 | 302 | } |
---|
309 | 303 | |
---|
.. | .. |
---|
563 | 557 | } |
---|
564 | 558 | |
---|
565 | 559 | #ifdef CONFIG_PPP_FILTER |
---|
566 | | -static int get_filter(void __user *arg, struct sock_filter **p) |
---|
| 560 | +static struct bpf_prog *get_filter(struct sock_fprog *uprog) |
---|
| 561 | +{ |
---|
| 562 | + struct sock_fprog_kern fprog; |
---|
| 563 | + struct bpf_prog *res = NULL; |
---|
| 564 | + int err; |
---|
| 565 | + |
---|
| 566 | + if (!uprog->len) |
---|
| 567 | + return NULL; |
---|
| 568 | + |
---|
| 569 | + /* uprog->len is unsigned short, so no overflow here */ |
---|
| 570 | + fprog.len = uprog->len; |
---|
| 571 | + fprog.filter = memdup_user(uprog->filter, |
---|
| 572 | + uprog->len * sizeof(struct sock_filter)); |
---|
| 573 | + if (IS_ERR(fprog.filter)) |
---|
| 574 | + return ERR_CAST(fprog.filter); |
---|
| 575 | + |
---|
| 576 | + err = bpf_prog_create(&res, &fprog); |
---|
| 577 | + kfree(fprog.filter); |
---|
| 578 | + |
---|
| 579 | + return err ? ERR_PTR(err) : res; |
---|
| 580 | +} |
---|
| 581 | + |
---|
| 582 | +static struct bpf_prog *ppp_get_filter(struct sock_fprog __user *p) |
---|
567 | 583 | { |
---|
568 | 584 | struct sock_fprog uprog; |
---|
569 | | - struct sock_filter *code = NULL; |
---|
570 | | - int len; |
---|
571 | 585 | |
---|
572 | | - if (copy_from_user(&uprog, arg, sizeof(uprog))) |
---|
573 | | - return -EFAULT; |
---|
574 | | - |
---|
575 | | - if (!uprog.len) { |
---|
576 | | - *p = NULL; |
---|
577 | | - return 0; |
---|
578 | | - } |
---|
579 | | - |
---|
580 | | - len = uprog.len * sizeof(struct sock_filter); |
---|
581 | | - code = memdup_user(uprog.filter, len); |
---|
582 | | - if (IS_ERR(code)) |
---|
583 | | - return PTR_ERR(code); |
---|
584 | | - |
---|
585 | | - *p = code; |
---|
586 | | - return uprog.len; |
---|
| 586 | + if (copy_from_user(&uprog, p, sizeof(struct sock_fprog))) |
---|
| 587 | + return ERR_PTR(-EFAULT); |
---|
| 588 | + return get_filter(&uprog); |
---|
587 | 589 | } |
---|
588 | | -#endif /* CONFIG_PPP_FILTER */ |
---|
| 590 | + |
---|
| 591 | +#ifdef CONFIG_COMPAT |
---|
| 592 | +struct sock_fprog32 { |
---|
| 593 | + unsigned short len; |
---|
| 594 | + compat_caddr_t filter; |
---|
| 595 | +}; |
---|
| 596 | + |
---|
| 597 | +#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32) |
---|
| 598 | +#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32) |
---|
| 599 | + |
---|
| 600 | +static struct bpf_prog *compat_ppp_get_filter(struct sock_fprog32 __user *p) |
---|
| 601 | +{ |
---|
| 602 | + struct sock_fprog32 uprog32; |
---|
| 603 | + struct sock_fprog uprog; |
---|
| 604 | + |
---|
| 605 | + if (copy_from_user(&uprog32, p, sizeof(struct sock_fprog32))) |
---|
| 606 | + return ERR_PTR(-EFAULT); |
---|
| 607 | + uprog.len = uprog32.len; |
---|
| 608 | + uprog.filter = compat_ptr(uprog32.filter); |
---|
| 609 | + return get_filter(&uprog); |
---|
| 610 | +} |
---|
| 611 | +#endif |
---|
| 612 | +#endif |
---|
589 | 613 | |
---|
590 | 614 | static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
---|
591 | 615 | { |
---|
592 | 616 | struct ppp_file *pf; |
---|
593 | 617 | struct ppp *ppp; |
---|
594 | 618 | int err = -EFAULT, val, val2, i; |
---|
595 | | - struct ppp_idle idle; |
---|
| 619 | + struct ppp_idle32 idle32; |
---|
| 620 | + struct ppp_idle64 idle64; |
---|
596 | 621 | struct npioctl npi; |
---|
597 | 622 | int unit, cflags; |
---|
598 | 623 | struct slcompress *vj; |
---|
.. | .. |
---|
688 | 713 | break; |
---|
689 | 714 | |
---|
690 | 715 | case PPPIOCSCOMPRESS: |
---|
691 | | - err = ppp_set_compress(ppp, arg); |
---|
| 716 | + { |
---|
| 717 | + struct ppp_option_data data; |
---|
| 718 | + if (copy_from_user(&data, argp, sizeof(data))) |
---|
| 719 | + err = -EFAULT; |
---|
| 720 | + else |
---|
| 721 | + err = ppp_set_compress(ppp, &data); |
---|
692 | 722 | break; |
---|
693 | | - |
---|
| 723 | + } |
---|
694 | 724 | case PPPIOCGUNIT: |
---|
695 | 725 | if (put_user(ppp->file.index, p)) |
---|
696 | 726 | break; |
---|
.. | .. |
---|
710 | 740 | err = 0; |
---|
711 | 741 | break; |
---|
712 | 742 | |
---|
713 | | - case PPPIOCGIDLE: |
---|
714 | | - idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ; |
---|
715 | | - idle.recv_idle = (jiffies - ppp->last_recv) / HZ; |
---|
716 | | - if (copy_to_user(argp, &idle, sizeof(idle))) |
---|
| 743 | + case PPPIOCGIDLE32: |
---|
| 744 | + idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ; |
---|
| 745 | + idle32.recv_idle = (jiffies - ppp->last_recv) / HZ; |
---|
| 746 | + if (copy_to_user(argp, &idle32, sizeof(idle32))) |
---|
| 747 | + break; |
---|
| 748 | + err = 0; |
---|
| 749 | + break; |
---|
| 750 | + |
---|
| 751 | + case PPPIOCGIDLE64: |
---|
| 752 | + idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ; |
---|
| 753 | + idle64.recv_idle = (jiffies - ppp->last_recv) / HZ; |
---|
| 754 | + if (copy_to_user(argp, &idle64, sizeof(idle64))) |
---|
717 | 755 | break; |
---|
718 | 756 | err = 0; |
---|
719 | 757 | break; |
---|
.. | .. |
---|
762 | 800 | |
---|
763 | 801 | #ifdef CONFIG_PPP_FILTER |
---|
764 | 802 | case PPPIOCSPASS: |
---|
765 | | - { |
---|
766 | | - struct sock_filter *code; |
---|
767 | | - |
---|
768 | | - err = get_filter(argp, &code); |
---|
769 | | - if (err >= 0) { |
---|
770 | | - struct bpf_prog *pass_filter = NULL; |
---|
771 | | - struct sock_fprog_kern fprog = { |
---|
772 | | - .len = err, |
---|
773 | | - .filter = code, |
---|
774 | | - }; |
---|
775 | | - |
---|
776 | | - err = 0; |
---|
777 | | - if (fprog.filter) |
---|
778 | | - err = bpf_prog_create(&pass_filter, &fprog); |
---|
779 | | - if (!err) { |
---|
780 | | - ppp_lock(ppp); |
---|
781 | | - if (ppp->pass_filter) |
---|
782 | | - bpf_prog_destroy(ppp->pass_filter); |
---|
783 | | - ppp->pass_filter = pass_filter; |
---|
784 | | - ppp_unlock(ppp); |
---|
785 | | - } |
---|
786 | | - kfree(code); |
---|
787 | | - } |
---|
788 | | - break; |
---|
789 | | - } |
---|
790 | 803 | case PPPIOCSACTIVE: |
---|
791 | 804 | { |
---|
792 | | - struct sock_filter *code; |
---|
| 805 | + struct bpf_prog *filter = ppp_get_filter(argp); |
---|
| 806 | + struct bpf_prog **which; |
---|
793 | 807 | |
---|
794 | | - err = get_filter(argp, &code); |
---|
795 | | - if (err >= 0) { |
---|
796 | | - struct bpf_prog *active_filter = NULL; |
---|
797 | | - struct sock_fprog_kern fprog = { |
---|
798 | | - .len = err, |
---|
799 | | - .filter = code, |
---|
800 | | - }; |
---|
801 | | - |
---|
802 | | - err = 0; |
---|
803 | | - if (fprog.filter) |
---|
804 | | - err = bpf_prog_create(&active_filter, &fprog); |
---|
805 | | - if (!err) { |
---|
806 | | - ppp_lock(ppp); |
---|
807 | | - if (ppp->active_filter) |
---|
808 | | - bpf_prog_destroy(ppp->active_filter); |
---|
809 | | - ppp->active_filter = active_filter; |
---|
810 | | - ppp_unlock(ppp); |
---|
811 | | - } |
---|
812 | | - kfree(code); |
---|
| 808 | + if (IS_ERR(filter)) { |
---|
| 809 | + err = PTR_ERR(filter); |
---|
| 810 | + break; |
---|
813 | 811 | } |
---|
| 812 | + if (cmd == PPPIOCSPASS) |
---|
| 813 | + which = &ppp->pass_filter; |
---|
| 814 | + else |
---|
| 815 | + which = &ppp->active_filter; |
---|
| 816 | + ppp_lock(ppp); |
---|
| 817 | + if (*which) |
---|
| 818 | + bpf_prog_destroy(*which); |
---|
| 819 | + *which = filter; |
---|
| 820 | + ppp_unlock(ppp); |
---|
| 821 | + err = 0; |
---|
814 | 822 | break; |
---|
815 | 823 | } |
---|
816 | 824 | #endif /* CONFIG_PPP_FILTER */ |
---|
.. | .. |
---|
835 | 843 | |
---|
836 | 844 | return err; |
---|
837 | 845 | } |
---|
| 846 | + |
---|
| 847 | +#ifdef CONFIG_COMPAT |
---|
| 848 | +struct ppp_option_data32 { |
---|
| 849 | + compat_uptr_t ptr; |
---|
| 850 | + u32 length; |
---|
| 851 | + compat_int_t transmit; |
---|
| 852 | +}; |
---|
| 853 | +#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) |
---|
| 854 | + |
---|
| 855 | +static long ppp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
---|
| 856 | +{ |
---|
| 857 | + struct ppp_file *pf; |
---|
| 858 | + int err = -ENOIOCTLCMD; |
---|
| 859 | + void __user *argp = (void __user *)arg; |
---|
| 860 | + |
---|
| 861 | + mutex_lock(&ppp_mutex); |
---|
| 862 | + |
---|
| 863 | + pf = file->private_data; |
---|
| 864 | + if (pf && pf->kind == INTERFACE) { |
---|
| 865 | + struct ppp *ppp = PF_TO_PPP(pf); |
---|
| 866 | + switch (cmd) { |
---|
| 867 | +#ifdef CONFIG_PPP_FILTER |
---|
| 868 | + case PPPIOCSPASS32: |
---|
| 869 | + case PPPIOCSACTIVE32: |
---|
| 870 | + { |
---|
| 871 | + struct bpf_prog *filter = compat_ppp_get_filter(argp); |
---|
| 872 | + struct bpf_prog **which; |
---|
| 873 | + |
---|
| 874 | + if (IS_ERR(filter)) { |
---|
| 875 | + err = PTR_ERR(filter); |
---|
| 876 | + break; |
---|
| 877 | + } |
---|
| 878 | + if (cmd == PPPIOCSPASS32) |
---|
| 879 | + which = &ppp->pass_filter; |
---|
| 880 | + else |
---|
| 881 | + which = &ppp->active_filter; |
---|
| 882 | + ppp_lock(ppp); |
---|
| 883 | + if (*which) |
---|
| 884 | + bpf_prog_destroy(*which); |
---|
| 885 | + *which = filter; |
---|
| 886 | + ppp_unlock(ppp); |
---|
| 887 | + err = 0; |
---|
| 888 | + break; |
---|
| 889 | + } |
---|
| 890 | +#endif /* CONFIG_PPP_FILTER */ |
---|
| 891 | + case PPPIOCSCOMPRESS32: |
---|
| 892 | + { |
---|
| 893 | + struct ppp_option_data32 data32; |
---|
| 894 | + if (copy_from_user(&data32, argp, sizeof(data32))) { |
---|
| 895 | + err = -EFAULT; |
---|
| 896 | + } else { |
---|
| 897 | + struct ppp_option_data data = { |
---|
| 898 | + .ptr = compat_ptr(data32.ptr), |
---|
| 899 | + .length = data32.length, |
---|
| 900 | + .transmit = data32.transmit |
---|
| 901 | + }; |
---|
| 902 | + err = ppp_set_compress(ppp, &data); |
---|
| 903 | + } |
---|
| 904 | + break; |
---|
| 905 | + } |
---|
| 906 | + } |
---|
| 907 | + } |
---|
| 908 | + mutex_unlock(&ppp_mutex); |
---|
| 909 | + |
---|
| 910 | + /* all other commands have compatible arguments */ |
---|
| 911 | + if (err == -ENOIOCTLCMD) |
---|
| 912 | + err = ppp_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); |
---|
| 913 | + |
---|
| 914 | + return err; |
---|
| 915 | +} |
---|
| 916 | +#endif |
---|
838 | 917 | |
---|
839 | 918 | static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, |
---|
840 | 919 | struct file *file, unsigned int cmd, unsigned long arg) |
---|
.. | .. |
---|
904 | 983 | .write = ppp_write, |
---|
905 | 984 | .poll = ppp_poll, |
---|
906 | 985 | .unlocked_ioctl = ppp_ioctl, |
---|
| 986 | +#ifdef CONFIG_COMPAT |
---|
| 987 | + .compat_ioctl = ppp_compat_ioctl, |
---|
| 988 | +#endif |
---|
907 | 989 | .open = ppp_open, |
---|
908 | 990 | .release = ppp_release, |
---|
909 | 991 | .llseek = noop_llseek, |
---|
.. | .. |
---|
1527 | 1609 | struct sk_buff *new_skb; |
---|
1528 | 1610 | int len; |
---|
1529 | 1611 | unsigned char *cp; |
---|
| 1612 | + |
---|
| 1613 | + skb->dev = ppp->dev; |
---|
1530 | 1614 | |
---|
1531 | 1615 | if (proto < 0x8000) { |
---|
1532 | 1616 | #ifdef CONFIG_PPP_FILTER |
---|
.. | .. |
---|
2466 | 2550 | |
---|
2467 | 2551 | if (ppp->mrru == 0) /* do nothing until mrru is set */ |
---|
2468 | 2552 | return NULL; |
---|
2469 | | - head = list->next; |
---|
| 2553 | + head = __skb_peek(list); |
---|
2470 | 2554 | tail = NULL; |
---|
2471 | 2555 | skb_queue_walk_safe(list, p, tmp) { |
---|
2472 | 2556 | again: |
---|
.. | .. |
---|
2756 | 2840 | |
---|
2757 | 2841 | /* Process the PPPIOCSCOMPRESS ioctl. */ |
---|
2758 | 2842 | static int |
---|
2759 | | -ppp_set_compress(struct ppp *ppp, unsigned long arg) |
---|
| 2843 | +ppp_set_compress(struct ppp *ppp, struct ppp_option_data *data) |
---|
2760 | 2844 | { |
---|
2761 | | - int err; |
---|
| 2845 | + int err = -EFAULT; |
---|
2762 | 2846 | struct compressor *cp, *ocomp; |
---|
2763 | | - struct ppp_option_data data; |
---|
2764 | 2847 | void *state, *ostate; |
---|
2765 | 2848 | unsigned char ccp_option[CCP_MAX_OPTION_LENGTH]; |
---|
2766 | 2849 | |
---|
2767 | | - err = -EFAULT; |
---|
2768 | | - if (copy_from_user(&data, (void __user *) arg, sizeof(data))) |
---|
| 2850 | + if (data->length > CCP_MAX_OPTION_LENGTH) |
---|
2769 | 2851 | goto out; |
---|
2770 | | - if (data.length > CCP_MAX_OPTION_LENGTH) |
---|
2771 | | - goto out; |
---|
2772 | | - if (copy_from_user(ccp_option, (void __user *) data.ptr, data.length)) |
---|
| 2852 | + if (copy_from_user(ccp_option, data->ptr, data->length)) |
---|
2773 | 2853 | goto out; |
---|
2774 | 2854 | |
---|
2775 | 2855 | err = -EINVAL; |
---|
2776 | | - if (data.length < 2 || ccp_option[1] < 2 || ccp_option[1] > data.length) |
---|
| 2856 | + if (data->length < 2 || ccp_option[1] < 2 || ccp_option[1] > data->length) |
---|
2777 | 2857 | goto out; |
---|
2778 | 2858 | |
---|
2779 | 2859 | cp = try_then_request_module( |
---|
.. | .. |
---|
2783 | 2863 | goto out; |
---|
2784 | 2864 | |
---|
2785 | 2865 | err = -ENOBUFS; |
---|
2786 | | - if (data.transmit) { |
---|
2787 | | - state = cp->comp_alloc(ccp_option, data.length); |
---|
| 2866 | + if (data->transmit) { |
---|
| 2867 | + state = cp->comp_alloc(ccp_option, data->length); |
---|
2788 | 2868 | if (state) { |
---|
2789 | 2869 | ppp_xmit_lock(ppp); |
---|
2790 | 2870 | ppp->xstate &= ~SC_COMP_RUN; |
---|
.. | .. |
---|
2802 | 2882 | module_put(cp->owner); |
---|
2803 | 2883 | |
---|
2804 | 2884 | } else { |
---|
2805 | | - state = cp->decomp_alloc(ccp_option, data.length); |
---|
| 2885 | + state = cp->decomp_alloc(ccp_option, data->length); |
---|
2806 | 2886 | if (state) { |
---|
2807 | 2887 | ppp_recv_lock(ppp); |
---|
2808 | 2888 | ppp->rstate &= ~SC_DECOMP_RUN; |
---|