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