Hi Günther, > Date: 2026-10-28 07:19:28+0100 > From: Günther Noack > > Hello Alejandro! > > On Tue, Oct 27, 2026 at 11:59:15PM +0100, Alejandro Colomar wrote: > > > Date: 2026-10-27 23:30:59+0100 > > > From: Günther Noack > > > On Tue, Oct 27, 2026 at 10:46:14PM +0100, Alejandro Colomar wrote: > > > > > Date: 2026-10-27 09:54:51+0100 > > > > > From: Günther Noack > > > > > > > > > > On Mon, Oct 26, 2026 at 11:41:13PM +0100, Günther Noack wrote: > > > > > > I'm still leaning towards documenting it as a buffer with > > > > > > implementation-defined contents which are provided by a LSM. How > > > > > > these buffer contents are interpreted is depending on the LSM in use > > > > > > anyway. > > > > > > > > > > To make a more concrete and constructive wording proposal: > > > > > > > > > > > > > > > SCM_SECURITY > > > > > > > > > > Receive the security context (the security label) of the peer > > > > > socket, as provided by the active Linux Security Module (LSM). The > > > > > received ancillary data is a byte buffer. > > > > > > > > > > The exact format of the security context buffer is defined by the > > > > > active major LSM. For example, SELinux returns a SELinux label as a > > > > > string (including a terminating null byte). > > > > > > > > Let's pause the discussion of the specific text for now. > > > > > > > > I have questions about the exact format used by each LSM. For example, > > > > you say that SELinux guarantees a string. Does it count the '\0' as > > > > part of the data size? Or is it guaranteed to exist but not counted? > > > > > > > > Same question for the other LSMs. > > > > > > Yes, SELinux counts the '\0' as part of the buffer size for the > > > SCM_SECURITY security context. > > > > Ok. > > > > > > > > Examples: > > > * If the label is "foo", it'll return {'f', 'o', 'o', '\0'} with payload size 4. > > > * If the reader calls recvmsg() but preallocates too little space in > > > the msg_control buffer, this can get truncated though, and then it > > > won't end with '\0': > > > {'e', 'x', 'a', 'm', 'p'} with payload size 5 (truncated) > > > > Ouch! So, no string guarantees here either, actually. > > Correct. Callers have to deal with the possibility of truncation, > which strips away the null byte. Is this true for every LSM? Do any LSMs guarantee a string even under truncation? > > > Other LSMs: > > > > > > * Smack excludes the null byte for SCM_SECURITY (smack_to_secctx()) > > > (but irritatingly it does count the null byte when a label is > > > returned through SO_PEERSEC (smack_socket_getpeersec_stream()). > > > Both functions are in security/smack/smack_lsm.c. > > > > And as we've seen, no string guarantees, IIUC. > > Correct. > > > > > > > * AppArmor excludes the null byte for SCM_SECURITY as well. > > > Implementation is in apparmor_label_to_secctx(), where it populates > > > the struct lsm_context *cp using: > > > > > > len = aa_label_asxprint(&cp->context...) > > > > > > and then sets > > > > > > cp->len = len; > > > > > > The function aa_label_asxprint() returns the length without trailing > > > null byte, as can be seen in its implementation. > > > > How does it behave if there's not enough space? Does AppArmor guarantee > > a string? > > The truncation case always strips off the null byte at the end of the > buffer. This is handled **independent of the LSM** in the common > net/core/scm.c layer one level above - it *always* kicks in when > truncation happens. Hmmmm. I believe that layer should guarantee a null byte when it truncates the data. It should be like strscpy(), which guarantees a correct string even on truncation. This seems to be another bug. > To sum it all up in a table: The only case where the null byte is > included in the buffer is in SELinux, when the generic SCM layer does > not need to do truncation: > > normal case truncation case > -------------------------------------------------------------- > SELinux has trailing null byte no trailing null byte > AppArmor no trailing null byte no trailing null byte > Smack no trailing null byte no trailing null byte > > (other LSMs don't have the feature at all) Thanks for the table! This seems to me to be 3 bugs: one in AppArmor, the same one in Smack, and one in the upper layer which corrupts the string when truncating. I wonder if we can do better in the truncation case, or if it's too late for that. Would you mind CCing the maintainers of the upper layer in net/core/scm.c? Have a lovely day! Alex > > –Günther --