develooper Front page | perl.perl5.porters | Postings from November 2013

[perl #120634] unlink on a directory can fail to set errno when running as root

Thread Previous
From:
Evan Zacks
Date:
November 26, 2013 19:34
Subject:
[perl #120634] unlink on a directory can fail to set errno when running as root
Message ID:
rt-4.0.18-30574-1385481291-323.120634-75-0@perl.org
# New Ticket Created by  Evan Zacks 
# Please include the string:  [perl #120634]
# in the subject line of all future correspondence about this issue. 
# <URL: https://rt.perl.org/Ticket/Display.html?id=120634 >


This is a bug report for perl from zackse@cpan.org,
generated with the help of perlbug 1.39 running under perl 5.19.7.


-----------------------------------------------------------------
[Please describe your issue here]

In 40ea6f6, the perlfunc pod for unlink was updated to mention that it
sets $! on failure. There is a case, however, where this is not true:
if unlink is called on an existing directory while running as root
without -U, the unlink call fails but does not set $!, meaning the
standard idiom of unlink(...) or warn/die $! will reflect whatever the
previous value of $! was. The reason is that unlink(2) is not actually
called in this case.

Here is an example that exhibits the problem on a Linux system:

    # 104 is ECONNRESET
    $ sudo perl -e '$dir = shift; mkdir $dir; $! = 104; unlink $dir or die
$!' /tmp/newdir
    Connection reset by peer at -e line 1.

    $ perl -e '$dir = shift; mkdir $dir; $! = 104; unlink $dir or die $!'
/tmp/otherdir
    Is a directory at -e line 1.

The code path can be found in doio.c starting at line 1800 of the
blead branch. If unlink is called as a user or as root with -U,
unlink(2) is called (line 1810), so attempting to remove a directory
would set errno to EISDIR as expected. If running as root without -U
(so PL_unsafe is false), line 1814 is reached, where lstat succeeds
and the S_ISDIR macro returns true, so the argument is skipped without
warning.

In #p5p, mst suggested that setting errno to EISDIR in this case would
be appropriate, since that is the reason the argument is
skipped. Attached is a patch, though I'm not certain about the proper
VMS error code for EISDIR. This OpenVMS reference suggested what
appears to be a default of SS$_ABORT:

    http://h71000.www7.hp.com/doc/73final/6529/6529pro_024.html

I'm also not sure whether a different errno is required for other
operating systems like Windows. Running the above test case with -U on
Windows 7 (to force unlink(2)) sets errno to EACCES which suggests
that the patch may need some changes. Is win32_get_errno() appropriate
here or should EACCESS be hardcoded, for example?

Hope this helps, and please let me know if the patch needs to be
reworked.

Thanks,
-Evan


[Please do not change anything below this line]
-----------------------------------------------------------------
---
Flags:
    category=core
    severity=low
---
Site configuration information for perl 5.19.7:

Configured by zackse at Mon Nov 25 17:20:01 EST 2013.

Summary of my perl5 (revision 5 version 19 subversion 7) configuration:
  Local Commit: 4628660aea283aff242e0d495e726eeb60b930b9
  Ancestor: ea5eb3d3ca6e00870adfc543a2364826e1c0f77e
  Platform:
    osname=linux, osvers=2.6.38-14-generic, archname=x86_64-linux
    uname='linux pocampo 2.6.38-14-generic #58-ubuntu smp tue mar 27
20:04:55 utc 2012 x86_64 x86_64 x86_64 gnulinux '
    config_args='-Dprefix=/data/tmp/perl-blead -Dusedevel -de'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector
-I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fno-strict-aliasing -pipe -fstack-protector
-I/usr/local/include'
    ccversion='', gccversion='4.5.2', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib /usr/lib/x86_64-linux-gnu /lib64
/usr/lib64 /usr/local/lib64
    libs=-lnsl -ldb -ldl -lm -lcrypt -lutil -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
    libc=, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.13'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib
-fstack-protector'

Locally applied patches:
    4628660aea283aff242e0d495e726eeb60b930b9

---
@INC for perl 5.19.7:
    /data/tmp/perl-blead/lib/site_perl/5.19.7/x86_64-linux
    /data/tmp/perl-blead/lib/site_perl/5.19.7
    /data/tmp/perl-blead/lib/5.19.7/x86_64-linux
    /data/tmp/perl-blead/lib/5.19.7
    .

---
Environment for perl 5.19.7:
    HOME=/home/zackse
    LANG=en_US.UTF-8
    LANGUAGE=en_US:en
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)

PATH=/home/zackse/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/zackse/local/bin
    PERL_BADLANG (unset)
    SHELL=/bin/bash

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About