smack: fix incorrect task context in smack_msg_queue_msgrcv

The smack_msg_queue_msgrcv() function incorrectly checks
the permissions of the 'current' task instead of the
'target' task.

In the msgsnd() syscall path, if a receiver is already waiting,
the pipelined_send() optimization is used to push the message
directly to the receiver task:

    ipc/msg.c`pipelined_send():
    ` smp_store_release(&msr->r_msg, msg)

In this case, the 'sender' (current) task performs the check
on behalf of the 'receiver' task (msr->r_tsk, passed as the
'target' parameter):

  ipc/msg.c`pipelined_send():
  ` security_msg_queue_msgrcv(,, target := msr->r_tsk,,)

However, smack_msg_queue_msgrcv() ignores the 'target' and
checks 'current':

  smack_msg_queue_msgrcv(…)
  ` smk_curacc_msq(isp, MAY_READWRITE); // current task

'current' MAY satisfy smack_msg_queue_msgrcv r/w requirement,
but 'target' (the receiver task) might NOT;
as a result, an unauthorized receiver gets the message,
violating MAC policy.

Test:
1) create a sysv message queue with label “foo”
2) echo "bar foo r" >/smack/load2
3) msgrcv(,,,0,MSG_NOERROR) in "bar"-labeled task.
    The task is waiting for the messages ...
4) msgsnd() from a "foo"-labeled task:
"bar"-labeled task gets the message.

This patch fixes the issue by checking permission on the
'target' task instead of 'current'.

(2008-02-04, Casey Schaufler)
Fixes: e114e47377 ("Smack: Simplified Mandatory Access Control Kernel")

Signed-off-by: Konstantin Andreev <andreev@swemel.ru>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
This commit is contained in:
Konstantin Andreev
2026-05-11 03:17:16 +03:00
committed by Casey Schaufler
parent 3cef22655c
commit fba3d32825

View File

@@ -130,12 +130,13 @@ static int smk_bu_note(char *note, struct smack_known *sskp,
#define smk_bu_note(note, sskp, oskp, mode, RC) (RC)
#endif
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_current(char *note, struct smack_known *oskp,
int mode, int rc)
static int
smk_bu_tsk_to_obj(struct task_struct *tsk, const struct task_smack *tsp,
char *note, struct smack_known *oskp, int mode, int rc)
{
struct task_smack *tsp = smack_cred(current_cred());
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
char acc[SMK_NUM_ACCESS_TYPE + 1];
char comm[TASK_COMM_LEN];
if (rc <= 0)
return rc;
@@ -143,14 +144,22 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
rc = 0;
smk_bu_mode(mode, acc);
pr_info("Smack %s: (%s %s %s) %s %s\n", smk_bu_mess[rc],
tsp->smk_task->smk_known, oskp->smk_known,
acc, current->comm, note);
smk_of_task(tsp)->smk_known, oskp->smk_known,
acc, get_task_comm(comm, tsk), note);
return 0;
}
#else
#define smk_bu_current(note, oskp, mode, RC) (RC)
return rc;
#endif
}
static int smk_bu_current(char *note, struct smack_known *oskp,
int mode, int rc)
{
return smk_bu_tsk_to_obj(current, smack_cred(current_cred()),
note, oskp, mode, rc);
}
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_task(struct task_struct *otp, int mode, int rc)
@@ -3353,14 +3362,20 @@ static int smack_sem_semop(struct kern_ipc_perm *isp, struct sembuf *sops,
}
/**
* smk_curacc_msq : helper to check if current has access on msq
* @isp : the msq
* smk_tskacc_msq : helper to check if tsk has access on msq
* @tsk: the task that requests access
* @isp : the sysv msg queue permissions
* @access : access requested
*
* return 0 if current has access, error otherwise
* return 0 if tsk has access, error otherwise
*/
static int smk_curacc_msq(struct kern_ipc_perm *isp, int access)
static int
smk_tskacc_msq(struct task_struct *tsk, struct kern_ipc_perm *isp, int access)
{
const bool tsk_is_current = (tsk == current);
const struct cred * const tsk_cred =
(tsk_is_current ? current_cred() : get_task_cred(tsk));
struct task_smack * const tsp = smack_cred(tsk_cred);
struct smack_known *msp = smack_of_ipc(isp);
struct smk_audit_info ad;
int rc;
@@ -3369,11 +3384,25 @@ static int smk_curacc_msq(struct kern_ipc_perm *isp, int access)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = isp->id;
#endif
rc = smk_curacc(msp, access, &ad);
rc = smk_bu_current("msq", msp, access, rc);
rc = smk_tskacc(tsp, msp, access, &ad);
rc = smk_bu_tsk_to_obj(tsk, tsp, "msq", msp, access, rc);
if (!tsk_is_current)
put_cred(tsk_cred);
return rc;
}
/**
* smk_curacc_msq : helper to check if current has access on msq
* @isp : the sysv msg queue permissions
* @access : access requested
*
* return 0 if current has access, error otherwise
*/
static int smk_curacc_msq(struct kern_ipc_perm *isp, int access)
{
return smk_tskacc_msq(current, isp, access);
}
/**
* smack_msg_queue_associate - Smack access check for msg_queue
* @isp: the object
@@ -3441,21 +3470,21 @@ static int smack_msg_queue_msgsnd(struct kern_ipc_perm *isp, struct msg_msg *msg
}
/**
* smack_msg_queue_msgrcv - Smack access check for msg_queue
* smack_msg_queue_msgrcv - check it target has r/w access to msg_queue
* @isp: the object
* @msg: unused
* @target: unused
* @target: the task that msgrcv() from the queue
* @type: unused
* @mode: unused
*
* Returns 0 if current has read and write access, error code otherwise
* Returns 0 if target has read and write access, error code otherwise
*/
static int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp,
struct msg_msg *msg,
struct task_struct *target, long type,
int mode)
{
return smk_curacc_msq(isp, MAY_READWRITE);
return smk_tskacc_msq(target, isp, MAY_READWRITE);
}
/**