⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch23_02.htm

📁 编程珍珠,里面很多好用的代码,大家可以参考学习呵呵,
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<html><head><title>Handling Timing Glitches (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly &amp; Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Handling Timing Glitches"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch23_01.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch23_01.htm">Chapter 23: Security</a></td><td align="right" valign="top" width="172"><a href="ch23_03.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">23.2. Handling Timing Glitches</h2><p><a name="INDEX-4016"></a><a name="INDEX-4017"></a><a name="INDEX-4018"></a><a name="INDEX-4019"></a>Sometimes your program's behavior is exquisitely sensitive to thetiming of external events beyond your control.  This is always aconcern when other programs, particularly inimical ones, might be vyingwith your program for the same resources (such as files or devices).  Ina multitasking environment, you cannot predict the order in whichprocesses waiting to run will be granted access to the processor.Instruction streams among all eligible processes are interleaved, sofirst one process gets some CPU, and then another process, and so on.Whose turn it is to run, and how long they're allowed to run, appearsto be random.  With just one program that's not a problem, but withseveral programs sharing common resources, it can be.</p><p><a name="INDEX-4020"></a>Thread programmers are especially sensitive to these issues.  Theyquickly learn not to say:<blockquote><pre class="programlisting">$var++ if $var == 0;</pre></blockquote>when they should say:<blockquote><pre class="programlisting">{    lock($var);    $var++ if $var == 0;}</pre></blockquote>The former produces unpredictable results when multiple executionthreads attempt to run this code at the same time.(See <a href="ch17_01.htm">Chapter 17, "Threads"</a>.)If you think of files as shared objects, and processes asthreads contending for access to those shared objects, you can see howthe same issues arise.  A process, after all, is really just a threadwith an attitude.  Or vice versa.</p><p>Timing unpredictabilities affect both privileged and nonprivilegedsituations.  We'll first describe how to cope with a long-standingbug in old Unix kernels that affects any set-id program.  Then we'llmove on to discuss race conditions in general, how they can turninto security holes, and steps you can take to avoid falling intothese holes.</p><h3 class="sect2">23.2.1. Unix Kernel Security Bugs</h3><a name="INDEX-4021"></a><a name="INDEX-4022"></a><a name="INDEX-4023"></a><a name="INDEX-4024"></a><a name="INDEX-4025"></a><a name="INDEX-4026"></a><a name="INDEX-4027"></a><p>Beyond the obvious problems that stem from giving special privilegesto interpreters as flexible and inscrutable as shells, older versionsof Unix have a kernel bug that makes any set-id script insecure beforeit ever gets to the interpreter.  The problem is not the scriptitself, but a race condition in what the kernel does when it finds aset-id executable script.  (The bug doesn't exist on machines thatdon't recognize <tt class="literal">#!</tt> in the kernel.) When a kernelopens such a file to see which interpreter to run, there's a delaybefore the (now set-id) interpreter starts up and reopens the file.That delay gives malicious entities a chance to change the file,especially if your system supports symbolic links.<a name="INDEX-4028"></a></p><p>Fortunately, sometimes this kernel "feature" can be disabled.Unfortunately, there are a couple of different ways to disable it.The system can outlaw scripts with the set-id bits set, which doesn'thelp much.  Alternatively, it can ignore the set-id bits on scripts.In the latter case, Perl can emulate the setuid and setgid mechanismwhen it notices the (otherwise useless) set-id bits on Perl scripts.It does this via a special executable called<em class="emphasis">suidperl</em>, which is automatically invoked for youif it's needed.<a href="#FOOTNOTE-7">[7]</a></p><blockquote class="footnote"><a name="FOOTNOTE-7"></a><p>[7]Needed <em class="emphasis">and</em>permitted--if Perl detects that the filesystem on which the scriptresides was mounted with the <tt class="literal">nosuid</tt> option, thatoption will still be honored.  You can't use Perl to sneak around yoursysadmin's security policy this way.</p></blockquote><p>However, if the kernel set-id script feature<em class="emphasis">isn't</em> disabled, Perl will complain loudly thatyour setuid script is insecure.  You'll either need to disable thekernel set-id script "feature", or else put a C wrapper around thescript.  A C wrapper is just a compiled program that does nothingexcept call your Perl program.  Compiled programs are not subject tothe kernel bug that plagues set-id scripts.</p><p><a name="INDEX-4029"></a><a name="INDEX-4030"></a>Here's a simple wrapper, written in C:<blockquote><pre class="programlisting">#define REAL_FILE "/path/to/script"main(ac, av)    char **av;{    execv(REAL_FILE, av);}</pre></blockquote>Compile this wrapper into an executable image and then make<em class="emphasis">it</em> rather than your script set-id.  Be sure touse an absolute filename, since C isn't smart enough to do taintchecking on your <tt class="literal">PATH</tt>.</p><p>(Another possible approach is to use the experimental C code generatorfor the Perl compiler.  A compiled image of your script will not havethe race condition.  See <a href="ch18_01.htm">Chapter 18, "Compiling"</a>.)</p><p>Vendors in recent years have finally started to provide systems freeof the set-id bug.  On such systems, when the kernel gives the name ofthe set-id script to the interpreter, it no longer uses a filenamesubject to meddling, but instead passes a special file representingthe file descriptor, like <em class="emphasis">/dev/fd/3</em>.  Thisspecial file is already opened on the script so that there can be norace condition for evil scripts toexploit.<a href="#FOOTNOTE-8">[8]</a> Most modern versions of Unix use thisapproach to avoid the race condition inherent in opening the samefilename twice.</p><blockquote class="footnote"><a name="FOOTNOTE-8"></a><p>[8]On thesesystems, Perl should be compiled with<tt class="userinput"><b>-DSETUID_SCRIPTS_ARE_SECURE_NOW</b></tt>.  The<em class="emphasis">Configure</em> program that builds Perl tries tofigure this out for itself, so you should never have to specify thisexplicitly.</p></blockquote><a name="ch23-sect-hrc"></a><h3 class="sect2">23.2.2. Handling Race Conditions</h3><p><a name="INDEX-4031"></a><a name="INDEX-4032"></a><a name="INDEX-4033"></a>Which runs us right into the topic of race conditions.  What are theyreally?  Race conditions turn up frequently in security discussions.(Although less often than they turn up in insecure programs.Unfortunately.)  That's because they're a fertile source of subtleprogramming errors, and such errors can often be turned into security<em class="emphasis">exploits</em> (the polite term for screwing upsomeone's security).  A race condition exists when the result ofseveral interrelated events depends on the ordering of those events,but that order cannot be guaranteed due to nondeterministic timingeffects.  Each event races to be the first one done, and the finalstate of the system is anybody's guess.</p><p>Imagine you have one process overwriting an existing file, andanother process reading that same file.  You can't predict whetheryou read in old data, new data, or a haphazard mixture of the two.You can't even know whether you've read all the data.  The readercould have won the race to the end of the file and quit.  Meanwhile,if the writer kept going after the reader hit end-of-file, the file wouldgrow past where the reader stopped reading, and the reader wouldnever know it.</p><p>Here the solution is simple: just have both parties<tt class="literal">flock</tt> the file.  The reader typically requests ashared lock, and the writer typically requests an exclusive one.  Solong as all parties request and respect these advisory locks, readsand writes cannot be interleaved, and there's no chance of mutilateddata.  See the section <a href="ch16_02.htm#ch16-sect-fl">Section 23.2.1, "File Locking"</a> in <a href="ch16_01.htm">Chapter 16, "Interprocess Communication"</a>.</p><p><a name="INDEX-4034"></a>You risk a far less obvious form of race condition every time youlet operations on a filename govern subsequent operationson that file.  When used on filenames rather than filehandles,the file test operators represent something of a garden path leadingstraight into a race condition.  Consider this code:<blockquote><pre class="programlisting">if (-e $file) {    open(FH, "&lt; $file")        or die "can't open $file for reading: $!";}else {    open(FH, "&gt; $file")        or die "can't open $file for writing: $!";}</pre></blockquote><a name="INDEX-4035"></a>The code looks just about as straightforward as it gets, but it'sstill subject to races.  There's no guarantee that the answer returnedby the <tt class="userinput"><b>-e</b></tt> test will still be valid by the timeeither <tt class="literal">open</tt> is called.  In the<tt class="literal">if</tt> block, another process could have removed thefile before it could be opened, and you wouldn't find the file youthought was going to be there.  In the <tt class="literal">else</tt> block,another process could have created the file before the second<tt class="literal">open</tt> could get its turn to create the file, so thefile that you thought would not be there, would be.  The simple<tt class="literal">open</tt> function creates new files but overwritesexisting ones.  You may think you want to overwrite any existing file,but consider that the existing file might be a newly created alias orsymbolic link to a file elsewhere on the system that you very muchdon't want to overwrite.  You may think you know what a filename meansat any particular instant, but you can never really be sure, as longas any other processes with access to the file's directory are runningon the same system.</p><p><a name="INDEX-4036"></a>To fix this problem of overwriting, you'll need to use<tt class="literal">sysopen</tt>, which provides individual controls overwhether to create a new file or to clobber an existing one.  And we'llditch that <tt class="userinput"><b>-e</b></tt> file existence test since itserves no useful purpose here and only increases our exposure to raceconditions.<blockquote><pre class="programlisting">use Fcntl qw/O_WRONLY O_CREAT O_EXCL/;open(FH, "&lt;", $file)    or sysopen(FH, $file, O_WRONLY | O_CREAT | O_EXCL)    or die "can't create new file $file: $!";</pre></blockquote>Now even if the file somehow springs into existence between when<tt class="literal">open</tt> fails and when <tt class="literal">sysopen</tt> tries to open a new file forwriting, no harm is done, because with the flags provided, <tt class="literal">sysopen</tt>will refuse to open a file that already exists.</p><p><a name="INDEX-4037"></a>If someone is trying to trick your program into misbehaving, there's agood chance they'll go about it by having files appear and disappearwhen you're not expecting.  One way to reduce the risk of deception is

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -