Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Aug 2021 14:02:39 +0400
From:      antranigv <antranigv@freebsd.am>
To:        "freebsd-hackers@FreeBSD.org" <freebsd-hackers@FreeBSD.org>
Subject:   Need advice: Better Jail integration into ps/top, setpwfile gone forever?
Message-ID:  <1B45F065-DC9D-40C9-958F-7D4D64DE8993@freebsd.am>

next in thread | raw e-mail | index | archive | help
Greetings all,

I am trying to have better integration of top(1) and ps(1) with FreeBSD =
Jails.

The main problem that I am trying to solve is displaying the correct UID =
username. Here's an example.

I have a host (srv0), it is running a Jail named "fsoc", The Jail "fsoc" =
has a user named "romero" with the UID 1001.

If I run `ps auxd` in the Jail, I get the following,

romero@fsoc:~ $ ps auxd
USER    PID %CPU %MEM   VSZ  RSS TT  STAT STARTED    TIME COMMAND
root   4377  0.0  0.0 11376  956  -  SsJ  14:15   0:00.38 =
/usr/sbin/syslogd -ss
root   5758  0.0  0.1 13128 1352  1  IJ   18:24   0:00.02 /bin/tcsh -i
root   5763  0.0  0.0 12048  960  1  IJ   18:24   0:00.01 - su - romero
romero 5764  0.0  0.1 12120 2268  1  SJ   18:24   0:00.02 `-- -su (sh)
romero 9625  0.0  0.1 11684 2576  1  R+J  09:41   0:00.01   `-- ps auxd

Good!

However, if I try to run it on the host, here's what I get,

root@srv0:~ # ps auxd -J fsoc
USER  PID %CPU %MEM   VSZ  RSS TT  STAT STARTED    TIME COMMAND
root 4377  0.0  0.0 11376  956  -  SsJ  14:15   0:00.38 =
/usr/sbin/syslogd -ss
root 5758  0.0  0.1 13128 1352  1  IJ   18:24   0:00.02 /bin/tcsh -i
root 5763  0.0  0.0 12048  960  1  IJ   18:24   0:00.01 - su - romero
1001 5764  0.0  0.1 12124 2436  1  I+J  18:24   0:00.02 `-- -su (sh)

As you can see, in the User field it says 1001, because the host does =
not have a user with that UID.

This seems fine, but it becomes an issue when you have multiple Jail and =
a large host running.

Here's an example if the host had a user with UID 1001,

root@pingvinashen:~ # ps auxd -J oragir
USER        PID %CPU %MEM    VSZ   RSS TT  STAT STARTED    TIME COMMAND
root        949  0.0  0.0  11344  2584  -  IsJ  Mon19   0:01.13 =
/usr/sbin/cron -s
root       1962  0.0  0.0  11428  2796  -  SsJ  Mon19   0:01.83 =
/usr/sbin/syslogd -ss
antranigv 95342  0.0  0.0  11004  2424  -  IsJ  Mon19   0:00.48 daemon: =
/usr/home/oragir/writefreely/writefreely[9992] (daemon)
antranigv  9992  0.0  0.4 767244 58336  -  IJ   Mon19   2:58.87 - =
/usr/home/oragir/writefreely/writefreely

Now, you would think that this is good, however, if you run this in the =
jail,

root@oragir:~ # ps auxd
USER      PID %CPU %MEM    VSZ   RSS TT  STAT STARTED    TIME COMMAND
root      949  0.0  0.0  11344  2584  -  SsJ  Mon15   0:01.13 =
/usr/sbin/cron -s
root     1962  0.0  0.0  11428  2796  -  SsJ  Mon15   0:01.83 =
/usr/sbin/syslogd -ss
oragir  95342  0.0  0.0  11004  2424  -  IsJ  Mon15   0:00.48 daemon: =
/usr/home/oragir/writefreely/writefreely[9992] (daemon)
oragir   9992  0.0  0.4 767244 58336  -  IJ   Mon15   2:58.88 - =
/usr/home/oragir/writefreely/writefreely
root    88228  0.0  0.0  13336  4004  8  SJ   09:45   0:00.01 /bin/csh =
-i
root    99502  0.0  0.0  11824  3140  8  R+J  09:45   0:00.00 - ps auxd

As you can see, the UID 1001 was not `antranigv`, instead it was =
`oragir`.

This has been an issue for me, so I tried writing some code to implement =
the following.

If the process is in a Jail, then change the passwd db from /etc to =
/path/of/the/jail/etc.

I thought it would be an easy thing to do, but not so much.

Here's what I've tried.

1) Call jail_attach and run ps inside the Jail. Oh yeah, it's a jail! =
after attaching to it there is no way to deattach :-) silly me!

2) Change the passwd file for getpwuid/getpwnam. I wanted to use =
setpwfile(3) but turns out that \
COMPATIBILITY
     The historic function setpwfile(3), which allowed the specification =
of
     alternate password databases, has been deprecated and is no longer
     available.

Okay, So I look into how other tools like pwd_mkdb is written and I see =
that everything is defined (pun intended) the following way,

in /usr/include/pwd.h

#define _PATH_PWD               "/etc"
#define _PATH_PASSWD            "/etc/passwd"
#define _PASSWD                 "passwd"
#define _PATH_MASTERPASSWD      "/etc/master.passwd"
#define _MASTERPASSWD           "master.passwd"

#define _PATH_MP_DB             "/etc/pwd.db"
#define _MP_DB                  "pwd.db"
#define _PATH_SMP_DB            "/etc/spwd.db"
#define _SMP_DB                 "spwd.db"

#define _PATH_PWD_MKDB          "/usr/sbin/pwd_mkdb"

and pwd_mkdb does the following

...
strcpy(prefix, _PATH_PWD);
...
                case 'd':
                        dflag++;
                        strlcpy(prefix, optarg, sizeof(prefix));
                        break;
...

Tuns out it parses the DB file, but I don't want to do that in ps/top! =
:-)

3) Just for fun, I played with chroot. I tried the following code.
# cat getpw.c=20

#define MAXHOSTNAMELEN  255
#define MAXPATHLEN      255
#include <pwd.h>
//#include <jail.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/jail.h>
#include <sys/param.h>
#include <sys/types.h>

int main(){
        // Just get root!
        struct passwd *pwd;
        printf("just root: %s\n", (getpwuid(0))->pw_name);

        // let's try with undef/define
#undef _PATH_PWD        =20
#undef _PATH_PASSWD     =20
#undef _PASSWD          =20
#undef _PATH_MASTERPASSWD
#undef _MASTERPASSWD    =20

#undef _PATH_MP_DB      =20
#undef _MP_DB           =20
#undef _PATH_SMP_DB     =20
#undef _SMP_DB          =20

#define _PATH_PWD               "/zdata/jails/fsoc/etc"
#define _PATH_PASSWD            "/zdata/jails/fsoc/etc/passwd"
#define _PASSWD                 "passwd"
#define _PATH_MASTERPASSWD      "/zdata/jails/fsoc/etc/master.passwd"
#define _MASTERPASSWD           "master.passwd"

#define _PATH_MP_DB             "/zdata/jails/fsoc/etc/pwd.db"
#define _MP_DB                  "pwd.db"
#define _PATH_SMP_DB            "/zdata/jails/fsoc/etc/spwd.db"
#define _SMP_DB                 "spwd.db"
        pwd =3D getpwuid(1001);
        if (pwd =3D=3D NULL) {
                printf("using undef/define: no user found\n");
        } else {
                printf("using undef/define: %s\n", pwd->pw_name);
        }

        // let's try with chroot!
        chroot("/zdata/jails/fsoc");
        pwd =3D getpwuid(1001);
        if (pwd =3D=3D NULL) {
                printf("after chroot: no user found\n");
        } else {
                printf("after chroot: %s\n", pwd->pw_name);
        }

        // escape back the chroot ;-)
        chroot("../../../../");
        pwd =3D getpwuid(1001);
        if (pwd =3D=3D NULL) {
                printf("after unchroot: no user found\n");
        } else {
                printf("after chroot: %s\n", pwd->pw_name);
        }

        return 42;
}

And I get the following:

# ./getpw=20
just root: root
using undef/define: no user found
after chroot: romero
after unchroot: no user found

So, any advice? should I do chroot in ps? (no I don't think that's a =
good idea), should I add a new call that implements setpwfile(3)? But I =
really want to know why it was removed, I'm sure there's a story there. =
Or is there a better way?

Kind regards, have a nice day!

--
antranigv
https://antranigv.am/




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1B45F065-DC9D-40C9-958F-7D4D64DE8993>