EzDevInfo.com

chroot interview questions

Top chroot frequently asked interview questions

How to run a command in a chroot jail not as root and without sudo?

I'm setting up a minimal chroot and want to avoid having sudo or su in it but still run my processes as non-root. This is a bit of a trick as running chroot requiers root. I could write a program that does this that would look something like:

uid = LookupUser(args[username])  // no /etc/passwd in jail
chroot(args[newroot])
cd("/")
setuids(uid)
execve(args[exe:])

Is that my best bet or is there a standard tool that does that for me?


I rolled my own here:


Source: (StackOverflow)

How does chroot affect dynamic libraries memory use?

Although there is another question with similar topic, it does not cover the memory use by the shared libraries in chrooted jails.

Let's say we have a few similar chroots. To be more specific, exactly the same sets of binary files and shared libraries which are actually hard links to the master copies to conserve the disk space (to prevent the potential possibility of a files alteration the file system is mounted read only).

How is the memory use affected in such a setup?


Source: (StackOverflow)

Advertisements

How can I get DNS resolution to work inside a Mac OS X `chroot` on El Capitan?

I'm trying to create a chroot to run a program that needs internet access to build myself a sandboxed, immutable developer environment. So far my jail is working well: I can run bash inside it and run simple programs from there! DNS resolution doesn't work however:

bash-3.2$ curl google.ca
curl: (6) Could not resolve host: google.ca

I am almost positive this is because the inner process is unable to connect to the mDNSResponder daemon running outside the jail. Outside the jail there is an mDNSResponder socket for the whole system to use:

host ➜  ls -lA /var/run/mDNSResponder
srw-rw-rw-  1 root  daemon  0 22 Oct 10:41 /var/run/mDNSResponder

But, inside the jail there is not. So, I tried to use socat to create a unix socket "proxy" from inside the jail to outside it: I run socat (command below) to create a socket inside my jail, and then inside the jail run curl again, but curl still gives the same error message. I see this in syslog after turning on the verbose logging of mDNSResponder with SIGUSR1:

2015-10-26 5:32:30.835 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:30.835 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23271](socat)
2015-10-26 5:32:30.836 PM mDNSResponder[95]:  12: read_msg: ERROR failed to get errsd via SCM_RIGHTS
2015-10-26 5:32:30.836 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23271](socat)
2015-10-26 5:32:30.836 PM mDNSResponder[95]:  12: Removing FD
2015-10-26 5:32:31.339 PM curl[23269]: dnssd_clientstub read_all(5) failed 0/4 0 
2015-10-26 5:32:31.339 PM curl[23269]: dnssd_clientstub write_all(4) failed -1/28 32 Broken pipe
2015-10-26 5:32:31.341 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:31.341 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23272](socat)
2015-10-26 5:32:31.342 PM mDNSResponder[95]:  12: read_msg: ERROR failed to get errsd via SCM_RIGHTS
2015-10-26 5:32:31.342 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23272](socat)
2015-10-26 5:32:31.342 PM mDNSResponder[95]:  12: Removing FD
2015-10-26 5:32:31.844 PM curl[23269]: dnssd_clientstub read_all(5) failed 0/4 0 
2015-10-26 5:32:31.846 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:31.846 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23274](socat)
2015-10-26 5:32:31.847 PM mDNSResponder[95]:  12: read_msg: ERROR failed to get errsd via SCM_RIGHTS
2015-10-26 5:32:31.847 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23274](socat)
2015-10-26 5:32:31.847 PM mDNSResponder[95]:  12: Removing FD
2015-10-26 5:32:32.349 PM curl[23269]: dnssd_clientstub read_all(5) failed 0/4 0 
2015-10-26 5:32:32.350 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 0
2015-10-26 5:32:32.351 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23275](socat)
2015-10-26 5:32:33.361 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23275](socat)
2015-10-26 5:32:33.361 PM mDNSResponder[95]:  12: Removing FD

which looks to me like curl via dnssd_clientstub is trying three times to resolve the name. Here's the socat log while the jailed process was trying to connect:

host ~/C/jail (master*) ➜
sudo socat -v -d -d UNIX-LISTEN:/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder,mode=666,fork,user=root,group=daemon UNIX-CLIENT:/private/var/run/mDNSResponder
Password:
2015/10/26 18:16:03 socat[24334] N listening on LEN=67 AF=1 "/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24334] N accepting connection from LEN=16 AF=1 "" on LEN=67 AF=1 "/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24334] N forked off child process 24341
2015/10/26 18:16:07 socat[24334] N listening on LEN=67 AF=1 "/Users/hornairs/Code/jail/jail-test/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24341] N opening connection to LEN=32 AF=1 "/private/var/run/mDNSResponder"
2015/10/26 18:16:07 socat[24341] N successfully connected from local address LEN=16 AF=1 ""
2015/10/26 18:16:07 socat[24341] N starting data transfer loop with FDs [6,6] and [5,5]
> 2015/10/26 18:16:07.081847  length=28 from=0 to=27
............................< 2015/10/26 18:16:07.082019  length=4 from=0 to=3
....> 2015/10/26 18:16:07.082167  length=50 from=28 to=77
...............\b...............P.....google.ca....> 2015/10/26 18:16:07.082287  length=1 from=78 to=78
.2015/10/26 18:16:07 socat[24341] N socket 2 (fd 5) is at EOF
2015/10/26 18:16:07 socat[24341] N exiting with status 0
2015/10/26 18:16:07 socat[24334] N childdied(): handling signal 20

For comparison, here's what a successful lookup looks like when I run it from the host:

2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: connect_callback: Adding FD for uid 501
2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: DNSServiceCreateConnection START PID[23190](curl)
2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: Result code socket 27 created 00000000 00000001
2015-10-26 5:31:56.524 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(15000, 0, google.ca., Addr) START PID[23190]()
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: Result code socket 27 closed  00000000 00000001 (0)
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) ADD    4 google.ca. Addr 74.216.233.251
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) ADD    4 google.ca. Addr 74.216.233.249
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) ADD    4 google.ca. Addr 74.216.233.227
*snip*
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: Result code socket 27 created 00000000 00000002
2015-10-26 5:31:56.525 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(15000, 0, google.ca., AAAA) START PID[23190]()
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: Result code socket 27 closed  00000000 00000002 (0)
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., AAAA) ADD   16 google.ca. AAAA 2607:F8B0:400B:080A:0000:0000:0000:100F
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: Cancel 00000000 00000001
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., Addr) STOP PID[23190]()
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: Cancel 00000000 00000002
2015-10-26 5:31:56.526 PM mDNSResponder[95]:  12: DNSServiceQueryRecord(google.ca., AAAA) STOP PID[23190]()
2015-10-26 5:31:56.587 PM mDNSResponder[95]:  12: DNSServiceCreateConnection STOP PID[23190](curl)
2015-10-26 5:31:56.587 PM mDNSResponder[95]:  12: Removing FD

The major differences I notice between the failure and the success are that the uid is 0 for the request inside the jail and 501 for the request outside it. Curious, but that doesn't seem to be where the request actually fails.

The error message that comes from mDNSResponder seems to be concerning getting the errsd from the incoming request across the socket. https://github.com/jevinskie/mDNSResponder/blob/2942dde61f920fbbf96ff9a3840567ebbe7cb1b6/mDNSShared/uds_daemon.c#L3660

At this point it seems to me like mDNSResponder expects its clients to pass it a pair of fd's across the socket to respond to the client with, which I am not sure is even possible to do from inside the chroot. I am a very poor C programmer so I could be wrong about that, but if that is the truth, is it even possible to do this, and is there a better path to getting DNS to work inside the chroot?

Other tidbits:

  • You can configure mDNSResponder to listen on more than one socket in it's launchd plist file, but that file is now protected by System Integrity Protection, which I don't want to disable to get this to work. It's janky, and easy to fall out of sync with the jail filesystems I am often changing on the hosts, which breaks DNS for every process if it can't create one of the sockets because the file doesn't exist. Running a proxy seems much more resilient

  • ping dies instantly in the jail, which is why I am using curl. It gets a Killed: 9 message on the console instantly.

  • I am getting some other files into the chroot using a bind mount, but I can't get that to work for the mDNSResponder socket. I use http://bindfs.org (since OS X doesn't support Linux' mount --bind) to mount in /var/run to the chroot, but this comes up in the logs when trying to connect:

    2015-10-26 6:39:40.833 PM curl[25002]: dnssd_clientstub ConnectToServer: connect()-> No of tries: 1
    2015-10-26 6:39:41.837 PM curl[25002]: dnssd_clientstub ConnectToServer: connect()-> No of tries: 2
    2015-10-26 6:39:42.843 PM curl[25002]: dnssd_clientstub ConnectToServer: connect()-> No of tries: 3
    2015-10-26 6:39:43.848 PM curl[25002]: dnssd_clientstub ConnectToServer: connect() failed path:/var/run/mDNSResponder Socket:4 Err:-1 Errno:61 Connection refused
    

Source: (StackOverflow)

does chroot() require root privileges?

Everything is in the question. When I try to use chroot with "." or the complete pathname as argument, perror tells me "Operation not permitted". If the answer to my question is yes, is there another way to change root directory ? (Without barbarian methods using strcmp() / strncmp())

Thanks !


Source: (StackOverflow)

Detecting a chroot jail from within

How can one detect being in a chroot jail without root privileges? Assume a standard BSD or Linux system. The best I came up with was to look at the inode value for "/" and to consider whether it is reasonably low, but I would like a more accurate method for detection.

[edit 20080916 142430 EST] Simply looking around the filesystem isn't sufficient, as it's not difficult to duplicate things like /boot and /dev to fool the jailed user.

[edit 20080916 142950 EST] For Linux systems, checking for unexpected values within /proc is reasonable, but what about systems that don't support /proc in the first place?


Source: (StackOverflow)

Detect program launch in another thread on linux [closed]

I am trying to sandbox ELF binaries by (among other things) chrooting them after they have been launched. To do so, a child process cloned with the CLONE_FS tag performs a chroot, while the parent runs the binary by calling an exec function.

The trick actually works if the chroot happens after the program has finished loading the shared libraries it needs. The problem is that I can't find a way to detect when this actually happens from the other process. Is there any way?


Source: (StackOverflow)

Public key authorization on sftp chroot directory

I want to add public key authorization to my sftp chroot directory but I allways get:

debug1: Next authentication method: publickey
debug1: Offering RSA public key: /home/test/.ssh/id_rsa
debug3: send_pubkey_test
debug2: we sent a publickey packet, wait for reply
debug1: Authentications that can continue: publickey
debug2: we did not send a packet, disable method
debug1: No more authentication methods to try.
Permission denied (publickey).
Couldn't read packet: Connection reset by peer

Chroot works because authorization with password is possible. I have other account on this host without chroot and it works with this key. I tried many times, but still it doesn't work.

On server in auth.log there is only: Connection closed by xxx [preauth]

This is my directory:

ls -laR /sftp/
/sftp/:
total 12
drwxr-xr-x  3 root root 4096 May  3 16:55 .
drwxr-xr-x 23 root root 4096 May  3 14:46 ..
drwxr-xr-x  3 root root 4096 May  3 16:45 backup

/sftp/backup:
total 12
drwxr-xr-x 3 root     root      4096 May  3 16:45 .
drwxr-xr-x 3 root     root      4096 May  3 16:55 ..
drwxr-xr-x 3 backup sftpusers 4096 May  3 16:55 incoming

/sftp/backup/incoming:
total 12
drwxr-xr-x 3 backup sftpusers 4096 May  3 16:55 .
drwxr-xr-x 3 root     root      4096 May  3 16:45 ..
drwx------ 2 backup sftpusers 4096 May  3 21:06 .ssh

/sftp/backup/incoming/.ssh:
total 12
drwx------ 2 backup sftpusers 4096 May  3 21:06 .
drwxr-xr-x 3 backup sftpusers 4096 May  3 16:55 ..
-rw------- 1 backup sftpusers  391 May  3 21:06 authorized_keys

My user:

backup:x:1002:1003::/incoming:/usr/sbin/nologin

My ssh config:

Match Group sftpusers
  ChrootDirectory /sftp/%u
  AuthorizedKeysFile  /sftp/backup/incoming/.ssh/authorized_keys
  ForceCommand internal-sftp
  AllowTcpForwarding no
  X11Forwarding no

Please help.


Source: (StackOverflow)

Why use Pythons 'virtualenv' on Linux when one has 'chroot' (and union/overlay filesystems)?

First of all let me state that I am a proponent of generic software (in general ;-). I am no expert on Python, but it seems that the 'virtualenv' utility solves pretty much the same problem 'chroot' can help to solve - bootstrapping a directory tree that can be passed as root, thus effectively protecting the real directory tree, if needed.

Since I am no expert in Python as already mentioned, I wonder - what problem can virtualenv solve that chroot cannot? I mean, can't I just set up a nice fake root tree (possibly using union mounting), chroot into it, and do pip install a package I want in my new environment, and then play around within the bounds of my new environment, running python scripts and what not?

Am I missing something here?

Update:

Can't one install packages/modules locally in whatever application directory, I mean, without root privileges and subsequently without overwriting or adding files to /usr/lib or /usr/local/lib? It appears that this is what virtualenv does, however I think it has to symlink or otherwise provide a python interpreter for each environment one creates, does it not?


Source: (StackOverflow)

How to exit a chroot inside a perl script?

While writing a perl script intended to fully automate the setup of virtual machines (Xen pv) I hit a small maybe very simple problem.

Using perl's chroot function I do my things on the guest file system and then I need to get back to my initial real root. How the hell I do that?

Script example:

`mount $disk_image $mount_point`;

chdir($mount_point);
chroot($mount_point);

#[Do my things...]

#<Exit chroot wanted here>

`umount $mount_point`;

#[Post install things...]

I've tried exit; but obviously that exit the whole script.

Searching for a way to exit the chroot I've found a number of scripts who aim to exit an already setup chroot (privilege escalation). Since I do the chroot here theses methods do not aplies.

Tried some crazy things like:

opendir REAL_ROOT, "/";
chdir($mount_point);
chroot($mount_point);
chdir(*REAL_ROOT);

But no go.

UPDATE Some points to consider:

  • I can't split the script in multiple files. (Silly reasons, but really, I can't)
  • The chrooted part involve using a lot of data gathered earlier by the script (before the chroot), enforcing the need of not lunching another script inside the chroot.
  • Using open, system or backticks is not good, I need to run commands and based on the output (not the exit code, the actual output) do other things.
  • Steps after the chroot depends on what was done inside the chroot, hence I need to have all the variables I defined or changed while inside, outside.
  • Fork is possible, but I don't know a good way to handle correctly the passing of informations from and to the child.

Source: (StackOverflow)

What is needed to run a Haskell program in a jailed environment

I want to run a simple Haskell program from a jailed environment that I construct myself. The following Haskell program I want to run:

import System.IO

main = do
    hPutStrLn stderr "test standard error!"
    hPutStrLn stdout "test standard out!"

It just outputs a string to stderr and stdout, works perfectly fine outside of the jail. The code is compiled as follows:

ghc -O2 --make -static -optc-static -optl-static $MAINHS -optl-pthread -o bin/run_ai

I get a run_ai executable that runs the program, as I said, this works fine outside of the jail. Below is the stuff that's put inside of the jailed environment and I think there's something missing here, because when I run the program in the jail it does absolutely nothing, it doesn't even exit and no error/output dumps are given at all.

mkdir -p lib64 lib bin

cp /bin/sh bin/

# Binaries
cp /lib64/ld-linux-x86-64.so.2 lib64/

cp /lib/x86_64-linux-gnu/libpthread.so.0 lib/
cp /lib/x86_64-linux-gnu/libc.so.6 lib/
cp /lib/x86_64-linux-gnu/libdl.so.2 lib/
cp /lib/x86_64-linux-gnu/librt.so.1 lib/
cp /lib/x86_64-linux-gnu/libm.so.6 lib/
cp /lib/x86_64-linux-gnu/libtinfo.so.5 lib/
cp /lib/x86_64-linux-gnu/libutil.so.1 lib/
cp /usr/lib/x86_64-linux-gnu/libffi.so.6 lib/
cp /usr/lib/x86_64-linux-gnu/libgmp.so.10 lib/
cp /usr/lib/libgmp.so.3 lib/

I know the jail itself works great, because I've successfully used it for a dozen other programming languages, but Haskell is giving me a headache because I get absolutely nothing on what might be going wrong. Sadly, I'm not an expert on Haskell, but I just need it to compile, and run inside of the jail. Am I missing something that is actually needed to run the executable Haskell file?

So my question is: What am I missing/doing wrong?


Source: (StackOverflow)

Running mysql in chroot

I've got a chroot environment working on my 10.04 ubuntu box. I'm trying to run mysql inside this chroot environment, but I get this error.

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

Basically I used debootstrap along with schroot to create the chroot. Then I installed "ubuntu-minimal" and mysql-server inside this chroot environment. If you are interested here are all the steps that I followed https://help.ubuntu.com/community/DebootstrapChroot . But mysql does not work inside the chroot. /var/log/mysql.log and /var/log/mysql.err files are empty and mysqld server is running. Any pointers?


Source: (StackOverflow)

How to build to chroot using Eclipse CDT?

I've got a chroot environment with everything needed for building a complex C++ project, using make (it's for a specific Linux distribution).

I would like to use Eclipse CDT (outside the chroot environment) in this project but make it so that Eclipse, when building, goes into the chroot enviroment and builds in there.

Is it possible?


Source: (StackOverflow)

C : system() call inside chroot

I have a program written in C, which runs chrooted, inside a jail, that makes some system calls e.g system ( "ls" ). The problem is that the program does not execute the system calls when I run it inside the jail. I have included all the necessary libraries of the executable ( found them with ldd bash command ), along with the bash executable ( /bin/bash ), and it's libraries ( also found with ldd ). It seems that something is missing. Does anyone have an idea about that?


Source: (StackOverflow)

How to (legitimately) access files after putting self into chrooted sandbox?

Changing a Linux C++ program which gives the user limited file access. Thus the program chroots itself to a sandbox with the files the user can get at. All worked well.

Now, however, the program needs to access some files for its own needs (not the user's) but they are outside the sandbox. I know chroot allows access to files opened before the chroot but in this case the needed files could a few among many hundreds so it is obviously impractical to open them all just for the couple that might be required.

Is there any way to get at the files?


Source: (StackOverflow)

Override libc functions called from another libc function with LD_PRELOAD

I've a project aiming to run php-cgi chrooted for mass virtual hosting (more than 10k virtual host), with each virtual host having their own chroot, under Ubuntu Lucid x86_64.

I would like to avoid creating the necessary environment inside each chroot for things like /dev/null, /dev/zero, locales, icons... and whatever which could be needed by php modules thinking that they run outside chroot.

The goal is to make php-cgi run inside a chroot, but allowing him access to files outside the chroot as long as those files are (for most of them) opened in read-only mode, and on an allowed list (/dev/log, /dev/zero, /dev/null, path to the locales...)

The obvious way seems to create (or use if it exists) a kernel module, which could hook and redirect trusted open() paths, outside of the chroot. But I don't think it's the easiest way:

  • I've never done a kernel module, so I do not correctly estimate the difficulty.
  • There seems to be multiple syscall to hook file "open" (open, connect, mmap...), but I guess there is a common kernel function for everything related to file opening.

I do want to minimize the number of patchs to php or it's module, to minimize the amount of work needed each time I will update our platform to the latest stable PHP release (and so update from upstream PHP releases more often and quickly), so I find better to patch the behavior of PHP from the outside (because we have a particular setup, so patching PHP and propose patch to upstream is not relevant).

Instead, I'm currently trying an userland solution : hook libc functions with LD_PRELOAD, which works well in most cases and is really quick to implement, but I've encountered a problem which I'm unable to resolve alone. (The idea is to talk to a daemon running outside the chroot, and get file descriptor from it using ioctl SENDFD and RECVFD).

When I call syslog() (without openlog() first), syslog() calls connect() to open a file.

Example:

folays@phenix:~/ldpreload$ strace logger test 2>&1 | grep connect
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(1, {sa_family=AF_FILE, path="/dev/log"}, 110) = 0

So far so good, I've tried to hook the connect() function of libc, without success. I've also tried to put some flags to dlopen() inside the _init() function of my preload library to test if some of them could make this work, without success

Here is the relevant code of my preload library:

void __attribute__((constructor)) my_init(void)
{
  printf("INIT preloadz %s\n", __progname);
  dlopen(getenv("LD_PRELOAD"), RTLD_NOLOAD | RTLD_DEEPBIND | RTLD_GLOBAL |
                               RTLD_NOW);
}

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
  printf("HOOKED connect\n");
  int (*f)() = dlsym(RTLD_NEXT, "connect");
  int ret = f(sockfd, addr, addrlen);
  return ret;
}

int __connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
  printf("HOOKED __connect\n");
  int (*f)() = dlsym(RTLD_NEXT, "connect");
  int ret = f(sockfd, addr, addrlen);
  return ret;
}

But the connect() function of the libc still takes precedence over mine:

folays@phenix:~/ldpreload$ LD_PRELOAD=./lib-preload.so logger test
INIT preloadz logger
[...] no lines with "HOOKED connect..." [...]
folays@phenix:~/ldpreload$

Looking at the code of syslog() (apt-get source libc6 , glibc-2.13/misc/syslog.c), it seems to call openlog_internal, which in turn call __connect(), at misc/syslog.c line 386:

            if (LogFile != -1 && !connected)
            {
                    int old_errno = errno;
                    if (__connect(LogFile, &SyslogAddr, sizeof(SyslogAddr))
                        == -1)
                    {

Well, objdump shows me connect and __connect in the dynamic symbol table of libc:

folays@phenix:~/ldpreload$ objdump -T /lib/x86_64-linux-gnu/libc.so.6 |grep -i connec
00000000000e6d00  w   DF .text  000000000000005e  GLIBC_2.2.5 connect
00000000000e6d00  w   DF .text  000000000000005e  GLIBC_2.2.5 __connect

But no connect symbol in the dynamic relocation entries, so I guess that it explains why I cannot successfully override the connect() used by openlog_internal(), it probably does not use dynamic symbol relocation, and probably has the address of the __connect() function in hard (a relative -fPIC offset?).

folays@phenix:~/ldpreload$ objdump -R /lib/x86_64-linux-gnu/libc.so.6 |grep -i connec
folays@phenix:~/ldpreload$ 

connect is a weak alias to __connect:

 eglibc-2.13/socket/connect.c:weak_alias (__connect, connect)

gdb is still able to breakpoint on the libc connect symbol of the libc:

folays@phenix:~/ldpreload$ gdb logger
(gdb) b connect
Breakpoint 1 at 0x400dc8
(gdb) r test
Starting program: /usr/bin/logger 

Breakpoint 1, connect () at ../sysdeps/unix/syscall-template.S:82
82      ../sysdeps/unix/syscall-template.S: No such file or directory.
        in ../sysdeps/unix/syscall-template.S
(gdb) c 2
Will ignore next crossing of breakpoint 1.  Continuing.

Breakpoint 1, connect () at ../sysdeps/unix/syscall-template.S:82
82      in ../sysdeps/unix/syscall-template.S
(gdb) bt
#0  connect () at ../sysdeps/unix/syscall-template.S:82
#1  0x00007ffff7b28974 in openlog_internal (ident=<value optimized out>, logstat=<value optimized out>, logfac=<value optimized out>) at ../misc/syslog.c:386
#2  0x00007ffff7b29187 in __vsyslog_chk (pri=<value optimized out>, flag=1, fmt=0x40198e "%s", ap=0x7fffffffdd40) at ../misc/syslog.c:274
#3  0x00007ffff7b293af in __syslog_chk (pri=<value optimized out>, flag=<value optimized out>, fmt=<value optimized out>) at ../misc/syslog.c:131

Of course, I could completely skip this particular problem by doing an openlog() myself, but I guess that I will encounter the same type of problem with some others functions.

I don't really understand why openlog_internal does not use dynamic symbol relocation to call __connect(), and if it's even possible to hook this __connect() call by using simple LD_PRELOAD mechanism.

The others way I see how it could be done:

  • Load libc.so from an LD_PRELOAD with dlopen, get the address of the libc's __connect with dlsym() and then patch the function (ASM wise) to get the hook working. It seems really overkill and error prone.
  • Use a modified custom libc for PHP to fix those problems directly at the source (open / connect / mmap functions...)
  • Code a LKM, to redirect file access where I want. Pros : no need of ioctl(SENDFD) and no daemon outside the chroot.

I would really appreciate to learn, if it is ever possible, how I could still hook the call to __connect() issued by openlog_internal, suggestions, or links to kernel documentation related to syscall hooking and redirection.

My google searches related to "hook syscalls" found lot of references to LSM, but it seems to only allow ACLs answering "yes" or "no", but no redirection of open() paths.

Thanks for reading.


Source: (StackOverflow)