Skip to content

SOCK_CAN interface rights #53

@RazeLighter777

Description

@RazeLighter777

While it may be less well known outside the automotive and automation industry, CAN or controller area network is a widely used bus-based industrial control protocol used commonly to allow electronic control systems to communicate.

Linux supports CAN through the SocketCAN subsystem.
https://docs.kernel.org/networking/can.html

Today, a process that can create AF_CAN sockets can generally bind to any CAN interface (can0, can1, vcan*, etc.) visible in its namespace. In systems with multiple CAN buses (automotive, robotics, industrial gateways, test setups with vcan), those interfaces often represent distinct trust or safety domains.

While it's less common outside of industry (especially automotive) it seems like landlock could be extended restrict access to certain CAN interfaces, which may be useful on control systems with multiple isolated CAN buses. (it is common in many vehicles, for instance to have CAN buses for safety critical systems like airbags and brakes seperate from air conditioning, entertainment systems etc)

From the linux SocketCAN documentation:

There are two types of CAN sockets:

CAN_RAW

s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

and:

CAN_BCM

s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);

The technical difference between them is CAN_RAW requires userspace to handle the timeout monitoring, and some of the protocol implementation itself (similar to other raw sockets).

CAN_RAW sockets are used with bind

int s;
struct sockaddr_can addr;
struct ifreq ifr;

s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr);

addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;

bind(s, (struct sockaddr *)&addr, sizeof(addr));

(..)

and CAN_BCM packets are used with connect()

int s;
struct sockaddr_can addr;
struct ifreq ifr;

s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);

strcpy(ifr.ifr_name, "can0");
ioctl(s, SIOCGIFINDEX, &ifr);

addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;

connect(s, (struct sockaddr *)&addr, sizeof(addr));

(..)

Meaning that both cases would need to be handled differently.

There is no "addressing" in the traditional sense with CAN, only interface IDs. An important case to note is when the interface is in CAM_BCM, you can pass in 0 for the interface number to connect to all interfaces on the system.

While the lookup for the interface is done with IOCTL, we don't currently restrict non-device ioctl calls like this. But it seems possible add support for this with the existing connect/bind/sendmsg/sendto lsm hooks and not have to do ioctl restrictions at all

Could this be something landlock could support?

Edit: As far as I can tell, no LSM currently outside selinux supports SOCK_CAN explicitly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions