इस glibc समस्या के आसपास काम करने का सबसे अच्छा तरीका क्या होगा?


26

मैं एक Gentoo हार्डडेन बॉक्स का उपयोग करता /bin/pingहूं, जो सेतु -रूट बायनेरिज़ (जैसे CAP_NET_RAW, आदि) की अधिकांश आवश्यकता को समाप्त करने के लिए फ़ाइल क्षमताओं का उपयोग करता है ।

वास्तव में, मेरे पास जो एकमात्र बाइनरी है वह यह है:

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

यदि मैं सेट्यूड बिट को हटा देता हूं, या अपने रूट फाइलसिस्टम nosuid, sshd और GNU स्क्रीन को रोक देता हूं , तो वे काम करना बंद कर देते हैं, क्योंकि वे grantpt(3)अपने मास्टर पेसुडोटर्मिनल्स पर कॉल करते हैं और ग्लिब्क जाहिरा तौर पर गुलाम स्यूडोटर्मिनल के तहत इस कार्यक्रम को चांस और चोदने के लिए निष्पादित करते हैं /dev/pts/, और GNU स्क्रीन इस फ़ंक्शन के बारे में परवाह करता है। विफल रहता है।

समस्या यह है कि, मेन्यू में grantpt(3)स्पष्ट रूप से कहा गया है कि लिनक्स के तहत, devptsफाइलसिस्टम माउंटेड होने के साथ, इस तरह के किसी भी सहायक बाइनरी की आवश्यकता नहीं है; कर्नेल स्वचालित रूप से UID & GID को गुलाम की वास्तविक 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;
}

हटाए गए पूर्वोक्त कार्यक्रम पर सेट बिट के साथ कार्रवाई में इसे देखें:

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) मेरे कुछ नहीं करने के लिए पैच अनुदान () मेरे libc में।

मैं इन दोनों को स्वचालित कर सकता हूं, लेकिन क्या किसी के पास एक के लिए एक सिफारिश है, या इसे कैसे हल करने के लिए सिफारिशें हैं?

एक बार यह हल हो जाने के बाद, मैं आखिरकार mount -o remount,nosuid /


जब मैं एक प्रतिक्रिया का इंतजार कर रहा हूं, मैं दृष्टिकोण 1 के साथ चला गया, और sshd और GNU स्क्रीन अभी भी काम करते हैं।
हारून जोन्स

वास्तव में कौन से कार्यक्रम विफल होते हैं? शायद वे टूट गए हैं और जांच नहीं कर रहे हैं pty(जैसा कि उन्हें चाहिए) लेकिन कार्यक्रम के लिए?
वॉनब्रांड

कोई भी प्रोग्राम जिसमें CAP_CHOWN और CAP_FOWNER नहीं हैं, कॉल अनुदान (), और सहायक द्विआधारी EUID == 0 के साथ शुरू नहीं हुआ है, इसमें अनुदान के लिए एक गैर-शून्य रिटर्न कोड होगा (), और प्रोग्राम SHODD गर्भपात PTS निर्माण जब यह होता है। , प्रति ptmx (4) के अनुसार।
एरॉन जोन्स

3
यह "समाधान" मुझे वसीयत देता है ... सबसे अच्छा मामले में, यह एक बग पर कागजात करता है, यह शायद एक नया बग बनाता है, सबसे खराब स्थिति में यह एक गंभीर सुरक्षा भेद्यता बनाता है। कृपया इसे ग्लिबेक डेवलपर्स के साथ लें।
वॉनब्रांड

3
फिर इस बात की सूचना ग्लिब लोगों को दें।
वॉनब्रांड

जवाबों:


2

यदि आपका glibc यथोचित वर्तमान है, और devpts ठीक से सेट है, वहाँ आह्वान करने के लिए कोई ज़रूरत नहीं होना चाहिए pt_chownसब पर सहायक।

आप एक ज्ञात / संभावित मुद्दे में चल रहे हो सकते हैं, जो सेतु-मूल को हटा रहा है pt_chown

grantpt()glibc-2.7devfs से समर्थित , glibc-2.11 में परिवर्तन किए गए थे, ताकि स्पष्ट रूप से जांचने के बजाय, यह देखने के बजाय यह जांचने के लिए कि क्या इसे वापस करने से पहले किसी भी कार्य को करने की आवश्यकता है या वापस लाने के लिए ।DEVFS_SUPER_MAGICchown()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;
    }
  ...

Gid और अनुमतियों की जांच करने के लिए एक समान श्लोक का उपयोग किया जाता है। पकड़ यह है कि यूआईडी, जीआईडी ​​और मोड अपेक्षाओं (आप, tty, और वास्तव में 620; पुष्टि के साथ मेल खाना चाहिए /usr/libexec/pt_chown --help)। यदि नहीं, chown()(जिसमें क्षमताओं की आवश्यकता होगी CAP_CHOWN, कॉलिंग बाइनरी / प्रक्रिया का CAP_FOWNER) प्रयास किया जाता है, और यदि वह विफल रहता है, तो pt_chownबाहरी सहायक (जिसे सेतु-रूट होना चाहिए) का प्रयास किया जाता है। के लिए आदेश में 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 देने के लिए संभावित वर्कअराउंड हो सकता है, लेकिन मैं वास्तव में यह अनुशंसा नहीं करता हूं कि चूंकि आप निश्चित रूप से इसे सीमित नहीं कर सकते हैं।

अगर यह आपको इसे हल करने में मदद नहीं करता है, तो पैचिंग sshdऔर screenपैचिंग ग्लिबैक की तुलना में थोड़ा कम असहनीय है। चूंकि समस्या glibc के भीतर है, हालांकि, एक डमी को लागू करने के लिए एक क्लीनर दृष्टिकोण DLL इंजेक्शन का चयनात्मक उपयोग होगा grantpt()


"चूंकि समस्या glibc के भीतर है, हालांकि, एक क्लीनर दृष्टिकोण DLL इंजेक्शन का चयनात्मक उपयोग होगा ताकि डमीपेंट () को लागू किया जा सके।" -- प्रतिभाशाली। मैंने ऐसा क्यों नहीं सोचा? धन्यवाद। :)
आरोन जोन्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.