2010-11-13 11 views
28

यूनिक्स में, किसी अज्ञात फ़ाइल में हैंडल बनाना संभव है, उदाहरण के लिए, इसे क्रिएट() के साथ बनाना और खोलना और फिर अनलिंक() के साथ निर्देशिका लिंक को हटा देना एक इनोड और भंडारण वाली फ़ाइल के साथ, लेकिन इसे फिर से खोलने का कोई भी संभावित तरीका नहीं है। ऐसी फ़ाइलों को अक्सर temp फ़ाइलों के रूप में उपयोग किया जाता है (और आमतौर पर यह है कि tmpfile() आपको वापस देता है)।एक अज्ञात (अनलिंक लेकिन खुली) फ़ाइल को रिंकंक करना

मेरा प्रश्न: क्या इस तरह की फ़ाइल को निर्देशिका संरचना में फिर से संलग्न करने का कोई तरीका है? यदि आप ऐसा कर सकते हैं तो इसका मतलब है कि आप उदा। फ़ाइल को लागू करने के लिए लिखते हैं ताकि फाइल परमाणु रूप से और पूरी तरह से गठित हो। यह मेरी बाध्यकारी स्वच्छता के लिए अपील करता है। ;)

प्रासंगिक सिस्टम कॉल फ़ंक्शंस के माध्यम से पोकिंग करते समय मुझे लिंक() (जिसे chmod()/fchmod() से तुलना करें) का संस्करण() की तुलना करने की उम्मीद है, लेकिन कम से कम लिनक्स पर यह अस्तित्व में नहीं है ।

डिस्क के निर्देशिका संरचना में फ़ाइल नाम को संक्षिप्त रूप से उजागर किए बिना अज्ञात फ़ाइल को बनाने के तरीके के बारे में बोनस पॉइंट्स।

उत्तर

30

A patch for a proposed Linux flink() system call कई साल पहले सबमिट किया गया था, लेकिन जब लिनस ने "there is no way in HELL we can do this securely without major other incursions" कहा, तो इस पर बहुत कुछ बहस खत्म हो गई थी।

अद्यतन: लिनक्स 3.11 के रूप में, यह अब संभव नई O_TMPFILE ध्वज के साथ open() का उपयोग कर कोई निर्देशिका प्रविष्टि के साथ एक फ़ाइल बनाते हैं, और फाइल सिस्टम में लिंक करने के लिए एक बार यह पूरी तरह से /proc/self/fd/fd पर linkat() का उपयोग कर बना हैAT_SYMLINK_FOLLOW ध्वज के साथ।

निम्न उदाहरण open() मैनुअल पृष्ठ पर प्रदान की जाती है:

char path[PATH_MAX]; 
    fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); 

    /* File I/O on 'fd'... */ 

    snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); 
    linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file", AT_SYMLINK_FOLLOW); 

ध्यान दें कि linkat() जा फिर से संलग्न करने के लिए खुली फ़ाइलों के बाद पिछले लिंक unlink() साथ हटा दिया जाता है की अनुमति नहीं होगी।

+0

ता। वह एक समाधान का प्रस्ताव करता है जो आपको काम करना चाहिए, आपको याद रखें। यद्यपि पूर्ण बाध्यकारी स्वच्छता के लिए आपको शायद निर्देशिका पर क्रिएट() को कॉल करने का एक तरीका भी चाहिए ताकि यह फ़ाइल और इनोड बनाता है लेकिन निर्देशिका प्रविष्टि नहीं, ताकि यह पहले स्थान पर कभी भी लिंक न हो। – ijw

+0

अद्यतन जीत से भरा है। मैं +2 आप नहीं कर सकता लेकिन मैं कर सकता था अगर मैं कर सकता। – ijw

+0

उलझन में, 'लिंकैट()' सामान्य ओपन-लेकिन-अनलिंक फ़ाइल को फिर से संलग्न करने के प्रयासों पर 'ENOENT' देता है। (या तो 'AT_SYMLINK_FOLLOW' या' AT_EMPTY_PATH') के साथ –

1

मेरा प्रश्न: क्या इस तरह की फ़ाइल को निर्देशिका संरचना में फिर से संलग्न करने का कोई तरीका है? यदि आप ऐसा कर सकते हैं तो इसका मतलब है कि आप उदा। फ़ाइल को लागू करने के लिए लिखते हैं ताकि फाइल परमाणु रूप से और पूरी तरह से गठित हो। यह मेरी बाध्यकारी स्वच्छता के लिए अपील करता है। ;)

यदि यह आपका एकमात्र लक्ष्य है, तो आप इसे एक बहुत ही सरल और व्यापक रूप से उपयोग किए जाने वाले तरीके से प्राप्त कर सकते हैं। आप a.dat करने के लिए outputting रहे हैं, तो:

  1. ओपन a.dat.part लिखने के लिए।
  2. अपना डेटा लिखें।
  3. a.dat.part से a.dat का नाम बदलें।

मैं समझना चाहता हूं कि साफ होना चाहते हैं, लेकिन फ़ाइल को अनलिंक करना और इसे "साफ" होना सिर्फ मूर्खतापूर्ण है।

This question on serverfault यह इंगित करता है कि इस प्रकार का पुनः लिंकिंग असुरक्षित है और समर्थित नहीं है।

+0

cdhowie सही है कि केवल एक अस्थायी फ़ाइल को लिखना बहुत बेहतर है। ध्यान दें कि जो सवाल आप मूल रूप से लिंक करते हैं, वह कहता है कि यह नहीं किया जा सकता है: आप '/ proc' से किसी अन्य फाइल सिस्टम में हार्डलिंक नहीं कर सकते हैं। – poolie

+0

@poolie किसी भी तरह से मुझे याद आया। सर्वरफॉल्ट पर एक अधिक उपयुक्त प्रश्न के लिए स्विच स्विच। – cdhowie

+2

अंतर यह है कि सर्वरफॉल्ट प्रश्न में प्रोग्राम एक अपारदर्शी चीज है (एक sysadmin फोरम और सब होने के नाते - यहां मैं वास्तव में प्रक्रिया के भीतर से प्रोग्रामेटिक रूप से खेलने के बारे में फ़ाइल हैंडल रखने के बारे में बात कर रहा हूं। अगर आप स्पष्ट रूप से उसमें बहिष्कृत कर सकते हैं भी, हमारे पास एक जवाब है;) – ijw

-1

स्पष्ट रूप से, यह संभव है - fsck उदाहरण के लिए, यह करता है। हालांकि, fsck यह प्रमुख स्थानीयकृत फ़ाइल सिस्टम मोोजो के साथ करता है और स्पष्ट रूप से पोर्टेबल नहीं होगा, न ही एक अप्रतिबंधित उपयोगकर्ता के रूप में निष्पादन योग्य होगा। यह ऊपर debugfs टिप्पणी के समान है।

लिख रहा है कि flink(2) कॉल एक दिलचस्प अभ्यास होगा। जैसा कि ijw इंगित करता है, यह अस्थायी फ़ाइल नामकरण (नाम बदलें, नोट, परमाणु गारंटीकृत है) के वर्तमान अभ्यास पर कुछ फायदे प्रदान करेगा।

-2

खेल के देर से कृपया मुझे http://computer-forensics.sans.org/blog/2009/01/27/recovering-open-but-unlinked-file-data मिला जो प्रश्न का उत्तर दे सकता है। मैंने इसका परीक्षण नहीं किया है, हालांकि, वाईएमएमवी। यह आवाज लग रहा है।

+1

जैसा कि मैंने उम्मीद की थी, यह सिर्फ 'बिल्ली/proc//fd/N> newfile' है। साफ अगर आपको/proc/fd के बारे में पता नहीं था, लेकिन इस सवाल का जवाब नहीं है। हटाए गए फ़ाइल में और परिवर्तन आपको 'सीपी' या' बिल्ली 'के साथ प्राप्त स्नैपशॉट के बाद दिखाई नहीं देंगे। ('tail -c +1 -f/proc//fd/n> newfile' आपको सामग्री की एक प्रति के साथ छोड़ देना चाहिए, अगर प्रक्रिया लिखने में केवल यह संलग्न होता है।) –

1

linkat(2) के बारे में @ mark4o पोस्ट करने के लिए धन्यवाद, विवरण के लिए उसका उत्तर देखें।

मैं यह देखने का प्रयास करना चाहता था कि वास्तव में क्या हुआ था जब वास्तव में किसी अज्ञात फ़ाइल को उस फ़ाइल सिस्टम में संग्रहीत करने के लिए वास्तव में लिंक करने का प्रयास किया गया था। (अक्सर /tmp, उदाहरण के लिए वीडियो डेटा के लिए फ़ायरफ़ॉक्स खेल रहा है)।


लिनक्स 3.16 के रूप में, अभी भी एक हटाई गई फ़ाइल को अनदेखा करने का कोई तरीका नहीं है जो अभी भी खुला है। AT_SYMLINK_FOLLOW और AT_EMPTY_PATHlinkat(2) के लिए हटाई गई फ़ाइलों के लिए चाल करें जो कि नाम के रूप में भी नाम के रूप में उपयोग करते हैं।

एकमात्र विकल्प tail -c +1 -f /proc/19044/fd/1 > data.recov है, जो एक अलग प्रति बनाता है, और इसे पूरा होने पर आपको इसे मैन्युअल रूप से मारना होगा।


यहां परीक्षण के लिए पकाया गया पर्ल रैपर है। यह सत्यापित करने के लिए कि आपका सिस्टम अभी भी खुली फ़ाइलों को मिटा नहीं सकता है, strace -eopen,linkat linkat.pl - </proc/.../fd/123 newname का उपयोग करें। (sudo के साथ भी लागू होता है)। जाहिर है आपको इसे चलाने से पहले इंटरनेट पर जो कोड मिलता है उसे पढ़ना चाहिए, या सैंडबॉक्स वाले खाते का उपयोग करना चाहिए।

#!/usr/bin/perl -w 
# 2015 Peter Cordes <[email protected]> 
# public domain. If it breaks, you get to keep both pieces. Share and enjoy 

# Linux-only linkat(2) wrapper (opens "." to get a directory FD for relative paths) 
if ($#ARGV != 1) { 
    print "wrong number of args. Usage:\n"; 
    print "linkat old new \t# will use AT_SYMLINK_FOLLOW\n"; 
    print "linkat - <old new\t# to use the AT_EMPTY_PATH flag (requires root, and still doesn't re-link arbitrary files)\n"; 
    exit(1); 
} 

# use POSIX qw(linkat AT_EMPTY_PATH AT_SYMLINK_FOLLOW); #nope, not even POSIX linkat is there 

require 'syscall.ph'; 
use Errno; 
# /usr/include/linux/fcntl.h 
# #define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ 
# #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ 
# #define AT_EMPTY_PATH  0x1000 /* Allow empty relative pathname */ 
unless (defined &AT_SYMLINK_NOFOLLOW) { sub AT_SYMLINK_NOFOLLOW() { 0x0100 } } 
unless (defined &AT_SYMLINK_FOLLOW ) { sub AT_SYMLINK_FOLLOW () { 0x0400 } } 
unless (defined &AT_EMPTY_PATH  ) { sub AT_EMPTY_PATH  () { 0x1000 } } 


sub my_linkat ($$$$$) { 
    # tmp copies: perl doesn't know that the string args won't be modified. 
    my ($oldp, $newp, $flags) = ($_[1], $_[3], $_[4]); 
    return !syscall(&SYS_linkat, fileno($_[0]), $oldp, fileno($_[2]), $newp, $flags); 
} 

sub linkat_dotpaths ($$$) { 
    open(DOTFD, ".") or die "open . $!"; 
    my $ret = my_linkat(DOTFD, $_[0], DOTFD, $_[1], $_[2]); 
    close DOTFD; 
    return $ret; 
} 

sub link_stdin ($) { 
    my ($newp,) = @_; 
    open(DOTFD, ".") or die "open . $!"; 
    my $ret = my_linkat(0, "", DOTFD, $newp, &AT_EMPTY_PATH); 
    close DOTFD; 
    return $ret; 
} 

sub linkat_follow_dotpaths ($$) { 
    return linkat_dotpaths($_[0], $_[1], &AT_SYMLINK_FOLLOW); 
} 


## main 
my $oldp = $ARGV[0]; 
my $newp = $ARGV[1]; 

# link($oldp, $newp) or die "$!"; 
# my_linkat(fileno(DIRFD), $oldp, fileno(DIRFD), $newp, AT_SYMLINK_FOLLOW) or die "$!"; 

if ($oldp eq '-') { 
    print "linking stdin to '$newp'. You will get ENOENT without root (or CAP_DAC_READ_SEARCH). Even then doesn't work when links=0\n"; 
    $ret = link_stdin($newp); 
} else { 
    $ret = linkat_follow_dotpaths($oldp, $newp); 
} 
# either way, you still can't re-link deleted files (tested Linux 3.16 and 4.2). 

# print STDERR 
die "error: linkat: $!.\n" . ($!{ENOENT} ? "ENOENT is the error you get when trying to re-link a deleted file\n" : '') unless $ret; 

# if you want to see exactly what happened, run 
# strace -eopen,linkat linkat.pl 
संबंधित मुद्दे