[RFC PATCH v2 30/41] ipc: add IPC_STAT_R and IPC_SET_R
Jan Koester
jan.koester at tuxist.de
Wed Oct 21 03:15:50 UTC 2026
The ids of SysV message queues, semaphore sets and shared memory
segments reach userspace in struct ipc64_perm, 32 bits each, so a UUID
or GUID owner shows up as the overflow id and can't be set at all.
Rather than doubling every *id64_ds, add two commands shared by
msgctl(), semctl() and shmctl() that work on a struct ipc_perm_r with
key, mode, and uid, gid, cuid and cgid as __kernel_uid_r_t:
- IPC_STAT_R reads it, with the permission checks of IPC_STAT,
- IPC_SET_R sets uid, gid and mode like IPC_SET does (a message queue
keeps its size).
The IPC_SET path now works on the kernel ids of a struct ipc_set_ids,
which the classic command fills from its ipc64_perm. The audit record
of IPC_SET has the new owner as a kuid as well and logs it like the
other audit ids, in the initial user namespace.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Jan Koester <jan.koester at tuxist.de>
---
include/linux/audit.h | 8 +--
include/uapi/linux/ipc.h | 17 ++++++
ipc/msg.c | 40 ++++++++++----
ipc/sem.c | 31 ++++++++---
ipc/shm.c | 32 ++++++++---
ipc/util.c | 112 +++++++++++++++++++++++++++++++++++----
ipc/util.h | 23 +++++++-
kernel/audit.h | 4 +-
kernel/auditsc.c | 8 +--
9 files changed, 226 insertions(+), 49 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 45abb3722d..a769f04e45 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -428,7 +428,7 @@ static inline void audit_ptrace(struct task_struct *t)
/* Private API (for audit.c only) */
extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
-extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
+extern void __audit_ipc_set_perm(unsigned long qbytes, kuid_t uid, kgid_t gid, umode_t mode);
extern void __audit_bprm(struct linux_binprm *bprm);
extern int __audit_socketcall(int nargs, unsigned long *args);
extern int __audit_sockaddr(int len, void *addr);
@@ -460,7 +460,7 @@ static inline void audit_fd_pair(int fd1, int fd2)
if (unlikely(!audit_dummy_context()))
__audit_fd_pair(fd1, fd2);
}
-static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode)
+static inline void audit_ipc_set_perm(unsigned long qbytes, kuid_t uid, kgid_t gid, umode_t mode)
{
if (unlikely(!audit_dummy_context()))
__audit_ipc_set_perm(qbytes, uid, gid, mode);
@@ -652,8 +652,8 @@ static inline void audit_seccomp_actions_logged(const char *names,
{ }
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{ }
-static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid,
- gid_t gid, umode_t mode)
+static inline void audit_ipc_set_perm(unsigned long qbytes, kuid_t uid,
+ kgid_t gid, umode_t mode)
{ }
static inline void audit_bprm(struct linux_binprm *bprm)
{ }
diff --git a/include/uapi/linux/ipc.h b/include/uapi/linux/ipc.h
index 5995fc9d67..e927564fbb 100644
--- a/include/uapi/linux/ipc.h
+++ b/include/uapi/linux/ipc.h
@@ -3,6 +3,7 @@
#define _UAPI_LINUX_IPC_H
#include <linux/types.h>
+#include <linux/uidgid_r.h>
#define IPC_PRIVATE ((__kernel_key_t) 0)
@@ -40,6 +41,22 @@ struct ipc_perm
#define IPC_SET 1 /* set ipc_perm options */
#define IPC_STAT 2 /* get ipc_perm options */
#define IPC_INFO 3 /* see ipcs */
+#define IPC_SET_R 21 /* set uid, gid and mode from struct ipc_perm_r */
+#define IPC_STAT_R 22 /* get struct ipc_perm_r */
+
+/*
+ * The ids and mode of an ipc object for IPC_STAT_R and IPC_SET_R, which
+ * also hold UUIDs and GUIDs; IPC_SET_R uses uid, gid and mode. The other
+ * attributes of the object come from IPC_STAT.
+ */
+struct ipc_perm_r {
+ __kernel_key_t key;
+ __u32 mode;
+ __kernel_uid_r_t uid;
+ __kernel_gid_r_t gid;
+ __kernel_uid_r_t cuid;
+ __kernel_gid_r_t cgid;
+};
/*
* Version flags for semctl, msgctl, and shmctl commands
diff --git a/ipc/msg.c b/ipc/msg.c
index 62996b97f0..a3f5287e54 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -398,8 +398,10 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
* to be held in write mode.
* NOTE: no locks must be held, the rwsem is taken inside this function.
*/
+/* IPC_SET_R is IPC_SET without a new queue size */
static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
- struct ipc64_perm *perm, int msg_qbytes)
+ const struct ipc_set_ids *set, int msg_qbytes,
+ bool set_qbytes)
{
struct kern_ipc_perm *ipcp;
struct msg_queue *msq;
@@ -409,7 +411,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
rcu_read_lock();
ipcp = ipcctl_obtain_check(ns, &msg_ids(ns), msqid, cmd,
- perm, msg_qbytes);
+ set, msg_qbytes);
if (IS_ERR(ipcp)) {
err = PTR_ERR(ipcp);
goto out_unlock1;
@@ -431,18 +433,19 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
{
DEFINE_WAKE_Q(wake_q);
- if (msg_qbytes > ns->msg_ctlmnb &&
+ if (set_qbytes && msg_qbytes > ns->msg_ctlmnb &&
!capable(CAP_SYS_RESOURCE)) {
err = -EPERM;
goto out_unlock1;
}
ipc_lock_object(&msq->q_perm);
- err = ipc_update_perm(perm, ipcp);
+ err = ipc_update_perm(set, ipcp);
if (err)
goto out_unlock0;
- msq->q_qbytes = msg_qbytes;
+ if (set_qbytes)
+ msq->q_qbytes = msg_qbytes;
msq->q_ctime = ktime_get_real_seconds();
/*
@@ -598,6 +601,7 @@ static long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf, int ver
{
struct ipc_namespace *ns;
struct msqid64_ds msqid64;
+ struct ipc_set_ids set;
int err;
if (msqid < 0 || cmd < 0)
@@ -628,10 +632,17 @@ static long ksys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf, int ver
case IPC_SET:
if (copy_msqid_from_user(&msqid64, buf, version))
return -EFAULT;
- return msgctl_down(ns, msqid, cmd, &msqid64.msg_perm,
- msqid64.msg_qbytes);
+ ipc64_perm_to_set_ids(&msqid64.msg_perm, &set);
+ return msgctl_down(ns, msqid, cmd, &set, msqid64.msg_qbytes, true);
+ case IPC_SET_R:
+ if (ipc_perm_r_to_set_ids((void __user *)buf, &set))
+ return -EFAULT;
+ return msgctl_down(ns, msqid, IPC_SET, &set, 0, false);
+ case IPC_STAT_R:
+ return ipc_stat_r(ns, &msg_ids(ns), msqid,
+ security_msg_queue_msgctl, (void __user *)buf);
case IPC_RMID:
- return msgctl_down(ns, msqid, cmd, NULL, 0);
+ return msgctl_down(ns, msqid, cmd, NULL, 0, false);
default:
return -EINVAL;
}
@@ -734,6 +745,7 @@ static long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr, int versio
struct ipc_namespace *ns;
int err;
struct msqid64_ds msqid64;
+ struct ipc_set_ids set;
ns = current->nsproxy->ipc_ns;
@@ -763,9 +775,17 @@ static long compat_ksys_msgctl(int msqid, int cmd, void __user *uptr, int versio
case IPC_SET:
if (copy_compat_msqid_from_user(&msqid64, uptr, version))
return -EFAULT;
- return msgctl_down(ns, msqid, cmd, &msqid64.msg_perm, msqid64.msg_qbytes);
+ ipc64_perm_to_set_ids(&msqid64.msg_perm, &set);
+ return msgctl_down(ns, msqid, cmd, &set, msqid64.msg_qbytes, true);
+ case IPC_SET_R:
+ if (ipc_perm_r_to_set_ids(uptr, &set))
+ return -EFAULT;
+ return msgctl_down(ns, msqid, IPC_SET, &set, 0, false);
+ case IPC_STAT_R:
+ return ipc_stat_r(ns, &msg_ids(ns), msqid,
+ security_msg_queue_msgctl, uptr);
case IPC_RMID:
- return msgctl_down(ns, msqid, cmd, NULL, 0);
+ return msgctl_down(ns, msqid, cmd, NULL, 0, false);
default:
return -EINVAL;
}
diff --git a/ipc/sem.c b/ipc/sem.c
index 5ec41de7e8..ab456991e4 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1599,7 +1599,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
* NOTE: no locks must be held, the rwsem is taken inside this function.
*/
static int semctl_down(struct ipc_namespace *ns, int semid,
- int cmd, struct semid64_ds *semid64)
+ int cmd, const struct ipc_set_ids *set)
{
struct sem_array *sma;
int err;
@@ -1608,8 +1608,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
down_write(&sem_ids(ns).rwsem);
rcu_read_lock();
- ipcp = ipcctl_obtain_check(ns, &sem_ids(ns), semid, cmd,
- &semid64->sem_perm, 0);
+ ipcp = ipcctl_obtain_check(ns, &sem_ids(ns), semid, cmd, set, 0);
if (IS_ERR(ipcp)) {
err = PTR_ERR(ipcp);
goto out_unlock1;
@@ -1629,7 +1628,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
goto out_up;
case IPC_SET:
sem_lock(sma, NULL, -1);
- err = ipc_update_perm(&semid64->sem_perm, ipcp);
+ err = ipc_update_perm(set, ipcp);
if (err)
goto out_unlock0;
sma->sem_ctime = ktime_get_real_seconds();
@@ -1653,6 +1652,7 @@ static long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg, int v
struct ipc_namespace *ns;
void __user *p = (void __user *)arg;
struct semid64_ds semid64;
+ struct ipc_set_ids set;
int err;
if (semid < 0)
@@ -1694,9 +1694,16 @@ static long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg, int v
case IPC_SET:
if (copy_semid_from_user(&semid64, p, version))
return -EFAULT;
- fallthrough;
+ ipc64_perm_to_set_ids(&semid64.sem_perm, &set);
+ return semctl_down(ns, semid, cmd, &set);
+ case IPC_SET_R:
+ if (ipc_perm_r_to_set_ids(p, &set))
+ return -EFAULT;
+ return semctl_down(ns, semid, IPC_SET, &set);
+ case IPC_STAT_R:
+ return ipc_stat_r(ns, &sem_ids(ns), semid, security_sem_semctl, p);
case IPC_RMID:
- return semctl_down(ns, semid, cmd, &semid64);
+ return semctl_down(ns, semid, cmd, NULL);
default:
return -EINVAL;
}
@@ -1776,6 +1783,7 @@ static long compat_ksys_semctl(int semid, int semnum, int cmd, int arg, int vers
void __user *p = compat_ptr(arg);
struct ipc_namespace *ns;
struct semid64_ds semid64;
+ struct ipc_set_ids set;
int err;
ns = current->nsproxy->ipc_ns;
@@ -1808,9 +1816,16 @@ static long compat_ksys_semctl(int semid, int semnum, int cmd, int arg, int vers
case IPC_SET:
if (copy_compat_semid_from_user(&semid64, p, version))
return -EFAULT;
- fallthrough;
+ ipc64_perm_to_set_ids(&semid64.sem_perm, &set);
+ return semctl_down(ns, semid, cmd, &set);
+ case IPC_SET_R:
+ if (ipc_perm_r_to_set_ids(p, &set))
+ return -EFAULT;
+ return semctl_down(ns, semid, IPC_SET, &set);
+ case IPC_STAT_R:
+ return ipc_stat_r(ns, &sem_ids(ns), semid, security_sem_semctl, p);
case IPC_RMID:
- return semctl_down(ns, semid, cmd, &semid64);
+ return semctl_down(ns, semid, cmd, NULL);
default:
return -EINVAL;
}
diff --git a/ipc/shm.c b/ipc/shm.c
index bb1a721a3e..33f30941c2 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -993,7 +993,7 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
* NOTE: no locks must be held, the rwsem is taken inside this function.
*/
static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
- struct shmid64_ds *shmid64)
+ const struct ipc_set_ids *set)
{
struct kern_ipc_perm *ipcp;
struct shmid_kernel *shp;
@@ -1002,8 +1002,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
down_write(&shm_ids(ns).rwsem);
rcu_read_lock();
- ipcp = ipcctl_obtain_check(ns, &shm_ids(ns), shmid, cmd,
- &shmid64->shm_perm, 0);
+ ipcp = ipcctl_obtain_check(ns, &shm_ids(ns), shmid, cmd, set, 0);
if (IS_ERR(ipcp)) {
err = PTR_ERR(ipcp);
goto out_unlock1;
@@ -1023,7 +1022,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
goto out_up;
case IPC_SET:
ipc_lock_object(&shp->shm_perm);
- err = ipc_update_perm(&shmid64->shm_perm, ipcp);
+ err = ipc_update_perm(set, ipcp);
if (err)
goto out_unlock0;
shp->shm_ctim = ktime_get_real_seconds();
@@ -1246,6 +1245,7 @@ static long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf, int ver
int err;
struct ipc_namespace *ns;
struct shmid64_ds sem64;
+ struct ipc_set_ids set;
if (cmd < 0 || shmid < 0)
return -EINVAL;
@@ -1284,9 +1284,17 @@ static long ksys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf, int ver
case IPC_SET:
if (copy_shmid_from_user(&sem64, buf, version))
return -EFAULT;
- fallthrough;
+ ipc64_perm_to_set_ids(&sem64.shm_perm, &set);
+ return shmctl_down(ns, shmid, cmd, &set);
+ case IPC_SET_R:
+ if (ipc_perm_r_to_set_ids((void __user *)buf, &set))
+ return -EFAULT;
+ return shmctl_down(ns, shmid, IPC_SET, &set);
+ case IPC_STAT_R:
+ return ipc_stat_r(ns, &shm_ids(ns), shmid, security_shm_shmctl,
+ (void __user *)buf);
case IPC_RMID:
- return shmctl_down(ns, shmid, cmd, &sem64);
+ return shmctl_down(ns, shmid, cmd, NULL);
case SHM_LOCK:
case SHM_UNLOCK:
return shmctl_do_lock(ns, shmid, cmd);
@@ -1440,6 +1448,7 @@ static long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr, int versio
{
struct ipc_namespace *ns;
struct shmid64_ds sem64;
+ struct ipc_set_ids set;
int err;
ns = current->nsproxy->ipc_ns;
@@ -1479,9 +1488,16 @@ static long compat_ksys_shmctl(int shmid, int cmd, void __user *uptr, int versio
case IPC_SET:
if (copy_compat_shmid_from_user(&sem64, uptr, version))
return -EFAULT;
- fallthrough;
+ ipc64_perm_to_set_ids(&sem64.shm_perm, &set);
+ return shmctl_down(ns, shmid, cmd, &set);
+ case IPC_SET_R:
+ if (ipc_perm_r_to_set_ids(uptr, &set))
+ return -EFAULT;
+ return shmctl_down(ns, shmid, IPC_SET, &set);
+ case IPC_STAT_R:
+ return ipc_stat_r(ns, &shm_ids(ns), shmid, security_shm_shmctl, uptr);
case IPC_RMID:
- return shmctl_down(ns, shmid, cmd, &sem64);
+ return shmctl_down(ns, shmid, cmd, NULL);
case SHM_LOCK:
case SHM_UNLOCK:
return shmctl_do_lock(ns, shmid, cmd);
diff --git a/ipc/util.c b/ipc/util.c
index 1737d776bc..bc4df56193 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -681,28 +681,117 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
* @in: the permission given as input.
* @out: the permission of the ipc to set.
*/
-int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
+int ipc_update_perm(const struct ipc_set_ids *in, struct kern_ipc_perm *out)
{
- kuid_t uid = make_kuid(current_user_ns(), in->uid);
- kgid_t gid = make_kgid(current_user_ns(), in->gid);
- if (!uid_valid(uid) || !gid_valid(gid))
- return -EINVAL;
+ if (in->err)
+ return in->err;
- out->uid = uid;
- out->gid = gid;
+ out->uid = in->uid;
+ out->gid = in->gid;
out->mode = (out->mode & ~S_IRWXUGO)
| (in->mode & S_IRWXUGO);
return 0;
}
+/**
+ * ipc64_perm_to_set_ids - the IPC_SET ids and mode of a classic ipc64_perm
+ * @in: user permissions
+ * @out: kernel ids and mode, -EINVAL in @out->err if an id is invalid
+ */
+void ipc64_perm_to_set_ids(const struct ipc64_perm *in, struct ipc_set_ids *out)
+{
+ out->uid = make_kuid(current_user_ns(), in->uid);
+ out->gid = make_kgid(current_user_ns(), in->gid);
+ out->mode = in->mode;
+ out->err = uid_valid(out->uid) && gid_valid(out->gid) ? 0 : -EINVAL;
+}
+
+/**
+ * ipc_perm_r_to_set_ids - the IPC_SET_R ids and mode of a struct ipc_perm_r
+ * @in: user permissions
+ * @out: kernel ids and mode, -EINVAL in @out->err if an id is invalid
+ *
+ * Return: 0 or -EFAULT.
+ */
+int ipc_perm_r_to_set_ids(const struct ipc_perm_r __user *in,
+ struct ipc_set_ids *out)
+{
+ struct ipc_perm_r perm;
+
+ if (copy_from_user(&perm, in, sizeof(perm)))
+ return -EFAULT;
+ out->uid = make_kuid_r(current_user_ns(), &perm.uid);
+ out->gid = make_kgid_r(current_user_ns(), &perm.gid);
+ out->mode = perm.mode;
+ out->err = uid_valid(out->uid) && gid_valid(out->gid) ? 0 : -EINVAL;
+ return 0;
+}
+
+/**
+ * ipc_stat_r - IPC_STAT_R of an ipc object
+ * @ns: ipc namespace
+ * @ids: the table of ids where to look for the object
+ * @id: the id of the object
+ * @security: the security hook of the object's kind, asked for IPC_STAT
+ * @buf: where to put the struct ipc_perm_r
+ *
+ * Return: 0 or a negative error code.
+ */
+int ipc_stat_r(struct ipc_namespace *ns, struct ipc_ids *ids, int id,
+ int (*security)(struct kern_ipc_perm *, int),
+ struct ipc_perm_r __user *buf)
+{
+ struct user_namespace *user_ns = current_user_ns();
+ struct kern_ipc_perm *ipcp;
+ struct ipc_perm_r perm;
+ int err;
+
+ memset(&perm, 0, sizeof(perm));
+ rcu_read_lock();
+ ipcp = ipc_obtain_object_check(ids, id);
+ if (IS_ERR(ipcp)) {
+ err = PTR_ERR(ipcp);
+ goto out_unlock;
+ }
+
+ err = -EACCES;
+ if (ipcperms(ns, ipcp, S_IRUGO))
+ goto out_unlock;
+
+ err = security(ipcp, IPC_STAT);
+ if (err)
+ goto out_unlock;
+
+ ipc_lock_object(ipcp);
+ if (!ipc_valid_object(ipcp)) {
+ ipc_unlock_object(ipcp);
+ err = -EIDRM;
+ goto out_unlock;
+ }
+ perm.key = ipcp->key;
+ perm.mode = ipcp->mode;
+ from_kuid_r_munged(user_ns, ipcp->uid, &perm.uid);
+ from_kgid_r_munged(user_ns, ipcp->gid, &perm.gid);
+ from_kuid_r_munged(user_ns, ipcp->cuid, &perm.cuid);
+ from_kgid_r_munged(user_ns, ipcp->cgid, &perm.cgid);
+ ipc_unlock_object(ipcp);
+ rcu_read_unlock();
+
+ return copy_to_user(buf, &perm, sizeof(perm)) ? -EFAULT : 0;
+
+out_unlock:
+ rcu_read_unlock();
+ return err;
+}
+
/**
* ipcctl_obtain_check - retrieve an ipc object and check permissions
* @ns: ipc namespace
* @ids: the table of ids where to look for the ipc
* @id: the id of the ipc to retrieve
* @cmd: the cmd to check
- * @perm: the permission to set
+ * @set: the ids and mode to set
* @extra_perm: one extra permission parameter used by msq
*
* This function does some common audit and permissions check for some IPC_XXX
@@ -718,7 +807,8 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
*/
struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
struct ipc_ids *ids, int id, int cmd,
- struct ipc64_perm *perm, int extra_perm)
+ const struct ipc_set_ids *set,
+ int extra_perm)
{
kuid_t euid;
int err = -EPERM;
@@ -732,8 +822,8 @@ struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
audit_ipc_obj(ipcp);
if (cmd == IPC_SET)
- audit_ipc_set_perm(extra_perm, perm->uid,
- perm->gid, perm->mode);
+ audit_ipc_set_perm(extra_perm, set->uid,
+ set->gid, set->mode);
euid = current_euid();
if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) ||
diff --git a/ipc/util.h b/ipc/util.h
index a55d6cebe6..b0d57f4e64 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -177,10 +177,29 @@ struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id);
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
-int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
+
+/*
+ * The new owner, group and mode of IPC_SET/IPC_SET_R. @err is an error of
+ * their conversion, reported once the object has been found.
+ */
+struct ipc_set_ids {
+ kuid_t uid;
+ kgid_t gid;
+ umode_t mode;
+ int err;
+};
+
+void ipc64_perm_to_set_ids(const struct ipc64_perm *in, struct ipc_set_ids *out);
+int ipc_perm_r_to_set_ids(const struct ipc_perm_r __user *in,
+ struct ipc_set_ids *out);
+int ipc_update_perm(const struct ipc_set_ids *in, struct kern_ipc_perm *out);
struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,
struct ipc_ids *ids, int id, int cmd,
- struct ipc64_perm *perm, int extra_perm);
+ const struct ipc_set_ids *set,
+ int extra_perm);
+int ipc_stat_r(struct ipc_namespace *ns, struct ipc_ids *ids, int id,
+ int (*security)(struct kern_ipc_perm *, int),
+ struct ipc_perm_r __user *buf);
static inline void ipc_update_pid(struct pid **pos, struct pid *pid)
{
diff --git a/kernel/audit.h b/kernel/audit.h
index 92d5e723d5..6195f13882 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -168,8 +168,8 @@ struct audit_context {
umode_t mode;
struct lsm_prop oprop;
int has_perm;
- uid_t perm_uid;
- gid_t perm_gid;
+ kuid_t perm_uid;
+ kgid_t perm_gid;
umode_t perm_mode;
unsigned long qbytes;
} ipc;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 08d8f5af46..9abe0615a1 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1395,10 +1395,10 @@ static void show_special(struct audit_context *context, int *call_panic)
if (unlikely(!ab))
return;
audit_log_format(ab,
- "qbytes=%lx ouid=%u ogid=%u mode=%#ho",
+ "qbytes=%lx ouid=%s ogid=%s mode=%#ho",
context->ipc.qbytes,
- context->ipc.perm_uid,
- context->ipc.perm_gid,
+ KUID_STR(context->ipc.perm_uid),
+ KGID_STR(context->ipc.perm_gid),
context->ipc.perm_mode);
}
break;
@@ -2585,7 +2585,7 @@ void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
*
* Called only after audit_ipc_obj().
*/
-void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode)
+void __audit_ipc_set_perm(unsigned long qbytes, kuid_t uid, kgid_t gid, umode_t mode)
{
struct audit_context *context = audit_context();
--
2.56.0
More information about the Linux-security-module-archive
mailing list