setsockopt SO_BINDTODEVICE nie działa jako user

Bash, C, C++, Java, PHP, Ruby, GTK, Qt i wiele innych - wszystko tutaj.
Awatar użytkownika
desowin
Piegowaty Guziec
Piegowaty Guziec
Posty: 14
Rejestracja: 15 lut 2008, 22:12
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: Xfce
Kontakt:

setsockopt SO_BINDTODEVICE nie działa jako user

Post autor: desowin »

Mam socket, który odbiera pakiety wysyłane na broadcast.
chcę ogranicznyć odbierane pakiety do danego urządzenia, np. 'eth0'
znalazłem informacje na temat SO_BINDTODEVICE, jednakże to działa pięknie gdy jest uruchomione jako root..
natomiast przy próbie uruchomienia tego jako user dostaję operation not permitted.

(Kod - tylko dla "zobrazowania" - jako root setsockopt wykona się poprawnie, jako user zwróci błąd)

Kod: Zaznacz cały

#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>

int
main()
{
    int rsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if (setsockopt(rsock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&"eth0\0", 5) < 0) {
        printf("SO_BINDTODEVICE failed %d\n", errno);
        return 1;
    }

    return 0;
}
Awatar użytkownika
doles2
Sędziwy Jeż
Sędziwy Jeż
Posty: 46
Rejestracja: 24 lip 2006, 19:58
Płeć: Mężczyzna
Wersja Ubuntu: 11.10
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: setsockopt SO_BINDTODEVICE nie działa jako user

Post autor: doles2 »

Wygląda na to, że nie tylko Ty masz taki problem. Co prawda to odnosi się do jądra 2.4, ale zawsze coś:
http://oss.sgi.com/archives/netdev/2001 ... 00104.html
Nie jestem dobrze obeznany w kodzie jądra Linuksa odpowiedzialnym za sieć, ale jest taka opcja jak CAP_NET_ADMIN:

Kod: Zaznacz cały

CAP_NET_ADMIN
      Pozwala na konfigurację interfejsu;
      Pozwala na zarządzanie kontami, maskaradą i firewallem;
      Pozwala na ustawianie opcji debug dla gniazd;
      Pozwala na modyfikacje tabeli routingu;
      Pozwala na przypisanie procesowi/grupie procesów prawa własności do gniazd;
      Pozwala na przywiązanie do dowolnego adresu dla przezroczystego proxy;
      Pozwala na ustawianie TOS ([ang.] type of service);
      Pozwala na ustawianie trybu promiscuous;
      Pozwala na czyszczenie statystyk sterownika;
      Pozwala na multicasting;
      Pozwala na odczyt/zapis, specyficznych dla urządzenia, rejestrów;
      Pozwala na aktywację gniazd kontrolnych ATM control.
Zaimplementowali ją bo bodajże w POSIX takie coś istnieje. Nie wiem dokładnie co to jest, w każdym bądź razie w kodzie jądra jest to zwykła dyrektywa preprocesora, sprawdzana np tak:

Kod: Zaznacz cały

 if (!capable(CAP_NET_ADMIN))
 74                 return -EPERM;
To pewnie jakaś grupa czy coś w ten deseń i na ogół (albo właściwie zawsze) należy do niej root. Taka polityka bezpieczeństwa, która dotyczy się w ogóle wywołania setsockopt(), nie tylko dla SO_BINDTODEVICE.

PS: A udało Ci się może wywołać te funkcje z innymi parametrami niż SO_BINDTODEVICE jako zwykły user ?
Awatar użytkownika
desowin
Piegowaty Guziec
Piegowaty Guziec
Posty: 14
Rejestracja: 15 lut 2008, 22:12
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: Xfce
Kontakt:

Odp: setsockopt SO_BINDTODEVICE nie działa jako user

Post autor: desowin »

doles2 pisze:Taka polityka bezpieczeństwa, która dotyczy się w ogóle wywołania setsockopt(), nie tylko dla SO_BINDTODEVICE.

PS: A udało Ci się może wywołać te funkcje z innymi parametrami niż SO_BINDTODEVICE jako zwykły user ?
nie dla każdego wywołania, z tego co w net/core/sock.c znalazłem to dla SO_BINDTODEVICE oraz SO_DEBUG

natomiast reszta powinna działać ok jako user,
a jako zwykły user na 100% działa SO_BROADCAST, SO_REUSEADDR, SO_RCVBUF.
Awatar użytkownika
doles2
Sędziwy Jeż
Sędziwy Jeż
Posty: 46
Rejestracja: 24 lip 2006, 19:58
Płeć: Mężczyzna
Wersja Ubuntu: 11.10
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: setsockopt SO_BINDTODEVICE nie działa jako user

Post autor: doles2 »

Kopałem teraz nieco i mam takie oto dziwne rzeczy. Z net/core/sock.c:

Kod: Zaznacz cały

int sock_setsockopt(struct socket *sock, int level, int optname,
442                     char __user *optval, int optlen)
443 {
444         struct sock *sk=sock->sk;
445         int val;
446         int valbool;
447         struct linger ling;
448         int ret = 0;
449 
450         /*
451          *      Options without arguments
452          */
453 
454         if (optname == SO_BINDTODEVICE)
455                 return sock_bindtodevice(sk, optval, optlen);
456         */dziwne, że w ogóle tego nie ma w switch tylko tak sobie luzem sprawdza*/
457         if (optlen < sizeof(int))
458                 return -EINVAL;
459 
460         if (get_user(val, (int __user *)optval))
461                 return -EFAULT;
462 
463         valbool = val?1:0;
464 
465         lock_sock(sk);
466 
467         switch(optname) {
468         case SO_DEBUG:
469                 if (val && !capable(CAP_NET_ADMIN)) {
470                         ret = -EACCES;
471                 } else
472                         sock_valbool_flag(sk, SOCK_DBG, valbool);
473                 break;
474         case SO_REUSEADDR:
475                 sk->sk_reuse = valbool;
476                 break;
477         case SO_TYPE:
478         case SO_ERROR:
479                 ret = -ENOPROTOOPT;
480                 break;
481         case SO_DONTROUTE:
482                 sock_valbool_flag(sk, SOCK_LOCALROUTE, valbool);
483                 break;
484         case SO_BROADCAST:
485                 sock_valbool_flag(sk, SOCK_BROADCAST, valbool);
486                 break;
487         case SO_SNDBUF:
488                 /* Don't error on this BSD doesn't and if you think
489                    about it this is right. Otherwise apps have to
490                    play 'guess the biggest size' games. RCVBUF/SNDBUF
491                    are treated in BSD as hints */
492 
493                 if (val > sysctl_wmem_max)
494                         val = sysctl_wmem_max;
495 set_sndbuf:
496                 sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
497                 if ((val * 2) < SOCK_MIN_SNDBUF)
498                         sk->sk_sndbuf = SOCK_MIN_SNDBUF;
499                 else
500                         sk->sk_sndbuf = val * 2;
501 
502                 /*
503                  *      Wake up sending tasks if we
504                  *      upped the value.
505                  */
506                 sk->sk_write_space(sk);
507                 break;
508 
509         case SO_SNDBUFFORCE:
510                 if (!capable(CAP_NET_ADMIN)) {
511                         ret = -EPERM;
512                         break;
513                 }
514                 goto set_sndbuf;
515 
516         case SO_RCVBUF:
517                 /* Don't error on this BSD doesn't and if you think
518                    about it this is right. Otherwise apps have to
519                    play 'guess the biggest size' games. RCVBUF/SNDBUF
520                    are treated in BSD as hints */
521 
522                 if (val > sysctl_rmem_max)
523                         val = sysctl_rmem_max;
524 set_rcvbuf:
525                 sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
526                 /*
527                  * We double it on the way in to account for
528                  * "struct sk_buff" etc. overhead.   Applications
529                  * assume that the SO_RCVBUF setting they make will
530                  * allow that much actual data to be received on that
531                  * socket.
532                  *
533                  * Applications are unaware that "struct sk_buff" and
534                  * other overheads allocate from the receive buffer
535                  * during socket buffer allocation.
536                  *
537                  * And after considering the possible alternatives,
538                  * returning the value we actually used in getsockopt
539                  * is the most desirable behavior.
540                  */
541                 if ((val * 2) < SOCK_MIN_RCVBUF)
542                         sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
543                 else
544                         sk->sk_rcvbuf = val * 2;
545                 break;
546 
547         case SO_RCVBUFFORCE:
548                 if (!capable(CAP_NET_ADMIN)) {
549                         ret = -EPERM;
550                         break;
551                 }
552                 goto set_rcvbuf;
553 
554         case SO_KEEPALIVE:
555 #ifdef CONFIG_INET
556                 if (sk->sk_protocol == IPPROTO_TCP)
557                         tcp_set_keepalive(sk, valbool);
558 #endif
559                 sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
560                 break;
561 
562         case SO_OOBINLINE:
563                 sock_valbool_flag(sk, SOCK_URGINLINE, valbool);
564                 break;
565 
566         case SO_NO_CHECK:
567                 sk->sk_no_check = valbool;
568                 break;
569 
570         case SO_PRIORITY:
571                 if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN))
572                         sk->sk_priority = val;
573                 else
574                         ret = -EPERM;
575                 break;
576 
577         case SO_LINGER:
578                 if (optlen < sizeof(ling)) {
579                         ret = -EINVAL;  /* 1003.1g */
580                         break;
581                 }
582                 if (copy_from_user(&ling,optval,sizeof(ling))) {
583                         ret = -EFAULT;
584                         break;
585                 }
586                 if (!ling.l_onoff)
587                         sock_reset_flag(sk, SOCK_LINGER);
588                 else {
589 #if (BITS_PER_LONG == 32)
590                         if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
591                                 sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT;
592                         else
593 #endif
594                                 sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;
595                         sock_set_flag(sk, SOCK_LINGER);
596                 }
597                 break;
598 
599         case SO_BSDCOMPAT:
600                 sock_warn_obsolete_bsdism("setsockopt");
601                 break;
602 
603         case SO_PASSCRED:
604                 if (valbool)
605                         set_bit(SOCK_PASSCRED, &sock->flags);
606                 else
607                         clear_bit(SOCK_PASSCRED, &sock->flags);
608                 break;
609 
610         case SO_TIMESTAMP:
611         case SO_TIMESTAMPNS:
612                 if (valbool)  {
613                         if (optname == SO_TIMESTAMP)
614                                 sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
615                         else
616                                 sock_set_flag(sk, SOCK_RCVTSTAMPNS);
617                         sock_set_flag(sk, SOCK_RCVTSTAMP);
618                         sock_enable_timestamp(sk);
619                 } else {
620                         sock_reset_flag(sk, SOCK_RCVTSTAMP);
621                         sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
622                 }
623                 break;
624 
625         case SO_RCVLOWAT:
626                 if (val < 0)
627                         val = INT_MAX;
628                 sk->sk_rcvlowat = val ? : 1;
629                 break;
630 
631         case SO_RCVTIMEO:
632                 ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen);
633                 break;
634 
635         case SO_SNDTIMEO:
636                 ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen);
637                 break;
638 
639         case SO_ATTACH_FILTER:
640                 ret = -EINVAL;
641                 if (optlen == sizeof(struct sock_fprog)) {
642                         struct sock_fprog fprog;
643 
644                         ret = -EFAULT;
645                         if (copy_from_user(&fprog, optval, sizeof(fprog)))
646                                 break;
647 
648                         ret = sk_attach_filter(&fprog, sk);
649                 }
650                 break;
651 
652         case SO_DETACH_FILTER:
653                 ret = sk_detach_filter(sk);
654                 break;
655 
656         case SO_PASSSEC:
657                 if (valbool)
658                         set_bit(SOCK_PASSSEC, &sock->flags);
659                 else
660                         clear_bit(SOCK_PASSSEC, &sock->flags);
661                 break;
662         case SO_MARK:
663                 if (!capable(CAP_NET_ADMIN))
664                         ret = -EPERM;
665                 else {
666                         sk->sk_mark = val;
667                 }
668                 break;
669 
670                 /* We implement the SO_SNDLOWAT etc to
671                    not be settable (1003.1g 5.3) */
672         default:
673                 ret = -ENOPROTOOPT;
674                 break;
675         }
676         release_sock(sk);
677         return ret;
678 }
Jak widać w instrukcji:

Kod: Zaznacz cały

if (optname == SO_BINDTODEVICE)
nie sprawdza zupełnie nic co może mieć coś wspólnego z prawami czy bezpieczeństem, od razu wywołuje sock_bindtodevice() z pliku "net/core/sock.c" . A tutaj zaś jest sprawdzenie:

Kod: Zaznacz cały

 ret = -EPERM;
       if (!capable(CAP_NET_RAW))
              goto out;
Czyli jeśli CAP_NET_RAW jest niespełniony, a nie CAP_NET_ADMIN (jak było napisane tamtej grupie dyskusyjnej) to funkcja kończy swoje działanie z kodem błędu -EPERM, czyli właśnie Twoje:

Kod: Zaznacz cały

#define EPERM            1      /* Operation not permitted */
No to mamy źródło sprawcy. Wiesz zawsze możesz usunąć ten warunek sprawdzania z kodu jądra i przekompilować jajko na nowo :P
Mam nadzieję, że w jakikolwiek sposób pomogłem.
Awatar użytkownika
desowin
Piegowaty Guziec
Piegowaty Guziec
Posty: 14
Rejestracja: 15 lut 2008, 22:12
Płeć: Mężczyzna
Wersja Ubuntu: inny OS
Środowisko graficzne: Xfce
Kontakt:

Odp: setsockopt SO_BINDTODEVICE nie działa jako user

Post autor: desowin »

doles2 pisze:No to mamy źródło sprawcy. Wiesz zawsze możesz usunąć ten warunek sprawdzania z kodu jądra i przekompilować jajko na nowo :P
tyle to też wiem... tylko to jest niezbyt ok

abrdziej mi chodzi czy nie da się tego jakoś zrobić, ale nie używając SO_BINDTODEVICE
Awatar użytkownika
doles2
Sędziwy Jeż
Sędziwy Jeż
Posty: 46
Rejestracja: 24 lip 2006, 19:58
Płeć: Mężczyzna
Wersja Ubuntu: 11.10
Środowisko graficzne: KDE Plasma
Architektura: x86_64

Odp: setsockopt SO_BINDTODEVICE nie działa jako user

Post autor: doles2 »

desowin pisze: abrdziej mi chodzi czy nie da się tego jakoś zrobić, ale nie używając SO_BINDTODEVICE
No nie bardzo. Chcesz dokonać sciśle "wysumblimowanego" działania a takie oferuje wyłącznie SO_BINDTODEVICE. Zawsze można do socket.c dopisać drugą wersję funkcji sock_setsockopt() i ustawić drugie wywołanie systemowe (choć powiem szczerze nie dobrnąłem w mojej edukacji tak daleko jak pisanie własnych wywołań). W ten sposób nie naruszyłbyś zbyt wiele bezpieczeństwa systemu, bo tylko Twój program korzystałby z setsockopt2(), ewentualnie napisać dodatkowe "SO_BINDTODEVICE", które nie byłoby sprawdzane pod kątem uprawnień w sock_bindtodevice(). Niestety to i tak na nic się nie zda, bowiem gdziekolwiek byś nie uruchamiał swojego programu musiałbyś mieć jądro z swoim patchem :? Ale widzę, że jesteś fachowcem to sam dobie dasz radę z tym problemem ;-)
ODPOWIEDZ

Wróć do „Programowanie”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 3 gości