Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re^2: readdir() on a sysopen() handle?

by perlhuhn (Novice)
on Aug 20, 2017 at 10:49 UTC ( [id://1197694]=note: print w/replies, xml ) Need Help??


in reply to Re: readdir() on a sysopen() handle?
in thread readdir() on a sysopen() handle?

Such a filter would have to use stat() to determine if an entry is a diretory before opening it. The problem is that an entry might change from a directory to a symbolic link between the stat() and the open(). O_NOFOLLOW prevents such race conditions.

Replies are listed 'Best First'.
Re^3: readdir() on a sysopen() handle?
by shmem (Chancellor) on Aug 20, 2017 at 14:37 UTC
    The problem is that an entry might change from a directory to a symbolic link between the stat() and the open().

    Wouldn't a second stat() after the open tell? Well duh, the underlying file could just switch back from symlink to directory between the open() and the second stat, e.g. something that emulates a directory via a maliciously loaded file system module doing sinister things. Just curious - what problem are you trying to solve?

    Correct me if I am wrong, but after getting a handle to something, even if the something is renamed, deleted, and symlinked back, it holds to the original structure being accessed:

    my $path = '/tmp/open'; -d $path and die "remove $path first\n"; mkdir $path; for (qw(foo bar quux)) { open my $fh, '>',"$path/$_"; } mkdir "$path/baz"; for (qw(blorf blorfldyick)) { open my $fh,'>', "$path/baz/$_"; } opendir my $dh1, $path; while(readdir $dh1) { next if /^\.\.?$/; print "read(dh1): $path/$_\n"; if (-d "$path/$_") { opendir my $dh2, "$path/$_" or die; # emulate external change directory to symlink rename "$path/$_","$path/fie"; symlink "$path/fie", "$path/$_" or die; # end emulate if(-l "$path/$_") { print "bogus change to $path/$_:\n"; print " $path/$_ points to ",readlink "$path/$_","\n"; } while (my $e = readdir $dh2) { next if $e =~ /^\.\.?$/; print "read(dh2): $e\n"; } } } __END__ read(dh1): /tmp/open/foo read(dh1): /tmp/open/quux read(dh1): /tmp/open/baz bogus change to /tmp/open/baz: /tmp/open/baz points to /tmp/open/fie read(dh2): blorf read(dh2): blorfldyick read(dh1): /tmp/open/bar

    Side note which might resolve this XY Problem (if so): -d on a symlink returns true up to v5.25.10, so -d resolves symlinks, which it shouldn't do. IMHO this is a bug.

    Apropos race condition: I can't think of anything which would resolve that, other than a system call like openif() into which the expected type is passed as an argument.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      -d following symlinks is not a bug because it calls stat() which follows symlinks as required by POSIX. You have to use lstat() (or -l) if you don't want that.
Re^3: readdir() on a sysopen() handle?
by Laurent_R (Canon) on Aug 20, 2017 at 17:32 UTC
    The problem is that an entry might change from a directory to a symbolic link between the stat() and the open(). O_NOFOLLOW prevents such race conditions.
    I fail to see why or how O_NOFOLLOW would prevent this from happening if you were thinking about doing a sysopen followed by a readdir or anything more or less equivalent with a different system call.

    Maybe you should explain more precisely what you're really trying to do.

      I can't speak for the OP, but—

      Problems such as this often arise in scenarios where the effective user has more privileges than necessary for the intended operation. Then the program must either juggle with privileges/capabilities, or otherwise take precaution.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1197694]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2024-04-23 23:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found