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), |