This answer works on Debian (tested on lenny and squeeze). After investigation, it seems to work only thanks to a Debian patch; users of other distributions such as Ubuntu may be out of luck.
You can use mount --bind
. Mount the “real” filesystem under a directory that's not publicly accessible. Make a read-only bind mount that's more widely accessible. Make a read-write bind mount for the part you want to expose with read-write access.
mkdir /media/hidden /media/hidden/sdz99
chmod 700 /media/hidden
mount /dev/sdz99 /media/hidden/sdz99
mount -o bind,ro /media/hidden/sdz99/world-readable /media/world-readable
mount -o bind /media/hidden/sdz99/world-writable /media/world-writable
In your use case, I think you can do:
mkdir /var/smb/hidden
mv /var/smb/snapshot /var/smb/hidden
mkdir /var/smb/snapshot
chmod 700 /var/smb/hidden
chmod 755 /var/smb/hidden/snapshot
mount -o bind,ro /var/smb/hidden/snapshot /var/smb/hidden/snapshot
I.e. put the real snapshot
directory under a restricted directory, but give snapshot
read permissions for everyone. It won't be directly accessible because its parent has restricted access. Bind-mount it read-only in an accessible location, so that everyone can read it through that path.
(Read-only bind mounts only became possible several years after bind mounts were introduced, so you might remember a time when they didn't work. I don't know offhand since when they work, but they already worked in Debian lenny (i.e. now oldstable).)
This is actually common and quite straightforward. sudo
allows you to limit specific applications that a user can invoke. In other words, you don't have to give them all root or nothing; you can give them sudo
permissions to run a specific command. This is exactly what you want, and is very common practice for things like allowing users to push Git repositories via SSH and the like.
To do this, all you have to do is add a line to /etc/sudoers
that looks something like
bob ALL=(root) NOPASSWD: /path/to/command/you/trust
(The NOPASSWD:
part is not required, but is very common in this situation.) At that point, bob
can invoke /path/to/command/you/trust
via sudo, but nothing else.
That said, giving someone root—what we're doing here—may not be quite what you want. Notably, if there were any flaw in your script whatsoever, you risk letting your box get rooted. For that reason, you may instead prefer to create a user specifically to own the special file—say, specialuser
—then chown
the file to them, and have the /etc/sudoers
make bob
be that special user. In that case, the line you add to sudoers
would simply be
bob ALL=(specialuser) NOPASSWD: /path/to/command/you/trust
Best Answer
Put it on a CD or a DVD. The once-writable kind, not the erasable ones. Or some other kind of a read-only device.
Ok, I suppose you want a software solution, so here are some ideas: You could possibly create an SELinux ruleset that disables the syscall (*) that
chattr
uses, even for root. Another possibility would be to use capabilities: setting+i
requires theCAP_LINUX_IMMUTABLE
capability, so if you can arrange the capability bounding set of all processes to not include that, then no-one can change those flags. But you'd need support frominit
to have that apply to all processes. Systemd can do that, but I think it would need to be done for each service separately.(* maybe it was an
ioctl
instead.)However, if you do that, remember that a usual root can modify the filesystem from the raw device (that's what
debugfs
is for), so you'd need to prevent that, too, as well as prevent modifying the kernel (loading modules). Loading modules can be prevented with thekernel.modules_disabled
sysctl, but I'm not sure about preventing access to raw devices. And make all the relevant configuration files also immutable.Anyway, after that, you'd also need to prevent changing the way the system boots, otherwise someone could reboot the system with a kernel that allows overriding the above restrictions.