2

I am using grsecurity kernel with CONFIG_GRKERNSEC_SOCKET_SERVER enabled:

[*] Socket restrictions  
  [ ]   Deny any sockets to group (NEW)  
  [ ]   Deny client sockets to group (NEW)
  [*]   Deny server sockets to group

This prevents a user from creating a "server" socket (i.e. starting Apache), but allows opening client sockets (i.e. Firefox).

Indeed, all network clients work fine (Firefox, telnet, ssh, nc, w3m, ..). Only Chrome browser (Chromium) does not work.

When starting chrome from command line, I get following error:

ERROR:address_tracker_linux.cc(138)] Could not bind NETLINK socket: Permission denied
libudev: udev_monitor_enable_receiving: bind failed: Permission denied
FATAL:udev_linux.cc(31)] Check failed: 0 == ret (0 vs. -1)
Aborted

and in the logs, I see:

grsec: denied bind() by /usr/lib/chromium/chromium[NetworkChangeNo:3920]
grsec: denied bind() by /usr/lib/chromium/chromium[WorkerPool/3922:3922]
grsec: denied bind() by /usr/lib/chromium/chromium[Chrome_IOThread:3934]
grsec: denied bind() by /usr/lib/chromium/chromium[NetworkChangeNo:3966]
grsec: denied bind() by /usr/lib/chromium/chromium[WorkerPool/3968:3968]
grsec: denied bind() by /usr/lib/chromium/chromium[Chrome_IOThread:3980]

Can somebody please explain, why chrome fails to start while all other clients (Firefox) work fine ?

I am using Chrome (Chromium) 37 on Debian Wheezy (64-bit)

0

1 Answer 1

6

Chromium fails to start because denying server sockets also denies AF_NETLINK sockets, and for some reason Chromium needs to communicate with udev, which required AF_NETLINK sockets. I don't have an obviously authoritative source, but I'll try to explain from first principles using the underlying source code and hopefully not make too many mistakes in the process.

I started off investigating the first error message. The code that produces the error message in Chromium is https://src.chromium.org/svn/trunk/src/net/base/address_tracker_linux.cc line 138:

  // Request notifications.
  struct sockaddr_nl addr = {};
  addr.nl_family = AF_NETLINK;
  addr.nl_pid = getpid();
  // TODO(szym): Track RTMGRP_LINK as well for ifi_type, http://crbug.com/113993
  addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY |
      RTMGRP_LINK;
  int rv = bind(netlink_fd_,
                reinterpret_cast<struct sockaddr*>(&addr),
                sizeof(addr));
  if (rv < 0) {
    PLOG(ERROR) << "Could not bind NETLINK socket";
    AbortAndForceOnline();
    return;
  }

The actual grsec-related failure happens in the bind() call, which attempts to set up a netlink socket which will receive notifications whenever an interface IPv4 or IPv6 address changes and whenever a link state changes.

This call is handled by a syscall in the kernel, in net/socket.c:

SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
{
        struct socket *sock;
        struct sockaddr_storage address;
        int err, fput_needed;

This declares the syscall and a few local variables. You can see the syscall declaration matches the bind() call in the Chromium code: int fd, struct sockaddr __user * umyaddr, int addrlen.

        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (sock) {

This looks the socket up from the file descriptor. If a socket is found...

                err = move_addr_to_kernel(umyaddr, addrlen, &address);
                if (err >= 0) {

This copies the data provided from user space to kernel space. If there is no error...

                        err = security_socket_bind(sock,
                                                   (struct sockaddr *)&address,
                                                   addrlen);
                        if (!err)

This gives any loaded LSM (SELinux etc.) a chance to check the call is allowed. If so...

                                err = sock->ops->bind(sock,
                                                      (struct sockaddr *)
                                                      &address, addrlen);

The bind proceeds elsewhere, and we're done as far as the analysis of the standard kernel code is concerned here.

grsec patches net/socket.c in a number of places; in particular, before the LSM security check, it adds its own checks (see https://grsecurity.net/test/grsecurity-3.0-3.18.6-201502062100.patch; search for SYSCALL_DEFINE3(bind):

                        if (gr_handle_sock_server((struct sockaddr *)&address)) {
                                err = -EACCES;
                                goto error;
                        }
                        err = gr_search_bind(sock, (struct sockaddr_in *)&address);
                        if (err)
                                goto error;

The first check is the one that's relevant here; it calls gr_handle_sock_server():

gr_handle_sock_server(const struct sockaddr *sck)
{
#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER
       if (grsec_enable_socket_server &&
           in_group_p(grsec_socket_server_gid) &&
           sck && (sck->sa_family != AF_UNIX) &&
           (sck->sa_family != AF_LOCAL)) {
               gr_log_noargs(GR_DONT_AUDIT, GR_BIND_MSG);
               return -EACCES;
       }
#endif
       return 0;
}

This implements the "deny server sockets to group" check. As verified in the comments, on your system grsec_enable_socket_server is 1, so when running as group 1001, the if succeeds (sck->sa_family == AF_NETLINK in this case), and access is denied.

Going back to the Chromium code, this logs an error message and calls AbortAndForceOnline(), which just sets things up so the browser reckons it's online. So this doesn't explain the failure to start.

Before pushing further I attempted to reproduce the failure. To do this, I adapted authbind so it would prevent AF_NETLINK binds; in libauthbind.c, in the bind() function I added a case to the first switch:

  case AF_NETLINK:
    puts("Denying AF_NETLINK");
    return -EACCES;

Running with the resulting library reproduced the failure:

% LD_PRELOAD=/usr/lib/authbind/libauthbind.so.1 chromium
Denying AF_NETLINK
 [15858:15876:0214/160730:ERROR:address_tracker_linux.cc(154)] Could not bind NETLINK socket: Success
Denying AF_NETLINK
libudev: udev_monitor_enable_receiving: bind failed: No such file or directory
[15858:15890:0214/160730:FATAL:udev_linux.cc(29)] Check failed: 0 == ret (0 vs. -2)
zsh: abort      LD_PRELOAD=/usr/lib/authbind/libauthbind.so.1 chromium

(The strange error messages, "Success" and "No such file directory", occur because I'm not setting errno.)

So the abort is indeed related to bind(). Checking udev_linux.cc line 29 shows

  int ret = udev_monitor_enable_receiving(monitor_.get());
  CHECK_EQ(0, ret);

ret here is negative because udev_monitor_enable_receiving() can't bind a netlink socket, and CHECK_EQ causes an assertion failure here (see https://src.chromium.org/svn/trunk/src/base/logging.h for the implementation). This produces an abort signal and Chromium quits with an "Aborted" message of some sort, depending on the shell being used.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .