Monday May 26, 2014

Solaris 11.2: presentations in Holland

I'm giving a presentation on Solaris 11.2 new features among others in June  12th and 19th,2014; register here: http://www.nosig.org/.

I'll be highlighting some new features but will also show how new and old features are combined and how Solaris 11 is our first operating system with a holistic design philosophy.

Friday May 16, 2014

Solaris 11.2: unlink(2)/link(2) for directories: your time is up.

Some thirty years ago, the 4.2BSD Unix release included two new system calls: mkdir(2) and rmdir(2).  Before that time, in order to make a directory, you first needed to call mknod(2) and create the "." and ".." links.  When you remove a file, you would remove those two links and finally unlink the directory itself. As you couldn't call mknod(2) as an ordinary user nor could you call unlink(2) on a directory, the mkdir(1) and rmdir(1) commands were set-uid root.  A cursory inspection of the UNIX-V7 showed that both commands likely had security bugs.

Did 4.2BSD remove the ability to link or unlink directories?  It didn't.  It was probably kept temporarily for backward compatibility.  But many years later, and many Unix releases later, it is still their; neither Sun in SunOS or Solaris, nor Oracle in Solaris 11/11 or 11.1.

If you ask fsck(1m), the final arbiter about what is a valid UFS file system, it will complain loudly and it generally required system admin intervention when you made an additional hardlink to a directory; this was later hidden by logging UFS; fsck was hardly ever run since the introduction of UFS logging especially once it became the default.  In tmpfs it was a good way to lose swap, hide data or confuse the kernel. Special code was needed in find(1) and du(1) to not lose their way when the file system isn't a tree but rather a cyclic graph.

It is one of the reasons why, when Solaris Zones were developed, we decided that non-global zones can only be run without the {SYS_LINKDIR} privilege and that when we introduced ZFS it came without the ability to use link(2) or unlink(2) on directories.  VxFS also doesn't allow additional hardlinks to directories. And no-one complained!

This discrepancy between the global zone and non-global zones and ZFS versus the rest and it gave us problems when developing code; code run in tmpfs file system in the global zone, suddenly stopped working when moved to a non-global zone; code that worked before in UFS stopped working when moved to ZFS or to a non-global zone.  As Linux never allowed unlink(2) on directories, code developed there might suddenly have disastrous effect on Solaris when it was run with (not-so) appropriate privileges under Solaris.  There were at least two cases during the development of Solaris 11.2 when we were bitten by this problem for code we developed ourselves.

The time has arrived to disable link(2) and unlink(2) on directories; and that is what we have done in Solaris 11.2.  The {SYS_LINKDIR} privileges still exists in Solaris 11.2 but it is obsolete and has no effect.  We will likely remove it in a future minor release.

Is this a sudden incompatible change?  Perhaps, but is well within the limits of the specification and using this feature only leads to downtime and support calls. Sorry for removing this rope from your toolbox.


Friday May 02, 2014

Solaris 11.2: No Limits

In the past, I have increased a number of limitations in Solaris:

  • In Solaris 11.0, I increased NGROUPS_MAX to 1024 (from 32); also available since Solaris 10u8.
  • In Solaris 11.1, I added support for more than 16 groups for NFS AUTH_SYS authentication
  • In Solaris 11.1, I changed the system calls getcwd() and realpath() to support returning pathnames longer than MAXPATHLEN (and introduced frealpath() while I was in that code)

So what did I change in Solaris 11.2?   It was about time to look at the restrictions of user names and group names.

In a micro release, such as a Solaris 11 update, we cannot modify constants such as LOGNAME_MAX because of binary compatibility, we can only do that in a future minor release.  However, we can modify the code that limit usernames.  These are the bugs we have fixed and this shows how much work it actually was:

    14933330 SUNBT4033673 getlogin causes passwd to fail if login name is longer than 8 chars
    14954449 SUNBT4109819 programs inconsistently limit the size of user names
    15059729 SUNBT4435330 logname(1) prints out only part of long login name
    15178384 SUNBT4927530 *w* w(1) truncates usernames to 8 chars
    15393621 SUNBT6551524 su truncates LOGNAME for long usernames.
    15436992 SUNBT6627292 *cron* confused about username lengths
    15550167 SUNBT6819489 *su* sulog source username truncated to 8 chars but not destination
    15574163 SUNBT6857992 ps -u does not support usernames longer than 10 chars
    15579148 SUNBT6866548 last command does not support usernames longer than 8 characters
    17528753 group name handling in Solaris is a standards violation
    17528788 useradd(1m) user name handling problems
    17600453 bug 15226690, find with long usernames, not completely fixed
    17600724 The fix for 14954449 misses some programs (in.rlogind, in.rshd. zone*, dump)
    17625438 group file updates very inefficient.
    17625458 pwck lives in the past
    18068180 SunSSH truncates usernames/home directories with %.100s
    18068355 A few programs still limit the size of user names.
    18068215 passmgmt invents its own limits for the sizes of entries in /etc/passwd

In generaly, the code was changed to lift limits, but we are generally limited by the format of the utmpx file.  The maximum length of a username that can be stored there, is 32 bytes.  This is now a safe limit and we support user names in length upto 32 characters, despite protests from useradd(1m).  getlogin() and getlogin_r() can return a string of at most 33 characters, including the final NUL character.  Of course, getlogin_r() will not store past the end of the buffer given to it but it will now accept a buffer of any size.   Programs changed are, among others:

  • logname(1)
  • w(1)
  • who(1)
  • last(1)
  • ls(1)  - now a 64 bit executable
  • find(1) - now a 64 bit executable
  • passmgmt(1)
  • useradd/usermod/roleadd/rolemod(1m)
  • sshd(1mr)
  • repquota(1m)
  • zfs(1)
  • yppasswd(1)
  • tar(1)
  • lastcomm(1)
  • cron(1) etc
  • newtask(1)
  • ps(1)
  • wall(1)
  • rwall(1)
  • zlogin(1)
  • grpck(1)
  • pwck(1)
  • login(1)
  • in.rexecd(1m), in.rshd(1m), in.rlogind(1m)

And libraries such as libsocket (remote shell/remote login/rexec protocol)

I could only wonder why so many applications cache the return value of getpwuid() and getgrgid() while doing that in a fixed sized character array.

For reasons only known in New-Jersey, we didn't allow groupnames over 8 characters while limiting the characters to lower case and digits; as there is no manifest constant defining the size of a group name, there is no problem increasing it so we currently support upto 32 characters and we now accept all portable file name characters in a group name (lower and upper case, digits, dot, hyphen and underscore as long as the name doesn't start with a hyphen. Other than programs caching the result of getpwuid(), I found no other limits on the length of a group name in our code.

Thursday May 01, 2014

Solaris 11.2: Immutable Global Zone

This is blog is a bit more substantial; it requires some knowledge about Solaris Zones, Immutable Zones and Solaris administration in general. It is high-level; in future I'm hoping to get down to the nuts and bolts.

Immutable Zones

In Solaris 11 we added the Read-Only Root Non-Global Zones, marketed as Immutable Zones; this is a feature that makes a zone tamper-proof.

In an Immutable Zone is configured simply by setting the "file-mac-profile" to one of "strict" (not much writeable), "fixed-configuration" and "flexible-configuration" (configuration is writeable but binaries and such or not). This is all implemented in the kernel based on pathnames and depending on the context; the super-user in the global zone can still update the zone or even modify protected files as long as that is not done from within the zone.

We have made some changes to Immutable Non-Global Zones (IMZ, for short) that came out of developing the Immutable Global Zones (IMGZ); we have added a new feature, the "Trusted Path (TP)"; when logged in through the Trusted Path using the "-T" option to zlogin(1m), you can now modify protected files from within the zone. This is much safer as you no longer need to give root access in the global zone nor do you need to boot the IMZ in writeable mode. In the following example, we log in to the zone "fixed" which has been configured with the fixed-configuration file-mac-profile. A normal root login doesn't allow us to modify "/etc/passwd"; I'm using touch(1) under privilege debugging to illustrate the error and was caused the error. When we login with the "-T" option we suddenly can modify "/etc/passwd" because we're now in the Trusted Path. Notice also that the output from privilege debugging has been clarified; it points to the MWAC(5) manual page and it now also lists the system call name and not the number as it did before.

# zlogin fixed
[Connected to zone 'fixed' pts/3]
Oracle Corporation      SunOS 5.11      11.2    April 2014
root@fixed:~# ppriv -De touch /etc/passwd
touch[117063]: MWAC(5) policy violation (euid = 0, syscall = "utimensat") for "/etc/passwd" at fop_setattr+0x10b
touch: cannot change times on /etc/passwd: Read-only file system
root@fixed:~# logout
[Connection to zone 'fixed' pts/3 closed]

# zlogin -T fixed
[Connected to zone 'fixed' pts/3]
Oracle Corporation      SunOS 5.11      11.2    April 2014
root@fixed:~# ppriv -De touch /etc/passwd
root@fixed:~# 

Additionally, we have restricted the use of mount(1m) in an IMZ, while we allowed random loopback mounts before we now only allow loopback mounts on empty directories unless the file or directory isn't protected by MWAC(5).

Immutable Global Zone

In order to prevent tampering of the file system, we have extended Immutable Zones in Solaris 11.2 to the global zone; using the same mechanism you can now configure the global zone as an IMGZ. As there is no "super-global" zone, a different mechanism has been designed to enter the Trusted Path. A kernel-zone still has a bare-metal zone controlling it, so this doesn't apply to kernel zones. Some additional steps need to be taken and they are listed here.

Preparing the global zone for immutable global zone.

As maintenance of the global zone is only possible using the Trusted Path access; Trusted Path is only available on the console, so make sure the console is accessible through the ILOM, a serial connection or through the graphical console.

Once a system is configured as an immutable global zone, the break sequence, F1-A on a graphical console, <break> or the alternate break sequence (CR-tilde-<ctl-b>) on a serial console, will instead start the Trusted Path login. (A immediate second break sequence will work as a standard break-sequence: start the kernel debugger (if it is loaded), drop to the OBP, etc)

Configuring the Global Immutable Zone

The configuration of the global zone is done through zonecfg(1m) by picking the appropriate file-mac-profile for your situation; they allowed values are the same for non-global immutable zones: "strict", "fixed-configuration", "flexible-configuration". See zonecfg(1m).

Note that if the system uses DHCP to set network interfaces, the "flexible-configuration" must be selected.

        # zonecfg -z global
        zonecfg:global> set file-mac-profile=flexible-configuration
The "rpool" dataset will be restricted but sub dataset can be unrestricted using "add dataset"
        zonecfg:global> add dataset
        zonecfg:global:dataset> set name=rpool/export
        zonecfg:global:dataset> end

        zonecfg:global> add dataset
        zonecfg:global:dataset> set name=rpool/zones
        zonecfg:global:dataset> end
In this example we add "rpool/export" and "rpool/zones"; writable data sets for users and for zones. An immutable global zone can only run zones in unrestricted datasets. All the children of an unrestricted dataset are also unrestricted.

Note that all datasets on other zpools are unrestricted and there is no needed to add them with "add dataset".

After committing the zonecfg boot information is written and the boot archive is updated:

        zonecfg:global> commit
        updating /platform/sun4u/boot_archive
When the system is configured, it should be rebooted the system will boot with an immutable global zone.

Maintenance of the immutable global zone

An immutable zone cannot be updated other then through the Trusted Path login or when the system is booted in writeable mode by using the "-w" flag when booting. Note that if you try to reboot the immutable zone with "reboot -- -w", the argument is ignored when not performed through the Trusted Path login.

After using the break-sequence on the console, you should be greeted with:

        trusted path console login:
Login and assume the root role; at that point ordinary commands used to update the system are available; this includes "pkg update", "beadm activate" or also "zonecfg" if the need arises to change the global zone's configuration.

A separate pam stack can be configured for tpdlogin(1).

When "pkg update" is performed, the first boot of the immutable global zone is read write; this is needed by the system to perform the needed self-assembly steps. When the self-assembly steps have been performed, the system will reboot and in this second boot the system will be immutable again.

Wednesday Apr 30, 2014

Solaris 11.2: User, Pid and Commands in netstat(1m)

As it has been years since I've blogged, let me start with one of smallest features I added to Solaris 11.2; an option to netstat(1m), allowing administrators to figure out who is using which port and which with process or command is using a particular network connection.

As there little or no similarity between other netstat implementation, we picked our own option letter "-u". At the same time we realigned the columns as the standard width didn't fit modern TCP window sizes, the length of Unix sockets, etc. We've also removed, for unprivileged users, unusable information such as the "kernel addresses", leaving a bit more room, though an 80 width terminal isn't really enough room for all of the information. Alignment only guaranteed with -n, of course.

Our implementation doesn't use /proc like the Linux implementation uses nor does it look through /dev/kmem like lsof(1m) does; instead we get the information available direct in the kernel. While some of the information might be out of date, we can give information about sockets in TIME_WAIT or CLOSE_WAIT, even when the latter sockets haven't been accepted yet! Additionally, those sockets owned by the kernel are also listed. This works in the global zone, non-global zones, kernel zones *and* even in Solaris 10 branded zones; the latter uses the "native" Solaris 11.2 netstat command.

Here is some sample output, partially hidden by how we format blogs (so, install Solaris 11.2 and all will be revealed)

% netstat -aun

UDP: IPv4
   Local Address        Remote Address      User    Pid      Command       State
-------------------- -------------------- -------- ------ -------------- ----------
      *.50258                             root       1038 syslogd        Idle
      *.*                                 root        133 in.mpathd      Unbound
      *.*                                 root        133 in.mpathd      Unbound
      *.*                                 netadm      721 nwamd          Unbound
      *.*                                 netadm      721 nwamd          Unbound
      *.123                               root        961 ntpd           Idle
      *.123                               root        961 ntpd           Idle
127.0.0.1.123                             root        961 ntpd           Idle
10.311.249.18.123                         root        961 ntpd           Idle
      *.111                               daemon      980 rpcbind        Idle
      *.*                                 daemon      980 rpcbind        Unbound
      *.41327                             daemon      980 rpcbind        Idle
      *.111                               daemon      980 rpcbind        Idle
      *.*                                 daemon      980 rpcbind        Unbound
      *.37058                             daemon      980 rpcbind        Idle
      *.*                                 root        988 in.ndpd        Unbound
      *.*                                 root        999 statd          Unbound
      *.*                                 root        999 statd          Unbound
      *.39150                             root        999 statd          Idle
      *.43382                             root        999 statd          Idle
      *.4045                              daemon     1008 lockd          Idle
      *.4045                              daemon     1008 lockd          Idle
      *.56874                             root       1004 inetd          Idle
      *.37069                             root       1004 inetd          Idle
      *.42765                             root       1148 mountd         Idle
      *.64957                             root       1148 mountd         Idle
      *.2049                              root       1150 nfsd           Idle
      *.2049                              root       1150 nfsd           Idle

UDP: IPv6
   Local Address                     Remote Address                   User    Pid      Command       State      If
--------------------------------- --------------------------------- -------- ------ -------------- ---------- -----
      *.*                                                           root        133 in.mpathd      Unbound    
      *.*                                                           netadm      721 nwamd          Unbound    
      *.123                                                         root        961 ntpd           Idle       
::1.123                                                             root        961 ntpd           Idle       
      *.111                                                         daemon      980 rpcbind        Idle       
      *.*                                                           daemon      980 rpcbind        Unbound    
      *.41327                                                       daemon      980 rpcbind        Idle       
      *.*                                                           root        988 in.ndpd        Unbound    
      *.39150                                                       root        999 statd          Idle       
      *.4045                                                        daemon     1008 lockd          Idle       
      *.37069                                                       root       1004 inetd          Idle       
      *.42765                                                       root       1148 mountd         Idle       
      *.2049                                                        root       1150 nfsd           Idle       

TCP: IPv4
   Local Address        Remote Address      User     Pid     Command     Swind  Send-Q  Rwind  Recv-Q    State
-------------------- -------------------- -------- ------ ------------- ------- ------ ------- ------ -----------
127.0.0.1.5999             *.*            root        133 in.mpathd           0      0  128000      0 LISTEN
      *.111                *.*            daemon      980 rpcbind             0      0  128000      0 LISTEN
      *.*                  *.*            daemon      980 rpcbind             0      0  128000      0 IDLE
      *.111                *.*            daemon      980 rpcbind             0      0  128000      0 LISTEN
      *.*                  *.*            daemon      980 rpcbind             0      0  128000      0 IDLE
      *.36887              *.*            root        999 statd               0      0  128000      0 LISTEN
      *.65159              *.*            root        999 statd               0      0  128000      0 LISTEN
10.311.249.18.58810  10.312.132.13.636    root        851 nscd            49232      0  128872      0 ESTABLISHED
      *.4045               *.*            daemon     1008 lockd               0      0 1049200      0 LISTEN
      *.4045               *.*            daemon     1008 lockd               0      0 1048952      0 LISTEN
      *.22                 *.*            root       1030 sshd                0      0  128000      0 LISTEN
127.0.0.1.25               *.*            root       1068 sendmail            0      0  128000      0 LISTEN
127.0.0.1.587              *.*            root       1068 sendmail            0      0  128000      0 LISTEN
      *.47629              *.*            root       1148 mountd              0      0  128000      0 LISTEN
      *.35906              *.*            root       1148 mountd              0      0  128000      0 LISTEN
      *.2049               *.*            root       1150 nfsd                0      0 1049200      0 LISTEN
      *.2049               *.*            root       1150 nfsd                0      0 1048952      0 LISTEN
127.0.0.1.1008             *.*            pkg5srv    1600                     0      0  128000      0 LISTEN
10.311.249.18.857    10.311.246.25.2049   casper        0 <kernel>        49232      0 1049800    116 ESTABLISHED
10.311.249.18.22     10.311.249.34.64127  root       1030 sshd           263536     63  128872      0 ESTABLISHED
127.0.0.1.6010             *.*            casper     1969 sshd                0      0  128000      0 LISTEN

TCP: IPv6
   Local Address                     Remote Address                   User    Pid      Command      Swind  Send-Q  Rwind  Recv-Q   State      If
--------------------------------- --------------------------------- -------- ------ -------------- ------- ------ ------- ------ ----------- -----
::1.5999                                *.*                         root        133 in.mpathd            0      0  128000      0 LISTEN      
      *.111                             *.*                         daemon      980 rpcbind              0      0  128000      0 LISTEN      
      *.*                               *.*                         daemon      980 rpcbind              0      0  128000      0 IDLE        
      *.36887                           *.*                         root        999 statd                0      0  128000      0 LISTEN      
      *.4045                            *.*                         daemon     1008 lockd                0      0 1049200      0 LISTEN      
      *.22                              *.*                         root       1030 sshd                 0      0  128000      0 LISTEN      
::1.25                                  *.*                         root       1068 sendmail             0      0  128000      0 LISTEN      
      *.47629                           *.*                         root       1148 mountd               0      0  128000      0 LISTEN      
      *.2049                            *.*                         root       1150 nfsd                 0      0 1049200      0 LISTEN      
::1.6010                                *.*                         casper     1969 sshd                 0      0  128000      0 LISTEN      
::1.51794                         ::1.6010                          casper     1970 xterm           130880      0  139264      0 ESTABLISHED 
::1.6010                          ::1.51794                         casper     1969 sshd            139060      0  130880      0 ESTABLISHED 

Active UNIX domain sockets
Type       User        Pid Command        Local Address                           Remote Address
stream-ord casper     1969 sshd            (socketpair)                            (socketpair)
stream-ord casper     1969 sshd            (socketpair)                            (socketpair)
stream-ord casper     1969 sshd            (socketpair)                            (socketpair)
stream-ord casper     1969 sshd            (socketpair)                            (socketpair)
stream-ord casper     1969 sshd            (socketpair)                            (socketpair)
stream-ord root        372 dbus-daemon    /var/run/dbus/system_bus_socket
stream-ord root       1028 rmvolmgr                                               /var/run/dbus/system_bus_socket
stream-ord root        372 dbus-daemon    /var/run/dbus/system_bus_socket
stream-ord root        943 hald                                                   /var/run/dbus/system_bus_socket
stream-ord root       1004 inetd          /system/volatile/inetd.uds
stream-ord root        943 hald           /system/volatile/hald/dbus-TM2nMhzrpM
stream-ord root        993 hald-addon-sto                                         /system/volatile/hald/dbus-TM2nMhzrpM
stream-ord pkg5srv    1601 httpd.worker   /system/volatile/pkg/sysrepo/wsgi.1601.0.1.sock
stream-ord root        943 hald           /system/volatile/hald/dbus-TM2nMhzrpM
dgram      root        988 in.ndpd        /system/volatile/in.ndpd_mib
stream-ord root        988 in.ndpd        /system/volatile/in.ndpd_ipadm
stream-ord root        970 hald-addon-cpu                                         /system/volatile/hald/dbus-TM2nMhzrpM
stream-ord root        943 hald           /system/volatile/hald/dbus-MIhDasTVfy
stream-ord root        944 hald-runner                                            /system/volatile/hald/dbus-MIhDasTVfy
stream-ord root        943 hald           /system/volatile/hald/dbus-MIhDasTVfy
stream-ord root        943 hald           /system/volatile/hald/dbus-TM2nMhzrpM
stream-ord root        372 dbus-daemon    /var/run/dbus/system_bus_socket
stream-ord root        922 console-kit-da                                         /var/run/dbus/system_bus_socket
stream-ord root        196 rad            /system/volatile/rad/radsocket-unauth
stream-ord root        372 dbus-daemon     (socketpair)                            (socketpair)
stream-ord root        372 dbus-daemon     (socketpair)                            (socketpair)
stream-ord root        196 rad            /system/volatile/rad/radsocket
stream-ord root        372 dbus-daemon    /var/run/dbus/system_bus_socket
Adding the option -v, you also get command line:
UDP: IPv4
   Local Address        Remote Address      User    Pid     State       Command
-------------------- -------------------- -------- ------ ---------- ----------------
      *.50258                             root       1038 Idle       /usr/sbin/syslogd
      *.*                                 root        133 Unbound    /lib/inet/in.mpathd
      *.*                                 root        133 Unbound    /lib/inet/in.mpathd
      *.*                                 netadm      721 Unbound    /lib/inet/nwamd
      *.*                                 netadm      721 Unbound    /lib/inet/nwamd
      *.123                               root        961 Idle       /usr/lib/inet/ntpd -p /var/run/ntp.pid -g
...
And for half-closed connection, you'd also get the information you want:
TCP: IPv4
   Local Address        Remote Address      User     Pid     Command     Swind  Send-Q  Rwind  Recv-Q    State
-------------------- -------------------- -------- ------ ------------- ------- ------ ------- ------ -----------
127.0.0.1.55770      127.0.0.1.4321       casper     1033 closewait      130880      0  139264      0 FIN_WAIT_2
127.0.0.1.4321       127.0.0.1.55770      casper     1031 closewait      139264      0  130880      0 CLOSE_WAIT
127.0.0.1.54943      127.0.0.1.4321       casper     1033 closewait      130880      0  139264      0 FIN_WAIT_2
127.0.0.1.4321       127.0.0.1.54943      casper     1031 closewait      139264      0  130880      0 CLOSE_WAIT
127.0.0.1.41279      127.0.0.1.4321       casper     1033 closewait      130880      0  139264      0 FIN_WAIT_2
127.0.0.1.4321       127.0.0.1.41279      casper     1031 closewait      139264      0  130880      0 CLOSE_WAIT
...

PS: I used the Hollywood IP extension to masquerade the IP addresses.

About

casper

Search


Archives
« April 2017
MonTueWedThuFriSatSun
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
       
Today