0

I am using a GNU/Linux system.

Firstly, I have:

  • Moved to the /tmp/ directory.

  • Created a file called ruby.rb as a non-root user.

  • Opened irb as su user.

Now in IRB:

┌┄┄[root::archlinux]┈[/tmp]
└──╼⮚ irb
irb(main):001:0> File.writable?('ruby.rb')
=> true
irb(main):002:0> File.stat('ruby.rb')
=> #<File::Stat dev=0x2d, ino=819138, mode=0100644, nlink=1, uid=1000, gid=1000, rdev=0x0, size=0, blksize=4096, blocks=0, atime=2019-07-14 04:44:13 +0530, mtime=2019-07-14 04:44:13 +0530, ctime=2019-07-14 04:44:13 +0530>
irb(main):003:0> File.write('ruby.rb', '#!/usr/bin/ruby -w')
Traceback (most recent call last):
        3: from /root/.irb:351:in `<main>'
        2: from (irb):3
        1: from (irb):3:in `write'
Errno::EACCES (Permission denied @ rb_sysopen - ruby.rb)
irb(main):004:0> 

Apart from this, actually I am trying to do is writing a log file. I am checking if the file is writable. If not, it sends notification to the user.

I have faced the problem previously where File#writable?(str) returned true in such case (and it works on the /tmp/ directory). And just used a begin <...> rescue Errno::EACCES block to fix the problem. But in the current project, I don't want to use a rescue block.

Why does the File#writable?(str) return true in the first place?

EDIT: First of all this should be moved to unix.stackexchange.

Secondly I understood

  • You can't modify a file on a tmp filesystem: I have mounted a mere 4 MiB partition as tmpfs on /mnt. Created a file as local user. Then changed the permission to omnipotent 777! Then I changed my account to root. I tried to edit the contents with nano. It's not possible.

  • Ruby's File#writable? probably doesn't detect the mounted filesystem type. Whether it's XFS or EXT4 or procfs or tmpfs. If all it does is checking the mode, in such scenario, the File#writable? returns true while in reality, it's not actually writable!

Edit 2: I have uploaded 2 screenshots at imgur:

Screenshot 1

Screenshot 2

questionasker
  • 2,536
  • 12
  • 55
  • 119
15 Volts
  • 1,946
  • 15
  • 37
  • 2
    Why not use https://ruby-doc.org/stdlib-2.4.0/libdoc/tempfile/rdoc/Tempfile.html ? – anothermh Jul 14 '19 at 00:04
  • This question should be on-topic at Stack Overflow. The problem with it is, it is missing a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). `File#writable?(str)` is not enough information to assist you. – jww Jul 14 '19 at 00:13
  • On many systems `/tmp` is not a regular filesystem so you may not be able to use that directly. – tadman Jul 14 '19 at 00:53
  • `/tmp` is writeable on the popular Linux distributions. you can run `strace -o $HOME/trace irb` and repeat the session, The output in `$HOME/trace irb` will tell you what `irb` is asking the OS to do and what the OS replies. There could be ACL issues, or the filesystem could be mounted read-only. I suppose a "proper" way to implement `File#writable` is via the `access`(2) OS call - `strace`(1) should tell you if it does. – root Jul 14 '19 at 01:18
  • @root - Not always true. The majority of machines at the [GCC Compile Farm](https://gcc.gnu.org/wiki/CompileFarm) are Linux, but they do not have user writeable `/tmp`. If you have an account on the farm your need to `export TMPDIR="$HOME/tmp"` if you plan on using a temp directory. – jww Jul 14 '19 at 04:27
  • I am unable to reproduce this. This is what I tried (as non-root): `sudo mount -t tmpfs none /mnt`, `echo foo > /mnt/myfile`, `chmod 777 /mnt/myfile`, `sudo bash -c 'echo more >> /mnt/myfile'`. According to your post I should get an error, but instead it exits with success and `cat /mnt/myfile` shows "foo more" as expected – that other guy Jul 14 '19 at 05:47
  • @root, /tmp is writable. But you wrote a file called `a` as user x, as far as I saw, you can't write the file as user `y` even with 666 permissions... It's weird. My script needs root privilege in order to do some task. But well, I might at least check if the file exists already and if that is owned by root or not in Ruby... – 15 Volts Jul 14 '19 at 06:12
  • Well, actually I have 2 other computers. This behaviour is seen on my laptop running arch x86_64. Just to make sure, I tried my raspberry pi running Arch Linux ARM. Steps: (1) Go to /tmp. (2) `touch file` (3) `chmod 777 file`. (4) `su` (5) `nano file` And the same behaviour is seen on the Pi. If you see the permissions, it's 777 and anybody can read, write, and execute it. But if the file is on /tmp/ other users (even root) can't write to it. I am running Kernel `5.2.0-arch2-1-ARCH` on laptop, and `4.19.57-1-ARCH` on the Raspberry Pi 3 model B. – 15 Volts Jul 14 '19 at 06:21
  • @thatotherguy, yes, it's weird. If you type `echo > file` yes it works. But nano, vi TUI editors and Geany, Mousepad, atom GUI editors can't write to it. Once you do `echo > file` as root, you can't write it as regular user on those editors. Yes, ruby also fails to write the file. Only redirection works! – 15 Volts Jul 14 '19 at 06:28
  • Hi, I have uploaded 2 screenshots at imgur: https://imgur.com/tB4T5Jl https://imgur.com/hzc5s27 – 15 Volts Jul 14 '19 at 09:28
  • (1) what distro are you using on your laptop? (2) what's the output of `test -w /tmp/ruby.rb; echo $?`? (3) what's the output of `su -c 'test -w /tmp/ruby.rb; echo $?'`? (4) what's the output of `mount | grep /tmp`? (5) what's the output of `getfacl /tmp/ruby.rb`? (6) what's the output of `ls -ld /tmp`? – root Jul 14 '19 at 10:02
  • I can reproduce this on ArchLinux but not on any other distro. – that other guy Jul 14 '19 at 18:58
  • Same. I have 3 systems running Arch Linux. So I thought this can be reproduced on an system. Actually then I told my friend (who uses Ubuntu) to do it. He told that everything goes as expected. Then I fired up my Linux Mint virtual machine, and my question was no more applicable. Pardon me. I didn't know that this could be only for Arch Linux. I don't know why. Let me post this on Arch Linux forum! Let's not worry about downvotes ;) ... Learnt something new as always ;) – 15 Volts Jul 14 '19 at 19:00
  • Ok, here's something I found: https://bbs.archlinux.org/viewtopic.php?id=244482 – 15 Volts Jul 14 '19 at 19:16

2 Answers2

1

Okay this is not a Ruby specific problem. That said, any programming language will have such problem because it's all about the file system protection implemented in systemd.

The option fs.protected_regular is implemented in Linux Kernel 4.19+ to make data spoofing attacks harder.

So, firstly you need to check:

sysctl fs.protected_regular

In your case, it should print 1

So, change the value to 0:

sysctl fs.protected_regular=0

Hopefully the problem will get solved. Or try this:

sysctl fs.protected_regular=0
sysctl fs.protected_fifos=0

Note that the option is enabled by default. You may not prefer telling every user of your program to set the above to 0! They may not even prefer that!

So, in Ruby:

  1. You can delete the file:
File.delete('file') if File.exist?('file')
# Better use the '/tmp/file' or File.join(%w(/ tmp file)) otherwise the file will get delete from the Dir.pwd

Which will delete the file every time the script runs.

  1. You can also use begin ... rescue block and use Warning.warn or Kernel.warn or STDERR.puts to print a warning message.
15 Volts
  • 1,946
  • 15
  • 37
-1

Could be one of 2 things, file is not being opened for writing, or permissions issue with user.

Try to open the file for writing with either 'w' or 'w+'

File.open('ruby.rb', 'w') { |file| file.write("#!/usr/bin/ruby -w") }

If that doesn't work, try using chmod to update file permissions for ruby.rb with

chmod -R 777 <path_to_file>
nishant217
  • 19
  • 4
  • Nope, `File.open...` doesn't work. Well yes, I can require `fileutils` and add `FileUtils.chmod(0777, 'ruby.rb')` and still have the same problem. I also considered doing `0666` at first. You know the permission was set to `0644` at first which means it was writable! Anyways, doesn't work in any case! I have faced this issue only on the `/tmp/` directory... – 15 Volts Jul 13 '19 at 23:37