How to access /dev/mem for host from LXC container

I have a application from LXC container. It need exec dmidecode. But when i exec the cmd, it give me the following:

./dmidecode

dmidecode 2.8

/dev/mem: Operation not permitted

I had executed the following
$ lxc config device add container-name source=/dev/mem unix-char path=/dev/mem

But the issue is still there. So my question is how to access /dev/mem for host from container. Or how to map the /dev/mem of host to /dev/mem of containter.

Any comments are appreciated!

Have you tried adding sudo?

I may be wrong, but I suspect that dmidecode is performing an ioctl or something along those lines, which even if you have write access to the char device will still hit a permission check in the kernel and be denied for non-root users (including root inside an unprivileged container).

You may want to try with a privileged container, that’d likely work then.

Thx for your reply. I have set the container with a privileged container. But same result is there.

lxc config set app1 security.privileged true

lxc restart app1

[root@app1]# ./dmidecode

dmidecode 2.8

/dev/mem: Operation not permitted

Is it possible to access all devices for /dev about host from the container, if yes, how to do that?

BTW, i use the following:
lxd: 3.7
linux kernel: 4.18.9-gentoo

@brauner any idea on what kind of restrictions /dev/mem may be implemeting here?

Do you have CAP_SYS_RAWIO in the container? Because we drop it by default I think:

static int open_port(struct inode *inode, struct file *filp)
{
	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}

#define zero_lseek	null_lseek
#define full_lseek      null_lseek
#define write_zero	write_null
#define write_iter_zero	write_iter_null
#define open_mem	open_port
#define open_kmem	open_mem

I have not dropped the CAP_SYS_RAWIO in my container, the following is my config:

lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
lxc.mount.entry = sysfs sys sysfs defaults 0 0
lxc.tty = 2
lxc.pts = 1024
#lxc.cgroup.devices.deny = a
lxc.cgroup.devices.allow = a

lxc.cgroup.devices.allow = c 1:1 rwm
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
lxc.cgroup.devices.allow = c 254:0 rm
lxc.utsname = imap
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = virbr0
lxc.network.hwaddr = 00:16:3e:f1:35:ab
lxc.network.ipv4.gateway = 192.168.122.1
lxc.network.ipv4 = 192.168.122.15
lxc.cap.drop = sys_module
lxc.cap.drop = mac_admin
lxc.cap.drop = mac_override
lxc.cap.drop = sys_time
lxc.rootfs = /var/lib/lxc/app1/rootfs

You mean i need modify source code and recompile. : )

You don’t have any lxc.include lines?

@ brauner

Thx for your continuous help.

I have upgraded lxd to 3.8, I had used lxc init to generate the config. So, don’t see any lxc.include lines as you mentioned.

Also, i modify my config from gentoo /var/lib/lxc/app1/config as the following as your suggestion:

#lxc.cap.drop = sys_module
#lxc.cap.drop = mac_admin
#lxc.cap.drop = mac_override
#lxc.cap.drop = sys_time
lxc.cap.keep = sys_rawio —> add this line

I am able to see the added line, but i am not able to see thru cmd:

lxc config show app1

Could you let me know if it is possible to see /dev/sys, /dev/mem, /dev/proc for host from container? Or we are able to map /dev/sys, /dev/mem, /dev/proc for host into container.

This is very important because my customer’s application need generate certificate thru dmidecode.
I will let my customer know if this is not possible from theory.

Thx in advance!

So what should get you going - if you want to use privileged containers - is:

lxc config set <container-name> security.privileged true
lxc config set <container-name> raw.lxc 'lxc.cap.drop='
lxc config set <container-name> raw.lxc 'lxc.cap.keep='
lxc config device add <container-name> devmem unix-char source=/dev/mem
lxc restart <container-name>
lxc exec <container-name> dmidecode

The reason it doesn’t work with unprivileged containers is that capable(CAP_SYS_RAWIO) checks whether the caller has CAP_SYS_RAWIO in the initial user namespace which by design unprivileged containers have not.

@ brauner
Hope you are doing well. The following is for your reference:

sudo lxc config set app1 security.privileged true

lxc config set app1 raw.lxc ‘lxc.cap.drop=’

lxc config set app1 raw.lxc ‘lxc.cap.keep=’

lxc config device add app1 devmem unix-char source=/dev/mem

Error: The device already exists

lxc restart app1

lxc exec app1 /var/pari/dash/dmidecode

dmidecode 2.8

/dev/mem: Operation not permitted

The raw.lxc part is the issue, you’re effectively setting it to lxc.cap.drop= and then to lxc.cap.keep= when you in fact want both.

Or more likely, just lxc config set app1 raw.lxc lxc.cap.drop= will do the trick in this case.
(you’ll still need a restart afterwards)

@ brauner @stgraber
It works well now. I only use the follwing cmd:

lxc config set app1 raw.lxc ‘lxc.cap.drop=’

Thx for you great help.