diff options
Diffstat (limited to 'net/compat.c')
| -rw-r--r-- | net/compat.c | 114 |
1 files changed, 96 insertions, 18 deletions
diff --git a/net/compat.c b/net/compat.c index e593dace2fdb..8fd37cd7b501 100644 --- a/net/compat.c +++ b/net/compat.c | |||
| @@ -416,7 +416,7 @@ struct compat_sock_fprog { | |||
| 416 | compat_uptr_t filter; /* struct sock_filter * */ | 416 | compat_uptr_t filter; /* struct sock_filter * */ |
| 417 | }; | 417 | }; |
| 418 | 418 | ||
| 419 | static int do_set_attach_filter(int fd, int level, int optname, | 419 | static int do_set_attach_filter(struct socket *sock, int level, int optname, |
| 420 | char __user *optval, int optlen) | 420 | char __user *optval, int optlen) |
| 421 | { | 421 | { |
| 422 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; | 422 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; |
| @@ -432,11 +432,12 @@ static int do_set_attach_filter(int fd, int level, int optname, | |||
| 432 | __put_user(compat_ptr(ptr), &kfprog->filter)) | 432 | __put_user(compat_ptr(ptr), &kfprog->filter)) |
| 433 | return -EFAULT; | 433 | return -EFAULT; |
| 434 | 434 | ||
| 435 | return sys_setsockopt(fd, level, optname, (char __user *)kfprog, | 435 | return sock_setsockopt(sock, level, optname, (char __user *)kfprog, |
| 436 | sizeof(struct sock_fprog)); | 436 | sizeof(struct sock_fprog)); |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | static int do_set_sock_timeout(int fd, int level, int optname, char __user *optval, int optlen) | 439 | static int do_set_sock_timeout(struct socket *sock, int level, |
| 440 | int optname, char __user *optval, int optlen) | ||
| 440 | { | 441 | { |
| 441 | struct compat_timeval __user *up = (struct compat_timeval __user *) optval; | 442 | struct compat_timeval __user *up = (struct compat_timeval __user *) optval; |
| 442 | struct timeval ktime; | 443 | struct timeval ktime; |
| @@ -451,30 +452,61 @@ static int do_set_sock_timeout(int fd, int level, int optname, char __user *optv | |||
| 451 | return -EFAULT; | 452 | return -EFAULT; |
| 452 | old_fs = get_fs(); | 453 | old_fs = get_fs(); |
| 453 | set_fs(KERNEL_DS); | 454 | set_fs(KERNEL_DS); |
| 454 | err = sys_setsockopt(fd, level, optname, (char *) &ktime, sizeof(ktime)); | 455 | err = sock_setsockopt(sock, level, optname, (char *) &ktime, sizeof(ktime)); |
| 455 | set_fs(old_fs); | 456 | set_fs(old_fs); |
| 456 | 457 | ||
| 457 | return err; | 458 | return err; |
| 458 | } | 459 | } |
| 459 | 460 | ||
| 461 | static int compat_sock_setsockopt(struct socket *sock, int level, int optname, | ||
| 462 | char __user *optval, int optlen) | ||
| 463 | { | ||
| 464 | if (optname == SO_ATTACH_FILTER) | ||
| 465 | return do_set_attach_filter(sock, level, optname, | ||
| 466 | optval, optlen); | ||
| 467 | if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) | ||
| 468 | return do_set_sock_timeout(sock, level, optname, optval, optlen); | ||
| 469 | |||
| 470 | return sock_setsockopt(sock, level, optname, optval, optlen); | ||
| 471 | } | ||
| 472 | |||
| 460 | asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, | 473 | asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, |
| 461 | char __user *optval, int optlen) | 474 | char __user *optval, int optlen) |
| 462 | { | 475 | { |
| 476 | int err; | ||
| 477 | struct socket *sock; | ||
| 478 | |||
| 463 | /* SO_SET_REPLACE seems to be the same in all levels */ | 479 | /* SO_SET_REPLACE seems to be the same in all levels */ |
| 464 | if (optname == IPT_SO_SET_REPLACE) | 480 | if (optname == IPT_SO_SET_REPLACE) |
| 465 | return do_netfilter_replace(fd, level, optname, | 481 | return do_netfilter_replace(fd, level, optname, |
| 466 | optval, optlen); | 482 | optval, optlen); |
| 467 | if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) | ||
| 468 | return do_set_attach_filter(fd, level, optname, | ||
| 469 | optval, optlen); | ||
| 470 | if (level == SOL_SOCKET && | ||
| 471 | (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | ||
| 472 | return do_set_sock_timeout(fd, level, optname, optval, optlen); | ||
| 473 | 483 | ||
| 474 | return sys_setsockopt(fd, level, optname, optval, optlen); | 484 | if (optlen < 0) |
| 485 | return -EINVAL; | ||
| 486 | |||
| 487 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | ||
| 488 | { | ||
| 489 | err = security_socket_setsockopt(sock,level,optname); | ||
| 490 | if (err) { | ||
| 491 | sockfd_put(sock); | ||
| 492 | return err; | ||
| 493 | } | ||
| 494 | |||
| 495 | if (level == SOL_SOCKET) | ||
| 496 | err = compat_sock_setsockopt(sock, level, | ||
| 497 | optname, optval, optlen); | ||
| 498 | else if (sock->ops->compat_setsockopt) | ||
| 499 | err = sock->ops->compat_setsockopt(sock, level, | ||
| 500 | optname, optval, optlen); | ||
| 501 | else | ||
| 502 | err = sock->ops->setsockopt(sock, level, | ||
| 503 | optname, optval, optlen); | ||
| 504 | sockfd_put(sock); | ||
| 505 | } | ||
| 506 | return err; | ||
| 475 | } | 507 | } |
| 476 | 508 | ||
| 477 | static int do_get_sock_timeout(int fd, int level, int optname, | 509 | static int do_get_sock_timeout(struct socket *sock, int level, int optname, |
| 478 | char __user *optval, int __user *optlen) | 510 | char __user *optval, int __user *optlen) |
| 479 | { | 511 | { |
| 480 | struct compat_timeval __user *up; | 512 | struct compat_timeval __user *up; |
| @@ -490,7 +522,7 @@ static int do_get_sock_timeout(int fd, int level, int optname, | |||
| 490 | len = sizeof(ktime); | 522 | len = sizeof(ktime); |
| 491 | old_fs = get_fs(); | 523 | old_fs = get_fs(); |
| 492 | set_fs(KERNEL_DS); | 524 | set_fs(KERNEL_DS); |
| 493 | err = sys_getsockopt(fd, level, optname, (char *) &ktime, &len); | 525 | err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len); |
| 494 | set_fs(old_fs); | 526 | set_fs(old_fs); |
| 495 | 527 | ||
| 496 | if (!err) { | 528 | if (!err) { |
| @@ -503,15 +535,61 @@ static int do_get_sock_timeout(int fd, int level, int optname, | |||
| 503 | return err; | 535 | return err; |
| 504 | } | 536 | } |
| 505 | 537 | ||
| 506 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | 538 | static int compat_sock_getsockopt(struct socket *sock, int level, int optname, |
| 507 | char __user *optval, int __user *optlen) | 539 | char __user *optval, int __user *optlen) |
| 508 | { | 540 | { |
| 509 | if (level == SOL_SOCKET && | 541 | if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) |
| 510 | (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | 542 | return do_get_sock_timeout(sock, level, optname, optval, optlen); |
| 511 | return do_get_sock_timeout(fd, level, optname, optval, optlen); | 543 | return sock_getsockopt(sock, level, optname, optval, optlen); |
| 512 | return sys_getsockopt(fd, level, optname, optval, optlen); | 544 | } |
| 545 | |||
| 546 | int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) | ||
| 547 | { | ||
| 548 | struct compat_timeval __user *ctv = | ||
| 549 | (struct compat_timeval __user*) userstamp; | ||
| 550 | int err = -ENOENT; | ||
| 551 | |||
| 552 | if (!sock_flag(sk, SOCK_TIMESTAMP)) | ||
| 553 | sock_enable_timestamp(sk); | ||
| 554 | if (sk->sk_stamp.tv_sec == -1) | ||
| 555 | return err; | ||
| 556 | if (sk->sk_stamp.tv_sec == 0) | ||
| 557 | do_gettimeofday(&sk->sk_stamp); | ||
| 558 | if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) || | ||
| 559 | put_user(sk->sk_stamp.tv_usec, &ctv->tv_usec)) | ||
| 560 | err = -EFAULT; | ||
| 561 | return err; | ||
| 513 | } | 562 | } |
| 563 | EXPORT_SYMBOL(compat_sock_get_timestamp); | ||
| 564 | |||
| 565 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | ||
| 566 | char __user *optval, int __user *optlen) | ||
| 567 | { | ||
| 568 | int err; | ||
| 569 | struct socket *sock; | ||
| 570 | |||
| 571 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | ||
| 572 | { | ||
| 573 | err = security_socket_getsockopt(sock, level, | ||
| 574 | optname); | ||
| 575 | if (err) { | ||
| 576 | sockfd_put(sock); | ||
| 577 | return err; | ||
| 578 | } | ||
| 514 | 579 | ||
| 580 | if (level == SOL_SOCKET) | ||
| 581 | err = compat_sock_getsockopt(sock, level, | ||
| 582 | optname, optval, optlen); | ||
| 583 | else if (sock->ops->compat_getsockopt) | ||
| 584 | err = sock->ops->compat_getsockopt(sock, level, | ||
| 585 | optname, optval, optlen); | ||
| 586 | else | ||
| 587 | err = sock->ops->getsockopt(sock, level, | ||
| 588 | optname, optval, optlen); | ||
| 589 | sockfd_put(sock); | ||
| 590 | } | ||
| 591 | return err; | ||
| 592 | } | ||
| 515 | /* Argument list sizes for compat_sys_socketcall */ | 593 | /* Argument list sizes for compat_sys_socketcall */ |
| 516 | #define AL(x) ((x) * sizeof(u32)) | 594 | #define AL(x) ((x) * sizeof(u32)) |
| 517 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 595 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
