Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 27 Aug 2021 13:34:48 +0400
From:      antranigv <antranigv@freebsd.am>
To:        Alan Somers <asomers@freebsd.org>, Jamie Landeg-Jones <jamie@catflap.org>
Cc:        "freebsd-hackers@FreeBSD.org" <freebsd-hackers@freebsd.org>
Subject:   Re: Need advice: Better Jail integration into ps/top, setpwfile gone forever?
Message-ID:  <5DB070E0-2602-4C15-B950-920B56506E15@freebsd.am>
In-Reply-To: <CAOtMX2jWOm1sA%2BqoaYpMR9vvcn2_KkY=dvX6ko2euh5-2hwgWQ@mail.gmail.com>
References:  <1B45F065-DC9D-40C9-958F-7D4D64DE8993@freebsd.am> <CAOtMX2jWOm1sA%2BqoaYpMR9vvcn2_KkY=dvX6ko2euh5-2hwgWQ@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Dear Jamie and Alan,

Thank you both for your inputs.

Jamie, I totally understand your point, for an issue like this to be =
fixed, we=20
need to patch some subsystem. I'm not sure I have enough knowledge to do =
that,=20
but what you point is called UID Virtualization. If I am not mistaken =
illumos=20
systems do that for their Zones. I have to get into it, hopefully =
something=20
similar can be done with FreeBSD.

So,
1) Yes, patching only ps/top will not solve the issue, what about htop?=20=

sockstat? procstat? etc.
2) The ideal way is to make a major change. Look into what other systems =
are=20
doing and try to implement it here.

Alan, I got a PoC working!

#include <pwd.h>
#include <jail.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/types.h>
#include <sys/socket.h>

int main(int argc, char *argv[]){
        struct passwd *pwd;
        int sp[2], uid;
        pid_t pid;

        if (argc < 2 ) { printf("usage: psjail UID\n"); exit(1); }
        uid =3D atoi(argv[1]);
        printf("Got UID: %d\n", uid);

        socketpair(PF_LOCAL, SOCK_STREAM, 0, sp);

        pid =3D fork();

        if (pid =3D=3D 0){
                printf("In the child process\n");
                printf("Going into Jail\n");
                jail_attach(35);
                pwd =3D getpwuid(uid);
                if (pwd =3D=3D NULL) {
                        printf("In the Jail: no user found\n");
                        write(sp[1], "", sizeof(pwd));
                } else {
                        printf("In the Jail: %s\n", pwd->pw_name);
                        write(sp[1], pwd->pw_name, =
sizeof(pwd->pw_name));
                        printf("Message sent\n");
                }
                _Exit(0);
        } else {
                char buf[sizeof(pwd->pw_name)];
                printf("I'm the parent\n");
                int n =3D read(sp[0], buf, sizeof(pwd->pw_name));
                printf("got %d bytes\n", n);
                printf("parent got : '%s'\n", buf);
                pwd =3D getpwuid(uid);
                if (pwd =3D=3D NULL) {
                        printf("In the parent: no user found\n");
                } else {
                        printf("In the parent: %s\n", pwd->pw_name);
                }
        }
        printf("Done executing\n");
        return 42;
}

Here's a sample output,

root@srv0:~/src # ./spjail 1001
Got UID: 1001
I'm the parent
In the child process
Going into Jail
In the Jail: romero
Message sent
got 8 bytes
parent got : 'romero'
In the parent: no user found
Done executing

root@srv0:~/src # ./spjail 1000
Got UID: 1000
I'm the parent
In the child process
Going into Jail
In the Jail: no user found
got 8 bytes
parent got : ''
In the parent: no user found
Done executing

Now, as Jamie said, this is not a good idea, it's basically a "Hack." I =
will=20
try to find a proper way to virtualize the UID table, write a PoC for =
that and=20
see what the community thinks about that.

I like Jamie's approach, but I would not want it to be manual. We need =
some=20
automated way. Sure, I can integrate that into my Jail Orchestrator, but =
some=20
people want to use jail(8) with jail.conf, and it should be simple for =
them as=20
well.

Thank you all. Any more input will be appreciated.

Kind regards,

--
antranigv
https://antranigv.am/

> On 26 Aug 2021, at 5:43 AM, Alan Somers <asomers@freebsd.org> wrote:
>=20
> On Mon, Aug 23, 2021 at 4:03 AM antranigv <antranigv@freebsd.am> =
wrote:
>=20
>> Greetings all,
>>=20
>> I am trying to have better integration of top(1) and ps(1) with =
FreeBSD
>> Jails.
>>=20
>> The main problem that I am trying to solve is displaying the correct =
UID
>> username. Here's an example.
>>=20
>> I have a host (srv0), it is running a Jail named "fsoc", The Jail =
"fsoc"
>> has a user named "romero" with the UID 1001.
>>=20
>> If I run `ps auxd` in the Jail, I get the following,
>>=20
>> 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
>>=20
>> Good!
>>=20
>> However, if I try to run it on the host, here's what I get,
>>=20
>> 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)
>>=20
>> As you can see, in the User field it says 1001, because the host does =
not
>> have a user with that UID.
>>=20
>> This seems fine, but it becomes an issue when you have multiple Jail =
and a
>> large host running.
>>=20
>> Here's an example if the host had a user with UID 1001,
>>=20
>> 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
>>=20
>> Now, you would think that this is good, however, if you run this in =
the
>> jail,
>>=20
>> 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
>>=20
>> As you can see, the UID 1001 was not `antranigv`, instead it was =
`oragir`.
>>=20
>> This has been an issue for me, so I tried writing some code to =
implement
>> the following.
>>=20
>> If the process is in a Jail, then change the passwd db from /etc to
>> /path/of/the/jail/etc.
>>=20
>> I thought it would be an easy thing to do, but not so much.
>>=20
>> Here's what I've tried.
>>=20
>> 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!
>>=20
>> 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.
>>=20
>> 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,
>>=20
>> in /usr/include/pwd.h
>>=20
>> #define _PATH_PWD               "/etc"
>> #define _PATH_PASSWD            "/etc/passwd"
>> #define _PASSWD                 "passwd"
>> #define _PATH_MASTERPASSWD      "/etc/master.passwd"
>> #define _MASTERPASSWD           "master.passwd"
>>=20
>> #define _PATH_MP_DB             "/etc/pwd.db"
>> #define _MP_DB                  "pwd.db"
>> #define _PATH_SMP_DB            "/etc/spwd.db"
>> #define _SMP_DB                 "spwd.db"
>>=20
>> #define _PATH_PWD_MKDB          "/usr/sbin/pwd_mkdb"
>>=20
>> and pwd_mkdb does the following
>>=20
>> ...
>> strcpy(prefix, _PATH_PWD);
>> ...
>>                case 'd':
>>                        dflag++;
>>                        strlcpy(prefix, optarg, sizeof(prefix));
>>                        break;
>> ...
>>=20
>> Tuns out it parses the DB file, but I don't want to do that in =
ps/top! :-)
>>=20
>> 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>
>>=20
>> int main(){
>>        // Just get root!
>>        struct passwd *pwd;
>>        printf("just root: %s\n", (getpwuid(0))->pw_name);
>>=20
>>        // let's try with undef/define
>> #undef _PATH_PWD
>> #undef _PATH_PASSWD
>> #undef _PASSWD
>> #undef _PATH_MASTERPASSWD
>> #undef _MASTERPASSWD
>>=20
>> #undef _PATH_MP_DB
>> #undef _MP_DB
>> #undef _PATH_SMP_DB
>> #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"
>>=20
>> #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);
>>        }
>>=20
>>        // 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);
>>        }
>>=20
>>        // 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);
>>        }
>>=20
>>        return 42;
>> }
>>=20
>> And I get the following:
>>=20
>> # ./getpw
>> just root: root
>> using undef/define: no user found
>> after chroot: romero
>> after unchroot: no user found
>>=20
>> 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?
>>=20
>> Kind regards, have a nice day!
>>=20
>> --
>> antranigv
>> https://antranigv.am/
>>=20
>=20
> Oof, that's a hard problem.  But in fact, it's worse than you think.
> /etc/passwd isn't the only place that user information is stored.   It
> could be in NIS, or LDAP, or Heimdal, or who knows where.  The only
> reliable way to look up a user is to actually do it from within the =
jail.
> You could create a socketpair, then fork a child process and attach =
that to
> the jail, and use it to lookup jailed UIDs.  It's complicated, but I =
can't
> imagine anything simpler that would work.
> -Alan




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5DB070E0-2602-4C15-B950-920B56506E15>