Apa cara terbaik untuk mengatasi masalah glibc ini?

26

Saya mengelola kotak Gentoo Hardened yang menggunakan kemampuan file untuk menghilangkan sebagian besar kebutuhan untuk binari setuid-root (mis. /bin/pingMemiliki CAP_NET_RAW, dll.).

Infact, satu-satunya biner yang tersisa adalah ini:

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

Jika saya menghapus bit setuid, atau remount filesystem root saya nosuid, sshd dan GNU Screen berhenti bekerja, karena mereka memanggil grantpt(3)master pesudoterminals dan glibc rupanya mengeksekusi program ini untuk chown dan chmod slave pseudoterminal di bawah /dev/pts/, dan GNU Screen peduli ketika fungsi ini gagal

Masalahnya adalah, manual untuk grantpt(3)menyatakan secara eksplisit bahwa di Linux, dengan sistem devptsfile yang terpasang, tidak ada biner pembantu seperti itu diperlukan; kernel akan secara otomatis mengatur UID & GID dari slave ke UID & GID yang sebenarnya dari proses yang dibuka /dev/ptmx(dengan memanggil getpt(3)).

Saya telah menulis contoh program kecil untuk menunjukkan ini:

#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;
}

Amati dalam tindakan dengan bit setuid pada program yang disebutkan di atas dihapus:

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

Saya hanya punya beberapa ide tentang cara mengatasi masalah ini:

1) Ganti program dengan kerangka yang hanya mengembalikan 0.

2) Patch grantpt () di libc saya untuk tidak melakukan apa pun.

Saya dapat mengotomatiskan keduanya, tetapi apakah ada yang punya rekomendasi untuk yang satu di atas yang lain, atau rekomendasi untuk cara lain untuk menyelesaikan ini?

Setelah ini diselesaikan, saya akhirnya bisa mount -o remount,nosuid /.

Aaron Jones
sumber
Sementara saya menunggu jawaban, saya pergi dengan pendekatan 1, dan sshd dan Layar GNU masih berfungsi.
Aaron Jones
Apa sebenarnya program yang gagal? Mungkin mereka rusak dan memeriksa bukan untuk pty(sebagaimana mestinya) tetapi untuk program ini?
vonbrand
Program apa pun yang tidak memiliki CAP_CHOWN dan CAP_FOWNER, panggilan grantpt (), dan biner pembantu tidak dimulai dengan EUID == 0, akan memiliki kode pengembalian non-nol untuk grantpt (), dan program HARUS membatalkan kreasi PTS ketika ini terjadi , sesuai ptmx (4).
Aaron Jones
3
Itu "solusi" memberi saya tekad ... dalam kasus terbaik, itu kertas atas bug, itu mungkin menciptakan bug baru, dalam kasus terburuk itu menciptakan kerentanan keamanan yang serius. Silakan lakukan ini dengan pengembang glibc.
vonbrand
3
Kemudian laporkan ini ke orang-orang glibc.
vonbrand

Jawaban:

2

Jika glibc Anda cukup mutakhir, dan devpts sudah diatur dengan benar, seharusnya tidak perlu memanggil pt_chownhelper sama sekali.

Anda mungkin mengalami masalah yang diketahui / potensial menghapus setuid-root dari pt_chown.

grantpt()didukung devfsdari glibc-2.7 , perubahan dilakukan di glibc-2.11 sehingga daripada memeriksa secara eksplisit DEVFS_SUPER_MAGIC, ia memeriksa sebagai gantinya untuk melihat apakah perlu melakukan pekerjaan apa pun sebelum mencoba chown()atau mundur untuk memohon pt_chown.

Dari 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;
    }
  ...

Sebuah bait serupa digunakan untuk memeriksa gid dan izin. Tangkapannya adalah bahwa uid, gid dan mode harus sesuai dengan harapan (Anda, tty, dan tepat 620; konfirmasi dengan /usr/libexec/pt_chown --help). Jika tidak, chown()(yang akan membutuhkan kapabilitas CAP_CHOWN, CAP_FOWNER dari pemanggilan biner / proses) dicoba, dan jika itu gagal, pt_chownpenolong eksternal (yang harus di-setuid-root) dicoba. Agar pt_chowndapat menggunakan kemampuan itu (dan karenanya glibc Anda) harus dikompilasi dengan HAVE_LIBCAP. Namun , tampaknya itu pt_chown(pada glibc-2.17 , dan seperti yang Anda catat meskipun Anda belum menyatakan versinya) sulit dikodekan untuk menginginkan geteuid()==0 terlepas dari HAVE_LIBCAP, kode yang relevan dari 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'"));

(Berharap geteuid()==0sebelum mencoba menggunakan kapabilitas tampaknya tidak benar-benar sesuai semangat kapabilitas, saya akan menggunakan logging bug yang satu ini.)

Solusi potensial mungkin untuk memberikan CAP_CHOWN, CAP_FOWNER ke program yang terpengaruh, tapi saya benar-benar tidak merekomendasikan itu karena Anda tidak dapat membatasi itu untuk ptys tentu saja.

Jika itu tidak membantu Anda menyelesaikannya, menambal sshddan screensedikit kurang menyenangkan dibandingkan menambal glibc. Karena masalahnya terletak pada glibc, pendekatan yang lebih bersih adalah penggunaan selektif injeksi DLL untuk mengimplementasikan dummy grantpt().

mr.spuratic
sumber
"Karena masalahnya terletak pada glibc, pendekatan yang lebih bersih adalah penggunaan selektif injeksi DLL untuk mengimplementasikan dummy grantpt ()." - Cemerlang. Kenapa aku tidak memikirkan itu? Terima kasih. :)
Aaron Jones