Thursday, November 02, 2017

OpenZFS ZIL Internals

Very interesting presentation on how ZIL works and on latest improvements in OpenZFS, presented during OpenZFS Developer Summit 2017.

Tuesday, September 12, 2017

Tuesday, July 04, 2017

Sudo and Solaris Privileges

Sudo on Solaris 10 and Solaris 11 allow to specify a privilege set a command will run with. This is very powerful if you want to be more specific in granting only required privileges for a given command, instead of allowing a command to run as root. Although Solaris has additional/different means to achieve the same, which in some cases is better than sudo, but the latter is what most users are familiar with.

For example, the 'fmadm faulty' command requires sys_admin privilege to run.

milek    ALL=()PRIVS="basic,sys_admin" NOPASSWD:/usr/sbin/fmadm faulty
This means that user milek can now run: sudo fmadm faulty
and the command will now work, but it won't run as root - it will execute as user milek with privileges set to basic,sys_admin, which is more secure than allowing the command to run as root.

Tuesday, May 16, 2017

Solaris Open Source bits move to GitHub

Alan Coopersmith blogged about migration of Open Source content available in Solaris from to GitHub. This is definitely an improvement.

The new repositories on GitHub are:

Friday, April 21, 2017

Ebbisland and Extremeparr

Although The Register and others were suggesting Solaris 11 might be affected, it seems not to be the case - according to Oracle Solaris 11 has never been affected be either of them.The Register clarified it as well.

Also if you have a support contract you should have been told this much quicker.

ps. if you have CDE installed on Solaris 10 then there is an IDR available for extremeparr local exploit (again, Solaris 11 is not affected)

Saturday, February 25, 2017

Friday, January 20, 2017

Solaris 11 Continuous Delivery Model

Solaris 11 adopts Continuous Delivery model, which means instead of Solaris 12 there will be Solaris 11.4, 11.5, etc. This is generally a good thing - quicker adoption of new features as most software certified for Solaris 11 should stay certified for the new dot releases, etc. This is also similar to what Microsoft did with Windows.

Oracle also extended Solaris 11 support to 2031.

Friday, October 21, 2016

AI: Distro Constructor and a Custom Script

When building your own AI images with distro_const it is useful sometimes to add a custom script to modify the resulting image. This is easily achievable by adding a custom script to the xml manifest provided to distro_cons.

For example, to change the default password for user jack, add the following checkpoint to the xml file, just before pre-pkg-img-mode checkpoint. 

  Set password to user jack, should match root password
  (if hash contains slashed they need to be backslashed)
      <checkpoint name="lock-jack-account"
         desc="Lock the jack account from login"
         <args>/usr/bin/gsed -i -e 's/jack:.[^:]*:/jack:XXXXXX:/g' 

Tuesday, October 11, 2016

Requiring both GSSAPI and OTP

Darren Moffat blogged about how to force both GSSAPI (or pubkey) and OTP on Solaris in OpenSSH. This works, although is not entirely obvious how to set it up at first.

Friday, July 01, 2016


Oracle released new SPARC S7 CPU and SPARC S7-2 and S7-2L servers. This is really interesting SPARC CPU if you need low-end servers, the first one in many, many years which can compete with x86 both in performance and price. It has some unique features as well.

See launch video.

Various articles on S7:

The Register

Also see some benchmarks already published:

Database: S7 vs x86
Yahoo Cloud Serving Benchmark

Friday, May 20, 2016

Adjusting SO_RCVBUF of a running process

Recently I was looking into how to increase SO_RCVBUF size for a given socket in a running process, without having to restart it. This could be useful, if an application can't be restarted anytime soon, yet there are drops observed due to too low receive buffer set, or perhaps a given application doesn't even allow for the receive buffer to be specified and has a hard-coded value. In my case, an application does allow for the buffer to be specified, but it only sets it on startup and I couldn't restart it.

Solaris (nor Linux AFAIK) does not provide a tool to easily adjust the buffer for a socket in a running process, so I looked if I could do it via libproc. The answer is yes, and it is pretty straightforward.

I quickly wrote a small C program which changes the SO_RCVBUF size for a given pid and file descriptor number. Let's see an example on how to use it.

There is a process with pid 893 listening on port UDP/32623 with the SO_RCVBUG currently set to 128104:

# pfiles 893
893:    /usr/local/bin/test-daemon
  Current rlimit: 256 file descriptors
   4: S_IFSOCK mode:0666 dev:574,0 ino:43685 uid:0 gid:0 size:0
      sockname: AF_INET  port: 32623
      congestion control: newreno

Let's change the SO_RCVBUG to a higher value:

# ./pr_setsockopt 893 4 500000
Current SO_RCVBUG is 128104
New SO_RCVBUG is 500088

# pfiles 893
   4: S_IFSOCK mode:0666 dev:574,0 ino:43685 uid:0 gid:0 size:0
      sockname: AF_INET  port: 32623
      congestion control: newreno

The code is very similar to the one I wrote last time. However, as there is no pr_setsockopt() wrapper function, I wrote one based on how the other pr_* functions are implemented, specifically pr_getsockopt(). The trick is that there is Psyscall() function available, which allows you to call any syscall from the target process, so all that is required is to use it to call SYS_setsockopt.

As the source code for Solaris is no longer publicly available, I used Illumos source code. The program was tested only on Solaris 11 x86, although it probably works fine on Solaris 10 and Illumos, and should work on SPARC as well.

It is a quick "hack", with no safeguards, no proper argument parsing, etc.
Use it at your own risk.

// gcc -m64 -lproc -o pr_setsockopt pr_setsockopt.c

#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <libproc.h>

pr_setsockopt(struct ps_prochandle *Pr, int sock, int level, int optname, void *optval, int optlen) {
  sysret_t rval;  /* return value from getsockopt() */
  argdes_t argd[5]; /* arg descriptors for getsockopt() */
  argdes_t *adp;
  int error;

  if (Pr == NULL)  /* no subject process */
    return (_so_setsockopt(sock, level, optname, optval, optlen));

  adp = &argd[0];  /* sock argument */
  adp->arg_value = sock;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  adp++;   /* level argument */
  adp->arg_value = level;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  adp++;   /* optname argument */
  adp->arg_value = optname;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  adp++;   /* optval argument */
  adp->arg_value = 0;
  adp->arg_object = optval;
  adp->arg_type = AT_BYREF;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = optlen == NULL ? 0 : optlen;

  adp++;   /* optlen argument */
  adp->arg_value = optlen;
  adp->arg_object = NULL;
  adp->arg_type = AT_BYVAL;
  adp->arg_inout = AI_INPUT;
  adp->arg_size = 0;

  error = Psyscall(Pr, &rval, SYS_setsockopt, 5, &argd[0]);

  if (error) {
    errno = (error > 0)? error : ENOSYS;
    return (-1);
  return (0);

int main(int argc, char **argv) {
  pid_t pid;
  int fd;
  int perr;
  static struct ps_prochandle *Pr;

  pid = atop(argv[1]);
  fd = atoi(argv[2]);

  if((Pr = Pgrab(pid, PGRAB_NOSTOP, &perr)) == NULL) {
    printf("Pgrab() failed: %s\n", Pgrab_error(perr));

  int rcvbuf = 0;
  int rcvbuf_size = sizeof(rcvbuf);
  if(pr_getsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &rcvbuf_size)) {
    perror("pr_getsockopt() failed");
    Prelease(Pr, 0);

  printf("Current SO_RCVBUF is %d\n", rcvbuf);

  rcvbuf = atoi(argv[3]);
  if(pr_setsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, rcvbuf_size)) {
    perror("pr_setsockopt() failed");
    Prelease(Pr, 0);

  if(pr_getsockopt(Pr, fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &rcvbuf_size)) {
    perror("pr_getsockopt() failed");
    Prelease(Pr, 0);

  printf("New SO_RCVBUF is %d\n", rcvbuf);

  Prelease(Pr, 0);
  Pr = NULL;