4

I want to cheat a program to use a special /etc/resolv.conf file, that in turn will force it to use a nonstandard nameserver.

The obvious solution is to recreate the whole filesystem except one file and use a chroot. But may be there is a simpler hack for doing this.

how to change a file's content for a specific process only? gives solutions that work in many cases, but not for /etc/resolv.conf: LD_PRELOAD doesn't catch when the resolver inside libc opens /etc/resolv.conf, and a bind mount doesn't work to override a symbolic link (if the link target is missing or when the link is changed afterwards).

EDIT: A relevant question is How do I mount a file on top of a broken symbolic link? and there is no universal solution found

ZAB
  • 201
  • 1
    Yes. You can run it in a different mount namespace. – ctrl-alt-delor Jul 21 '19 at 17:34
  • @ctrl-alt-delor how to overwrite a single file afterwards? If I just run mount --bind newresolv /tmp/mnt/etc/resolv.conf it will follow the link path or, in my case where the link path is nonexistent, it fails with an error mount point is a symbolic link to nowhere – ZAB Jul 21 '19 at 19:03
  • 1
    One way is with unshare, see duplicate. There is probably a way to do it without root privileges (maybe fuse). – ctrl-alt-delor Jul 21 '19 at 22:24
  • 1
    @gilles I don't think that either answer to the purported dupe applies. Overriding fopen() with a LD_PRELOAD hack will not work when /etc/resolv.conf is opened by the resolver (ie via getaddrinfo()), and the way to reliably use unshare + bind mount with a "dynamic" symlink like /etc/resolv.conf needs to be explained more (at least for me, it's not at all obvious how that could be done; assuming that this Q is linux-only, despite no [linux] tag). –  Jul 22 '19 at 03:11
  • @mosvy You're right, this is a special case where the usual methods don't necessarily work. I've edited and reopened the question. – Gilles 'SO- stop being evil' Jul 23 '19 at 18:33

2 Answers2

0

You can use bubblewrap to create a mount namespace. It is included in most distributions, since flatpak needs it.

bwrap \
    --bind / / \
    --bind /home/user/resolv.conf /etc/resolv.conf \
    binary parameter1 parameter2d

AdminBee
  • 22,803
Alai
  • 1
  • It looks a little bit like bubblewrap and overlayfs are superficially similar.  Can you briefly discuss the similarities and/or differences?  Why would a user choose bubblewrap over overlayfs? – G-Man Says 'Reinstate Monica' Apr 04 '22 at 10:26
  • @G-ManSays'ReinstateMonica' bubblewrap in OP's case will mount over /run/NetworkManager/resolv.conf (or /run/systemd...) rather than /etc/resolv.conf (which is still a symlink). – A.B Apr 04 '22 at 10:28
0

One can use overlayfs to avoid duplication. If it's temporary, everything can be done using /tmp. Combined with a mount namespace, this can then be made to affect a single application. To be prepared from root (it does work with an user+mount namespace where a normal user is mapped as root, but without privileged assistance and/or recent kernel for pid translation, user mappings wouldn't help to do something useful).

  • create a new mount namespace
  • create an overlayfs in this mount namespace
  • bind mount this overlayfs back over /etc
  • change contents (eg delete the /etc/resolv.conf symlink then create the regular file /etc/resolv.conf with custom content)
  • run application, still from this mount namespace

Example:

mkdir /tmp/upper /tmp/work /tmp/fake_etc
unshare -m

next commands are run in the new mount namespace:

mount -t overlay -olowerdir=/etc,upperdir=/tmp/upper,workdir=/tmp/work overlay_etc /tmp/fake_etc

then just cover /etc with the one used to fake its contents:

mount --bind /tmp/fake_etc /etc

and do changes (affecting only the overlayfs in the mount namespace):

rm /etc/resolv.conf
echo nameserver 192.0.2.2 > /etc/resolv.conf

AFAIK can't mount a mount namespace to keep a reference. If needed one can use instead a PID reference from the mount namespace:

# echo $$
325304

Either in the same shell or in a separate (root) shell by running this:

nsenter -t 325304 --mount

then following the previous example (with a nameserver 192.0.2.2 that isn't reachable):

# su - -c 'ping stackexchange.com' someuser 
ping: stackexchange.com: Name or service not known

While anywhere else ping will work as usual.

A.B
  • 36,364
  • 2
  • 73
  • 118