Skip to content

Commit 3e859ad

Browse files
Al Viroarndb
authored andcommitted
compat_ioctl: unify copy-in of ppp filters
Now that isdn4linux is gone, the is only one implementation of PPPIOCSPASS and PPPIOCSACTIVE in ppp_generic.c, so this is where the compat_ioctl support should be implemented. The two commands are implemented in very similar ways, so introduce new helpers to allow sharing between the two and between native and compat mode. Signed-off-by: Al Viro <[email protected]> [arnd: rebased, and added changelog text] Cc: [email protected] Cc: [email protected] Cc: Paul Mackerras <[email protected]> Cc: "David S. Miller" <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]>
1 parent b7aff09 commit 3e859ad

File tree

2 files changed

+108
-98
lines changed

2 files changed

+108
-98
lines changed

drivers/net/ppp/ppp_generic.c

Lines changed: 108 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -554,29 +554,58 @@ static __poll_t ppp_poll(struct file *file, poll_table *wait)
554554
}
555555

556556
#ifdef CONFIG_PPP_FILTER
557-
static int get_filter(void __user *arg, struct sock_filter **p)
557+
static struct bpf_prog *get_filter(struct sock_fprog *uprog)
558+
{
559+
struct sock_fprog_kern fprog;
560+
struct bpf_prog *res = NULL;
561+
int err;
562+
563+
if (!uprog->len)
564+
return NULL;
565+
566+
/* uprog->len is unsigned short, so no overflow here */
567+
fprog.len = uprog->len * sizeof(struct sock_filter);
568+
fprog.filter = memdup_user(uprog->filter, fprog.len);
569+
if (IS_ERR(fprog.filter))
570+
return ERR_CAST(fprog.filter);
571+
572+
err = bpf_prog_create(&res, &fprog);
573+
kfree(fprog.filter);
574+
575+
return err ? ERR_PTR(err) : res;
576+
}
577+
578+
static struct bpf_prog *ppp_get_filter(struct sock_fprog __user *p)
558579
{
559580
struct sock_fprog uprog;
560-
struct sock_filter *code = NULL;
561-
int len;
562581

563-
if (copy_from_user(&uprog, arg, sizeof(uprog)))
564-
return -EFAULT;
582+
if (copy_from_user(&uprog, p, sizeof(struct sock_fprog)))
583+
return ERR_PTR(-EFAULT);
584+
return get_filter(&uprog);
585+
}
565586

566-
if (!uprog.len) {
567-
*p = NULL;
568-
return 0;
569-
}
587+
#ifdef CONFIG_COMPAT
588+
struct sock_fprog32 {
589+
unsigned short len;
590+
compat_caddr_t filter;
591+
};
570592

571-
len = uprog.len * sizeof(struct sock_filter);
572-
code = memdup_user(uprog.filter, len);
573-
if (IS_ERR(code))
574-
return PTR_ERR(code);
593+
#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
594+
#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
575595

576-
*p = code;
577-
return uprog.len;
596+
static struct bpf_prog *compat_ppp_get_filter(struct sock_fprog32 __user *p)
597+
{
598+
struct sock_fprog32 uprog32;
599+
struct sock_fprog uprog;
600+
601+
if (copy_from_user(&uprog32, p, sizeof(struct sock_fprog32)))
602+
return ERR_PTR(-EFAULT);
603+
uprog.len = uprog32.len;
604+
uprog.filter = compat_ptr(uprog32.filter);
605+
return get_filter(&uprog);
578606
}
579-
#endif /* CONFIG_PPP_FILTER */
607+
#endif
608+
#endif
580609

581610
static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
582611
{
@@ -753,55 +782,25 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
753782

754783
#ifdef CONFIG_PPP_FILTER
755784
case PPPIOCSPASS:
756-
{
757-
struct sock_filter *code;
758-
759-
err = get_filter(argp, &code);
760-
if (err >= 0) {
761-
struct bpf_prog *pass_filter = NULL;
762-
struct sock_fprog_kern fprog = {
763-
.len = err,
764-
.filter = code,
765-
};
766-
767-
err = 0;
768-
if (fprog.filter)
769-
err = bpf_prog_create(&pass_filter, &fprog);
770-
if (!err) {
771-
ppp_lock(ppp);
772-
if (ppp->pass_filter)
773-
bpf_prog_destroy(ppp->pass_filter);
774-
ppp->pass_filter = pass_filter;
775-
ppp_unlock(ppp);
776-
}
777-
kfree(code);
778-
}
779-
break;
780-
}
781785
case PPPIOCSACTIVE:
782786
{
783-
struct sock_filter *code;
787+
struct bpf_prog *filter = ppp_get_filter(argp);
788+
struct bpf_prog **which;
784789

785-
err = get_filter(argp, &code);
786-
if (err >= 0) {
787-
struct bpf_prog *active_filter = NULL;
788-
struct sock_fprog_kern fprog = {
789-
.len = err,
790-
.filter = code,
791-
};
792-
793-
err = 0;
794-
if (fprog.filter)
795-
err = bpf_prog_create(&active_filter, &fprog);
796-
if (!err) {
797-
ppp_lock(ppp);
798-
if (ppp->active_filter)
799-
bpf_prog_destroy(ppp->active_filter);
800-
ppp->active_filter = active_filter;
801-
ppp_unlock(ppp);
802-
}
803-
kfree(code);
790+
if (IS_ERR(filter)) {
791+
err = PTR_ERR(filter);
792+
break;
804793
}
794+
if (cmd == PPPIOCSPASS)
795+
which = &ppp->pass_filter;
796+
else
797+
which = &ppp->active_filter;
798+
ppp_lock(ppp);
799+
if (*which)
800+
bpf_prog_destroy(*which);
801+
*which = filter;
802+
ppp_unlock(ppp);
803+
err = 0;
805804
break;
806805
}
807806
#endif /* CONFIG_PPP_FILTER */
@@ -827,6 +826,51 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
827826
return err;
828827
}
829828

829+
#ifdef CONFIG_COMPAT
830+
static long ppp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
831+
{
832+
struct ppp_file *pf;
833+
int err = -ENOIOCTLCMD;
834+
void __user *argp = (void __user *)arg;
835+
836+
mutex_lock(&ppp_mutex);
837+
838+
pf = file->private_data;
839+
if (pf && pf->kind == INTERFACE) {
840+
struct ppp *ppp = PF_TO_PPP(pf);
841+
switch (cmd) {
842+
#ifdef CONFIG_PPP_FILTER
843+
case PPPIOCSPASS32:
844+
case PPPIOCSACTIVE32:
845+
{
846+
struct bpf_prog *filter = compat_ppp_get_filter(argp);
847+
struct bpf_prog **which;
848+
849+
if (IS_ERR(filter)) {
850+
err = PTR_ERR(filter);
851+
break;
852+
}
853+
if (cmd == PPPIOCSPASS32)
854+
which = &ppp->pass_filter;
855+
else
856+
which = &ppp->active_filter;
857+
ppp_lock(ppp);
858+
if (*which)
859+
bpf_prog_destroy(*which);
860+
*which = filter;
861+
ppp_unlock(ppp);
862+
err = 0;
863+
break;
864+
}
865+
#endif /* CONFIG_PPP_FILTER */
866+
}
867+
}
868+
mutex_unlock(&ppp_mutex);
869+
870+
return err;
871+
}
872+
#endif
873+
830874
static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
831875
struct file *file, unsigned int cmd, unsigned long arg)
832876
{
@@ -895,6 +939,9 @@ static const struct file_operations ppp_device_fops = {
895939
.write = ppp_write,
896940
.poll = ppp_poll,
897941
.unlocked_ioctl = ppp_ioctl,
942+
#ifdef CONFIG_COMPAT
943+
.compat_ioctl = ppp_compat_ioctl,
944+
#endif
898945
.open = ppp_open,
899946
.release = ppp_release,
900947
.llseek = noop_llseek,

fs/compat_ioctl.c

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -99,40 +99,6 @@ static int sg_grt_trans(struct file *file,
9999
}
100100
#endif /* CONFIG_BLOCK */
101101

102-
struct sock_fprog32 {
103-
unsigned short len;
104-
compat_caddr_t filter;
105-
};
106-
107-
#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
108-
#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
109-
110-
static int ppp_sock_fprog_ioctl_trans(struct file *file,
111-
unsigned int cmd, struct sock_fprog32 __user *u_fprog32)
112-
{
113-
struct sock_fprog __user *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
114-
void __user *fptr64;
115-
u32 fptr32;
116-
u16 flen;
117-
118-
if (get_user(flen, &u_fprog32->len) ||
119-
get_user(fptr32, &u_fprog32->filter))
120-
return -EFAULT;
121-
122-
fptr64 = compat_ptr(fptr32);
123-
124-
if (put_user(flen, &u_fprog64->len) ||
125-
put_user(fptr64, &u_fprog64->filter))
126-
return -EFAULT;
127-
128-
if (cmd == PPPIOCSPASS32)
129-
cmd = PPPIOCSPASS;
130-
else
131-
cmd = PPPIOCSACTIVE;
132-
133-
return do_ioctl(file, cmd, (unsigned long) u_fprog64);
134-
}
135-
136102
struct ppp_option_data32 {
137103
compat_caddr_t ptr;
138104
u32 length;
@@ -285,9 +251,6 @@ static long do_ioctl_trans(unsigned int cmd,
285251
return ppp_gidle(file, cmd, argp);
286252
case PPPIOCSCOMPRESS32:
287253
return ppp_scompress(file, cmd, argp);
288-
case PPPIOCSPASS32:
289-
case PPPIOCSACTIVE32:
290-
return ppp_sock_fprog_ioctl_trans(file, cmd, argp);
291254
#ifdef CONFIG_BLOCK
292255
case SG_GET_REQUEST_TABLE:
293256
return sg_grt_trans(file, cmd, argp);

0 commit comments

Comments
 (0)