Date: Wed, 25 Aug 2021 19:43:19 -0600 From: Alan Somers <asomers@freebsd.org> To: antranigv <antranigv@freebsd.am> Cc: "freebsd-hackers@FreeBSD.org" <freebsd-hackers@freebsd.org> Subject: Re: Need advice: Better Jail integration into ps/top, setpwfile gone forever? Message-ID: <CAOtMX2jWOm1sA%2BqoaYpMR9vvcn2_KkY=dvX6ko2euh5-2hwgWQ@mail.gmail.com> In-Reply-To: <1B45F065-DC9D-40C9-958F-7D4D64DE8993@freebsd.am> References: <1B45F065-DC9D-40C9-958F-7D4D64DE8993@freebsd.am>
next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, Aug 23, 2021 at 4:03 AM antranigv <antranigv@freebsd.am> wrote:
> 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
>
> #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
> #undef _PATH_PASSWD
> #undef _PASSWD
> #undef _PATH_MASTERPASSWD
> #undef _MASTERPASSWD
>
> #undef _PATH_MP_DB
> #undef _MP_DB
> #undef _PATH_SMP_DB
> #undef _SMP_DB
>
> #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 = getpwuid(1001);
> if (pwd == 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 = getpwuid(1001);
> if (pwd == NULL) {
> printf("after chroot: no user found\n");
> } else {
> printf("after chroot: %s\n", pwd->pw_name);
> }
>
> // escape back the chroot ;-)
> chroot("../../../../");
> pwd = getpwuid(1001);
> if (pwd == 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
> 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/
>
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?CAOtMX2jWOm1sA%2BqoaYpMR9vvcn2_KkY=dvX6ko2euh5-2hwgWQ>
