Bu glibc sorunu etrafında çalışmanın en iyi yolu nedir?


26

Setuid root ikili dosyalarına duyulan ihtiyacın çoğunu ortadan kaldırmak için dosya özelliklerini kullanan bir Gentoo Sertleştirilmiş kutusunu /bin/pingyönetiyorum (örn . CAP_NET_RAW, vb. Var).

Infact, kalan tek ikili budur:

abraxas ~ # find / -xdev -type f -perm -u=s
/usr/lib64/misc/glibc/pt_chown
abraxas ~ # 

Setuid bitini kaldırırsam veya kök dosya sistemimi yeniden bağlarsam nosuid, sshd ve GNU Screen çalışmamaya başlar çünkü grantpt(3)ana pesudoterminallerini çağırırlar ve glibc görünüşte bu programı çalıştırır ve altında çalışan köle psödoterminalini chmod eder /dev/pts/ve GNU Screen bu fonksiyonun ne zaman umurunda olduğunu önemser. başarısız olur.

Sorun şu ki, manpage grantpt(3)açıkça Linux altında, devptsdosya sistemi monte edildiğinde böyle bir yardımcı ikili kodunun gerekli olmadığını belirtir ; çekirdek otomatik olarak kölenin UID'sini ve GID'sini otomatik olarak açılan sürecin gerçek UID'sini /dev/ptmx(arayarak getpt(3)) ayarlayacaktır .

Bunu göstermek için küçük bir örnek program yazdım:

#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
    int master;
    char slave[16];
    struct stat slavestat;
    if ((master = getpt()) < 0) {
        fprintf(stderr, "getpt: %m\n");
        return 1;
    }
    printf("Opened a UNIX98 master terminal, fd = %d\n", master);
    /* I am not going to call grantpt() because I am trying to
     * demonstrate that it is not necessary with devpts mounted,
     * the owners and mode will be set automatically by the kernel.
     */
    if (unlockpt(master) < 0) {
        fprintf(stderr, "unlockpt: %m\n");
        return 2;
    }
    memset(slave, 0, sizeof(slave));
    if (ptsname_r(master, slave, sizeof(slave)) < 0) {
        fprintf(stderr, "ptsname: %m\n");
        return 2;
    }
    printf("Device name of slave pseudoterminal: %s\n", slave);
    if (stat(slave, &slavestat) < 0) {
        fprintf(stderr, "stat: %m\n");
        return 3;
    }
    printf("Information for device %s:\n", slave);
    printf("    Owner UID:  %d\n", slavestat.st_uid);
    printf("    Owner GID:  %d\n", slavestat.st_gid);
    printf("    Octal mode: %04o\n", slavestat.st_mode & 00007777);
    return 0;
}

Yukarıda belirtilen programdaki setuid biti kaldırılarak çalışırken gözlemleyin:

aaron@abraxas ~ $ id
uid=1000(aaron) gid=100(users) groups=100(users)
aaron@abraxas ~ $ ./ptytest 
Opened a UNIX98 master terminal, fd = 3
Device name of slave pseudoterminal: /dev/pts/17
Information for device /dev/pts/17:
    Owner UID:  1000
    Owner GID:  100
    Octal mode: 0620

Bu soruna geçici bir çözüm bulmak için birkaç fikrim var:

1) Programı, 0 döndüren bir iskeletle değiştirin.

2) Hiçbir şey yapmamak için libc'mde grantpt () eklentisini kullanın.

Bunların her ikisini de otomatikleştirebilirim, ancak bir başkası için bir öneri ya da bunun nasıl çözüleceği konusunda tavsiyeler var mı?

Bu çözüldüğünde, sonunda yapabilirim mount -o remount,nosuid /.


Bir cevap beklerken, yaklaşım 1'e geçtim ve sshd ve GNU Screen hala çalışıyor.
Aaron Jones

Başarısız olan programlar tam olarak nedir? Belki onlar kırılır ve için yapılmadığını kontrol pty(gerektiği gibi), ancak program için?
von

CAP_CHOWN ve CAP_FOWNER içermeyen, grantpt () çağırır ve yardımcı ikili EUID == 0 ile başlatılmazsa, grantpt () için sıfır olmayan bir dönüş kodu olur ve bu olduğunda PTS oluşturulmasını iptal eden programlar SHOULD olur. ptmx'e (4) göre.
Aaron Jones

3
Bu "çözüm", beni en iyi durumda, en iyi durumda, bir hatanın üzerine yazıyor, muhtemelen yeni bir hata yaratıyor, en kötü durumda ciddi bir güvenlik açığı yaratıyor. Lütfen bunu glibc geliştiricileri ile birlikte alın.
von

3
Sonra bunu glibc insanlarına bildirin.
von

Yanıtlar:


2

Senin Eğer glibc makul akımdır ve devpts doğru kurulmuş olup, çağırmak gerek yoktur olmalı pt_chownhiç yardımcı.

Setuid-root kaynağını kaldırmak için bilinen / potansiyel bir sorunla karşılaşıyor olabilirsiniz pt_chown.

grantpt()desteklenen devfsgelen glibc'nin-2.7 , değişiklikler yapılmıştır glibc'nin-2.11 olsa böylece ziyade açıkça kontrol DEVFS_SUPER_MAGICo denemeden önce herhangi bir iş yapmak gerekip gerekmediğini görmek için yerine denetler chown()veya çağırmadan geri düşen pt_chown.

itibaren glibc-2.17/sysdeps/unix/grantpt.c

  ...
  uid_t uid = __getuid ();
  if (st.st_uid != uid)
    {
       if (__chown (buf, uid, st.st_gid) < 0)
       goto helper;
    }
  ...

Benzer bir stanza gid ve izinleri kontrol etmek için kullanılır. Yakala, kullanıcı adı, gid ve modun beklentileri karşılaması gerektiğidir (siz, tty ve tam olarak 620; onaylayın /usr/libexec/pt_chown --help). Aksi takdirde chown()(ki bunlar CAP_CHOWN yeteneklerini gerektirir, çağıran ikili kod / işlemin CAP_FOWNER'ı denenir ve başarısız olursa, pt_chownharici yardımcı (setuid-root olmalıdır) denenir. İçin için pt_chownonu (ve sonucunda glibc) ile derlenmiş olması gerekmektedir özelliklerini kullanmak mümkün HAVE_LIBCAP. Ancak , görünüşe göre pt_chown( glibc-2.17 ve sürümü belirtmemiş olsanız da belirttiğiniz gibi) , aşağıdakilerden geteuid()==0 bağımsız olarak HAVE_LIBCAPilgili koddan bağımsız olarak istemek için kodlanmış glibc-2.17/login/programs/pt_chown.c:

  ...
  if (argc == 1 && euid == 0)
    {
#ifdef HAVE_LIBCAP
  /* Drop privileges.  */
     if (uid != euid)
  ...
#endif
    /* Normal invocation of this program is with no arguments and
       with privileges.  */
    return do_pt_chown ();
  }
...
  /* Check if we are properly installed.  */
  if (euid != 0)
    error (FAIL_EXEC, 0, gettext ("needs to be installed setuid `root'"));

( geteuid()==0Yetenekleri kullanmaya çalışmadan önce beklentiler gerçekten yeteneklerin ruhunda gözükmüyor, bununla ilgili bir hata kaydı ile devam ediyorum.)

Potansiyel bir çözüm etkilenen programlara CAP_CHOWN, CAP_FOWNER vermek olabilir, ama ben gerçekten önermiyoruz elbette PTY'leri bu kısıtlamak olamaz çünkü.

Eğer bu sorunu çözmenize yardımcı olmazsa, yama sshdve screenglibc'i yamadan biraz daha az nahoşdur. Sorun glibc içinde olduğundan, daha temiz bir yaklaşım bir kukla uygulamak için DLL enjeksiyonunun seçici kullanımı olacaktır grantpt().


“Ancak sorun glibc içinde olduğundan, daha temiz bir yaklaşım, sahte bir hibe () uygulamak için DLL enjeksiyonunun seçici kullanımı olacaktır.” -- Parlak. Bunu neden düşünmedim? Teşekkürler. :)
Aaron Jones
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.