[PATCH 0/6] landlock: Add POSIX message queue scoping

Günther Noack gnoack3000 at gmail.com
Fri Aug 21 08:46:37 UTC 2026


Hello Oxana!

On Wed, Jul 22, 2026 at 01:29:36PM +0100, Oxana Kharitonova wrote:
> This series adds landlock support for scoping POSIX message queuesi [1].
>  
> Landlock already supports scoped IPC restrictions for signals and abstract
> UNIX sockets. These restrictions make it possible to prevent a sandboxed
> task from interacting with IPC objects outside of its Landlock domain,
> while still allowing communication within the same domain or with nested
> domains.
>  
> This series extends the same model to POSIX message queues with a new
> LANDLOCK_SCOPE_POSIX_MSG_QUEUE scope. When this scope is enforced, a task
> can only open POSIX message queues that were created by a task in the same
> landlock domain or in a nested domain.
>  
> The implementation tags mqueuefs inodes at creation time with the creator's
> landlock domain. This domain is kept alive for the lifetime of the inode
> and is checked when the queue is opened.
>  
> The series also exposes the mqueuefs magic number through the shared UAPI
> magic header, bumps the Landlock ABI, updates documentation, adds sandboxer
> support, and adds selftests.
>  
> The new behavior is:
>  
> - a task restricted with LANDLOCK_SCOPE_POSIX_MSG_QUEUE cannot open a queue
>   created outside of its Landlock scope;
> - a task can still open a queue created within its own Landlock domain;
> - queues created outside of any Landlock domain are treated as outside the
>   scope for a scoped opener.

Thank you for sending this!

I have a high level question about this patch set:

You are adding a check to hook_file_open(), but the existing
hook_file_open() can already prevent mq_open().

The following experiment illustrates this:
* Restrict LANDLOCK_ACCESS_FS_READ_FILE and LANDLOCK_ACCESS_FS_WRITE_FILE
* Try to run mq_open("/foobar", O_CREAT...)

Depending on the installed PATH_BENEATH rules, you now see differing behaviour:

* If we allow READ_FILE and WRITE_FILE on nothing, mq_open() is *DENIED*.
* If we allow READ_FILE and WRITE_FILE on /, mq_open() is *DENIED*.
* If we allow READ_FILE and WRITE_FILE on a mounted /dev/mqueue, mq_open() is *ALLOWED*.

So it seems that the existing file system restrictions are already
preventing POSIX message queues from being opened?  And not only that
-- since such Landlock policies are already quite common, it seems
likely that many existing landlocked programs are already restricting
opening of POSIX message queues today.

So, to clarify:

* What your patch set is adding is only that we are now additionally
  taking the Landlock domain scope into account?
* This distinction only makes a difference for landlocked programs
  that do not restrict READ_FILE/WRITE_FILE or that do restrict it and
  then allow-list READ_FILE/WRITE_FILE on a previously mounted
  /dev/mqueue.

Maybe this would be interesting to clarify a bit more prominently in
the cover letter, because it reduces the applicability of this
patchset?

Attached below is a LLM-generated (but double checked) test program
which you can use to try out the creation of mqueues.  (As first
argument, use "-", "/" or "/dev/mqueue".)

What *might* still be interesting to restrict though: While mq_open()
checks the READ_FILE and WRITE_FILE rights, it checks none of the
LANDLOCK_ACCESS_FS_MAKE_* rights -- the message queue gets still
created, even when the mq_open() is denied and returns with an error.

To expand on Justin's comment in [1] -- it feels that there are maybe
still some gaps in the "lifecycle management" of these message queues
that might be worth thinking systematically about, because both
mq_unlink() and the creation of the message queue entries are
currently apparently not restrictable yet?  It makes me wonder whether
hijacking of message queue names (creating same-named queues in other
Landlock domains) is a problem then?  Do you have thoughts on this?

Thanks,
–Günther

[1] https://lore.kernel.org/all/amKDYoOSvHMzVbKX@suesslenovo/


--- llmq.c
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <linux/landlock.h>
#include <mqueue.h>
#include <stdio.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>

static int ll_create(const struct landlock_ruleset_attr *a, size_t s, __u32 f)
{ return syscall(__NR_landlock_create_ruleset, a, s, f); }
static int ll_add(int fd, enum landlock_rule_type t, const void *a, __u32 f)
{ return syscall(__NR_landlock_add_rule, fd, t, a, f); }
static int ll_self(int fd, __u32 f)
{ return syscall(__NR_landlock_restrict_self, fd, f); }

#define RW (LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE)

int main(int argc, char **argv)
{
	const char *grant = argv[1];		/* path to allow, or "-" for none */
	struct landlock_ruleset_attr rsa = { .handled_access_fs = RW };
	int rs = ll_create(&rsa, sizeof(rsa), 0);
	mqd_t mq;
	int f;

	if (rs < 0) { perror("create_ruleset"); return 1; }

	if (strcmp(grant, "-") != 0) {
		struct landlock_path_beneath_attr pb = { .allowed_access = RW };
		pb.parent_fd = open(grant, O_PATH | O_CLOEXEC);
		if (pb.parent_fd < 0) { perror(grant); return 1; }
		if (ll_add(rs, LANDLOCK_RULE_PATH_BENEATH, &pb, 0)) {
			perror("add_rule"); return 1;
		}
		close(pb.parent_fd);
	}

	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("nnp"); return 1; }
	if (ll_self(rs, 0)) { perror("restrict_self"); return 1; }

	printf("granted=%-12s ", grant);

	/* sanity: a normal file open, to prove the rule itself works */
	f = open("/etc/hostname", O_RDONLY);
	printf("open(/etc/hostname)=%-14s ",
	       f >= 0 ? "OK" : strerror(errno));
	if (f >= 0) close(f);

	mq = mq_open("/foobar", O_CREAT | O_RDWR, 0600, NULL);
	printf("mq_open()=%s\n", mq != (mqd_t)-1 ? "OK" : strerror(errno));
	if (mq != (mqd_t)-1) mq_close(mq);
	return 0;
}
---



More information about the Linux-security-module-archive mailing list