mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 23:59:33 -04:00
Right now if some LSM such as Smack denies an AF_UNIX socket peer to receive an SCM_RIGHTS fd, the SCM_RIGHTS fd array will be cut short at that point, and MSG_CTRUNC is set on return of recvmsg(). This is highly problematic behaviour, because it leaves the receiver wondering what happened. As per man page MSG_CTRUNC is supposed to indicate that the control buffer was sized too short, but suddenly a permission error might result in the exact same flag being set. Moreover, the receiver has no chance to determine how many fds got originally sent and how many were suppressed.[1] Add a SO_RIGHTS_NOTRUNC option to UNIX sockets to enable more useful handling of LSM denials when receiving SCM_RIGHTS messages: instead of truncating the message at the first blocked fd, keep every fd slot and store the LSM errno in the blocked slot. The socket option is inherited by the child accept() socket if set on the listen() socket. [1]: https://github.com/uapi-group/kernel-features#useful-handling-of-lsm-denials-on-scm_rights Reviewed-by: Christian Brauner (Amutable) <brauner@kernel.org> Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl> Link: https://patch.msgid.link/20260813162818.149248-4-jkoolstra@xs4all.nl Signed-off-by: Jakub Kicinski <kuba@kernel.org>
65 lines
1.4 KiB
C
65 lines
1.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __LINUX_NET_AFUNIX_H
|
|
#define __LINUX_NET_AFUNIX_H
|
|
|
|
#include <linux/atomic.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/net.h>
|
|
#include <linux/path.h>
|
|
#include <linux/refcount.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/wait.h>
|
|
#include <net/sock.h>
|
|
#include <uapi/linux/un.h>
|
|
|
|
#if IS_ENABLED(CONFIG_UNIX)
|
|
struct unix_sock *unix_get_socket(struct file *filp);
|
|
#else
|
|
static inline struct unix_sock *unix_get_socket(struct file *filp)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
struct unix_address {
|
|
refcount_t refcnt;
|
|
int len;
|
|
struct sockaddr_un name[];
|
|
};
|
|
|
|
struct scm_stat {
|
|
atomic_t nr_fds;
|
|
unsigned long nr_unix_fds;
|
|
};
|
|
|
|
/* The AF_UNIX socket */
|
|
struct unix_sock {
|
|
/* WARNING: sk has to be the first member */
|
|
struct sock sk;
|
|
struct unix_address *addr;
|
|
struct path path;
|
|
struct mutex iolock, bindlock;
|
|
struct sock *peer;
|
|
struct sock *listener;
|
|
struct unix_vertex *vertex;
|
|
spinlock_t lock;
|
|
struct socket_wq peer_wq;
|
|
#define peer_wait peer_wq.wait
|
|
wait_queue_entry_t peer_wake;
|
|
struct scm_stat scm_stat;
|
|
int inq_len;
|
|
bool recvmsg_inq;
|
|
bool scm_rights_notrunc;
|
|
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
|
|
struct sk_buff *oob_skb;
|
|
#endif
|
|
};
|
|
|
|
#define unix_sk(ptr) container_of_const(ptr, struct unix_sock, sk)
|
|
#define unix_peer(sk) (unix_sk(sk)->peer)
|
|
|
|
#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
|
|
#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
|
|
|
|
#endif
|