From: Alejandro Colomar <alx@kernel.org>
To: Casey Schaufler <casey@schaufler-ca.com>
Cc: "Günther Noack" <gnoack3000@gmail.com>,
linux-man@vger.kernel.org,
"Michael Kerrisk" <mtk.manpages@gmail.com>,
"Kuniyuki Iwashima" <kuniyu@google.com>
Subject: Re: [PATCH 4/7] man/man7/unix.7: SCM_SECURITY: Generalize to other LSMs, not just SELinux
Date: Tue, 27 Oct 2026 22:52:02 +0100 [thread overview]
Message-ID: <auEbrKeOiWeAS7D9@devuan> (raw)
In-Reply-To: <1bd4e8f9-28c5-4db8-bec6-35cd62643fda@schaufler-ca.com>
[-- Attachment #1: Type: text/plain, Size: 6650 bytes --]
Hi Casey,
> Date: 2026-10-27 09:32:57-0700
> From: Casey Schaufler <casey@schaufler-ca.com>
>
[...]
> >>>> This text, however, is saying that in some cases there might not be
> >>>> a '\0' at all.
> >>> The TL;DR is that the byte after the returned buffer's declared length
> >>> can't be trusted to be 0 - it is undefined and can be clobbered.
> >> Huh! This is to me a bug. Would you mind reporting them this as a bug
> >> and CCing me? I'd rather get this fixed in the kernel than documented
> >> as broken.
> >>
> >> Especially, if they use strlen(3) internally, this sounds very much like
> >> a kernel bug, but even if not, it is clearly a kernel bug.
> >>
> >> In any case, if we were to document this bug, we should not use the term
> >> string, because anything not containing a '\0' is not a string, by
> >> definition.
> > Casey, would you be able to confirm whether this constitutes a Smack
> > bug or is intentional?
>
> Inclusion of a null byte for C string interfaces has been a topic of
> debate since about 1980. At the time this code was written my understanding
> was that the data SCM_SECURITY returned could not be assumed to be a
> C string. Hence, the size of the data, not the size of a string. The
> null byte isn't considered a part of the string, as reported by strlen().
>
> So, the existing behavior is intentional, but I'm willing to have it
> considered a bug if (as of today) everyone thinks the data should include
> a null byte.
Yup, I think the issue of strings has more or less settled towards using
C strings everywhere, with other formats --such as fixed-width buffers
from utmp(5)-- being phased out. Most of libc takes C strings, and so
using C strings everywhere is safer, as it avoids having to manually
handle the bytes.
> > The TL;DR is that we came across the function smack_to_secctx() in
> > smack_lsm.c, which passes a Smack label string in a buffer without a
> > terminating null byte. This is inconsistent with what SELinux and
> > AppArmor do.
> >
> > Before we start explaining so many corner cases in the man pages, I
> > wanted to check -- is this something that Smack should fix, by
> > including the zero byte?
> >
> > I tried to double check the Smack userspace utilities but couldn't
> > find any use of SCM_SECURITY there. (Is the feature unused?)
>
> The Smack userspace utilities (github.com://smackteam/smack.git)
> represent a limited Smack system implementation. SCM_SECURITY is
> used in at least a couple of important embedded and enterprise
> implementations.
>
> >>> I have not read the full kernel implementation now, but it can already
> >>> be seen in userspace that that adjacent byte can belong to a different
> >>> data structue:
> >>>
> >>>
> >>> ## How control messages are represented
> >>>
> >>> The security context is returned to user space as a cmsghdr structure,
> >>> as described in cmsg(3), where it is returned as a buffer of length
> >>> cmsg_len:
> >>>
> >>> struct cmsghdr {
> >>> size_t cmsg_len; /* data byte count including header */
> >>> /* some other fields */
> >>>
> >>> /* followed by
> >>> unsigned char cmsg_data[]; */
> >>> };
> >>>
> >>> Reading beyond the declared cmsg_len is undefined, and callers don't
> >>> get any guarantees about the byte following the csmg_data[] buffer.
> >>>
> >>>
> >>> ## Iterating from userspace through multiple control messages
> >>>
> >>> Iterating through the cmsgs is done with the API described in cmsg(3),
> >>> CMSG_NXTHDR(). This is implemented as an inlined function in
> >>> /usr/include/bits/socket.h. The function does a bunch of validation
> >>> logic and then ends in this rather simple advancement logic:
> >>>
> >>> __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
> >>> + CMSG_ALIGN (__cmsg->cmsg_len));
> >>> return __cmsg;
> >>>
> >>> So, the cmsgs with their cmsg_data[] buffers are next to each other in
> >>> memory. They are aligned, but that still means that the byte after
> >>> cmsg_data[] might be part of the next cmsg header or beyond the list
> >>> of control messages.
> >>>
> >>> ---
> >>>
> >>>
> >>> The more I think about this, the more unsure I am that this is even
> >>> worth documenting. In the end, anyone reading and interpreting this
> >>> data probably needs to read the corresponding LSM anyway, and trailing
> >>> null bytes are probably the least of their worries...?
> >> Not only that it's worth documenting, but this might be a vulnerability.
> >>> Maybe it would be better to just say something like "The format of the
> >>> security context is determined by the LSM responsible for it". WDYT?
> >> I'm unwilling to accept a nonstring as a valid format, unless very good
> >> reasons are stated. And if those reasons are stated as "that ship
> >> sailed long ago", the way to document this might very well be BUGS.
> > Point taken and agreed that it would be better to call it a "buffer"
> > rather than a "string" when it does not have the null terminator.
> >
> > It does seem that this is used also outside of UNIX Domain Sockets:
> > IP_PASSSEC(2const) says:
> >
> > The security context returned in the SCM_SECURITY ancillary message
> > is of the same format as the one described in SO_PEERSEC(2const).
> >
> > And looking this format up in SO_PEERSEC(2const), we find:
> >
> > The security context string may include a terminating null character
> > in the returned length, but is not guaranteed to do so: a security
> > context "foo" might be represented as either {'f','o','o'} of length
> > 3 or {'f','o','o','\0'} of length 4, which are considered to be
> > interchangeable. The string is printable, does not contain non-
> > terminating null characters, and is in an unspecified encoding (in
> > particular, it is not guaranteed to be ASCII or UTF-8).
> >
> > So it seems that these "buffer" (not "string") semantics exist there
> > as well. Maybe it is intentional then that it is treated as a buffer
> > rather than a string?
>
> I'm easy. If there is a strong desire to make SCM_SECURITY a string
> Smack can be changed easily enough.
Yup. I think it'd be good to have guarantees that the label can be
passed to strlen(3). Whether the reported size includes the '\0' or
not, that's less important, but being able to pass the buffer to
strlen(3) and any other string functions is essential for safety, IMO.
Thank you very much!
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2026-10-27 21:52 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 21:22 [PATCH 0/7] unix.7: Socket Options and SCM_* fixes Günther Noack
2026-10-21 21:22 ` [PATCH 1/7] man/man7/unix.7: ERRORS: ETOOMANYREFS: Fix the conditions Günther Noack
2026-10-22 21:14 ` Alejandro Colomar
2026-10-23 16:50 ` Günther Noack
2026-10-24 4:45 ` Kuniyuki Iwashima
2026-10-21 21:22 ` [PATCH 2/7] man/man7/unix.7: Multiple same-typed SCM_* messages may be sent in one message Günther Noack
2026-10-22 21:28 ` Alejandro Colomar
2026-10-23 17:09 ` Günther Noack
2026-10-21 21:22 ` [PATCH 3/7] man/man7/unix.7: Autobind: Clarify when it happens, and mention SO_PASSPIDFD Günther Noack
2026-10-24 4:57 ` Kuniyuki Iwashima
2026-10-26 21:55 ` Günther Noack
2026-10-27 5:04 ` Kuniyuki Iwashima
2026-10-21 21:22 ` [PATCH 4/7] man/man7/unix.7: SCM_SECURITY: Generalize to other LSMs, not just SELinux Günther Noack
2026-10-23 9:57 ` Alejandro Colomar
2026-10-23 17:57 ` Günther Noack
2026-10-23 18:13 ` Alejandro Colomar
2026-10-26 22:41 ` Günther Noack
2026-10-27 8:54 ` Günther Noack
2026-10-27 21:46 ` Alejandro Colomar
2026-10-27 22:30 ` Günther Noack
2026-10-27 22:59 ` Alejandro Colomar
2026-10-28 6:19 ` Günther Noack
2026-10-28 12:45 ` Alejandro Colomar
2026-10-27 16:32 ` Casey Schaufler
2026-10-27 21:52 ` Alejandro Colomar [this message]
2026-10-21 21:22 ` [PATCH 5/7] man/man7/unix.7: SO_PASSSEC: wfix Günther Noack
2026-10-24 5:02 ` Kuniyuki Iwashima
2026-10-24 8:36 ` Alejandro Colomar
2026-10-26 22:42 ` Günther Noack
2026-10-27 5:05 ` Kuniyuki Iwashima
2026-10-21 21:22 ` [PATCH 6/7] man/man7/unix.7: Document SO_PASSPIDFD, SO_PEERPIDFD, and SCM_PIDFD Günther Noack
2026-10-24 5:22 ` Kuniyuki Iwashima
2026-10-26 23:02 ` Günther Noack
2026-10-27 5:06 ` Kuniyuki Iwashima
2026-10-21 21:22 ` [PATCH 7/7] man/man7/unix.7: Document SO_PASSRIGHTS Günther Noack
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=auEbrKeOiWeAS7D9@devuan \
--to=alx@kernel.org \
--cc=casey@schaufler-ca.com \
--cc=gnoack3000@gmail.com \
--cc=kuniyu@google.com \
--cc=linux-man@vger.kernel.org \
--cc=mtk.manpages@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox