อะไรจะเป็นวิธีที่ดีที่สุดในการแก้ไขปัญหา glibc นี้


26

ฉันจัดการกล่อง Gentoo Hardened ที่ใช้ความสามารถของไฟล์เพื่อกำจัดความต้องการไบนารีส่วนใหญ่ของ setuid (เช่น/bin/pingมี CAP_NET_RAW และอื่น ๆ )

Infact ไบนารีเดียวที่ฉันเหลืออยู่คืออันนี้:

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

ถ้าฉันลบบิต setuid หรือติดตั้งระบบไฟล์รูทของฉันnosuidใหม่ sshd และ GNU Screen หยุดทำงานเพราะพวกเขาเรียกgrantpt(3)pesudoterminals หลักและ glibc เรียกใช้โปรแกรมนี้เพื่อ chown และ chmod ทาส pseudoterminal ใต้/dev/pts/และหน้าจอ GNU ใส่ใจเมื่อฟังก์ชั่นนี้ ล้มเหลว

ปัญหาคือ manpage สำหรับการgrantpt(3)ระบุอย่างชัดเจนว่าภายใต้ Linux พร้อมกับdevptsติดตั้งระบบไฟล์ไม่จำเป็นต้องใช้ตัวช่วยไบนารี เคอร์เนลจะตั้งค่า UID & GID ของ slave ให้เป็น UID จริง & GID ของกระบวนการที่เปิด/dev/ptmx(โดยการโทรgetpt(3)) โดยอัตโนมัติ

ฉันได้เขียนโปรแกรมตัวอย่างเล็ก ๆ เพื่อสาธิตสิ่งนี้:

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

สังเกตมันในทางปฏิบัติด้วยบิต setuid ในโปรแกรมดังกล่าวลบออก:

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

ฉันมีความคิดเพียงเล็กน้อยเกี่ยวกับวิธีแก้ไขปัญหานี้:

1) แทนที่โปรแกรมด้วยโครงกระดูกที่ส่งกลับค่า 0

2) Patch allowpt () ใน libc ของฉันไม่ทำอะไรเลย

ฉันสามารถทำทั้งสองอย่างนี้โดยอัตโนมัติ แต่ไม่มีใครมีข้อเสนอแนะสำหรับอีกคนหนึ่งหรือคำแนะนำสำหรับวิธีอื่นในการแก้ปัญหานี้

mount -o remount,nosuid /ครั้งนี้จะแก้ไขได้ผมจนสามารถ


ในขณะที่ฉันรอการตอบรับฉันไปด้วยวิธีที่ 1 และ sshd และ GNU Screen ยังคงทำงาน
แอรอนโจนส์

อะไรคือโปรแกรมที่ล้มเหลว บางทีพวกเขาอาจจะเสียและตรวจสอบไม่ได้สำหรับpty(เท่าที่ควร) แต่สำหรับโปรแกรม?
vonbrand

โปรแกรมใด ๆ ที่ไม่มี CAP_CHOWN และ CAP_FOWNER, call grantpt () และไบนารีตัวช่วยเหลือไม่ได้เริ่มต้นด้วย EUID == 0 จะมีโค้ดส่งคืนที่ไม่ใช่ศูนย์สำหรับ Grantpt () และโปรแกรมควรยกเลิกการสร้าง PTS เมื่อเกิดเหตุการณ์นี้ ตาม ptmx (4)
แอรอนโจนส์

3
"ทางออก" นั้นทำให้ฉันนึกถึงวิลลี่ ... ในกรณีที่ดีที่สุดมันเขียนทับข้อผิดพลาดมันอาจจะสร้างบั๊กใหม่ในกรณีที่แย่ที่สุดมันสร้างช่องโหว่ด้านความปลอดภัยที่ร้ายแรง โปรดรับสิ่งนี้กับนักพัฒนา glibc
vonbrand

3
จากนั้นรายงานสิ่งนี้ต่อผู้คน glibc
vonbrand

คำตอบ:


2

หากglibcของคุณเป็นกระแสอย่างสมเหตุสมผลและตั้งค่าdevptsอย่างถูกต้องไม่จำเป็นต้องเรียกใช้ตัวpt_chownช่วยเลย

คุณอาจจะใช้เป็นที่รู้จักกันออก / ศักยภาพการลบ setuid pt_chownรากจาก

grantpt()ได้รับการสนับสนุนdevfsจากglibc-2.7การเปลี่ยนแปลงได้ทำในglibc-2.11แต่เพื่อที่มากกว่าอย่างชัดเจนตรวจสอบDEVFS_SUPER_MAGICจะตรวจสอบแทนเพื่อดูว่าจะต้องมีการทำงานใด ๆ ก่อนที่จะพยายามหรือกลับไปกล่าวอ้างล้มchown()pt_chown

จาก 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;
    }
  ...

stanza ที่คล้ายกันถูกใช้เพื่อตรวจสอบ gid และการอนุญาต จับเป็นว่า uid, GID และโหมดต้องตรงกับความคาดหวัง (คุณ TTY และตรง 620; ยืนยันด้วย/usr/libexec/pt_chown --help) หากไม่พยายามchown()(ซึ่งต้องใช้ความสามารถ CAP_CHOWN, CAP_FOWNER ของการเรียกไบนารี / กระบวนการ) และหากล้มเหลวจะมีการพยายามpt_chownช่วยเหลือจากภายนอก (ซึ่งต้องเป็น setuid-root) ในเพื่อpt_chownที่จะสามารถใช้ความสามารถมัน (และด้วยเหตุนี้ glibc ของคุณ) HAVE_LIBCAPจะต้องได้รับการรวบรวมด้วย แต่มันก็ดูเหมือนว่าpt_chownเป็น (เหมือนglibc-2.17และเป็นคุณสังเกตเห็นว่าคุณยังไม่ได้ระบุรุ่น) กำหนดค่าตายตัวที่จะต้องการgeteuid()==0 โดยไม่คำนึงถึงของHAVE_LIBCAPรหัสที่เกี่ยวข้องจาก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()==0ก่อนที่จะพยายามใช้ความสามารถดูเหมือนจะไม่ได้อยู่ในจิตวิญญาณของความสามารถฉันจะไปกับการบันทึกข้อบกพร่องในหนึ่งนี้)

วิธีแก้ปัญหาที่เป็นไปได้คือการมอบ CAP_CHOWN, CAP_FOWNER ให้กับโปรแกรมที่ได้รับผลกระทบ แต่ฉันไม่แนะนำให้ทำเพราะคุณไม่สามารถ จำกัด สิ่งนั้นให้กับ ptys ได้

หากวิธีนี้ไม่ช่วยให้คุณแก้ไขได้ให้แก้ไขsshdและscreenไม่น่าพอใจน้อยกว่าการแก้ไข glibc ตั้งแต่ปัญหาอยู่ภายใน glibc แม้ว่าวิธีการทำความสะอาดจะเลือกใช้การฉีด DLLgrantpt()ที่จะใช้หุ่น


"เนื่องจากปัญหาอยู่ภายใน glibc วิธีการที่สะอาดกว่านั้นก็คือการเลือกใช้การฉีด DLL เพื่อใช้ dummy Grant ()" - ยอดเยี่ยม ทำไมฉันไม่คิดอย่างนั้น ขอบคุณ :)
Aaron Jones
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.