Import of kernel-5.14.0-611.20.1.el9_7
This commit is contained in:
parent
e562c02649
commit
09329b4587
@ -12,7 +12,7 @@ RHEL_MINOR = 7
|
||||
#
|
||||
# Use this spot to avoid future merge conflicts.
|
||||
# Do not trim this comment.
|
||||
RHEL_RELEASE = 611.16.1
|
||||
RHEL_RELEASE = 611.20.1
|
||||
|
||||
#
|
||||
# ZSTREAM
|
||||
|
||||
@ -1447,6 +1447,14 @@ static __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
if (hdev->vendor == I2C_VENDOR_ID_GOODIX &&
|
||||
(hdev->product == I2C_DEVICE_ID_GOODIX_01E8 ||
|
||||
hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) {
|
||||
if (*size < 608) {
|
||||
dev_info(
|
||||
&hdev->dev,
|
||||
"GT7868Q fixup: report descriptor is only %u bytes, skipping\n",
|
||||
*size);
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
if (rdesc[607] == 0x15) {
|
||||
rdesc[607] = 0x25;
|
||||
dev_info(
|
||||
|
||||
@ -3526,8 +3526,64 @@ static int partition_tape(struct scsi_tape *STp, int size)
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handles any extra state needed for ioctls which are not st-specific.
|
||||
* Called with the scsi_tape lock held, released before return
|
||||
*/
|
||||
static long st_common_ioctl(struct scsi_tape *STp, struct st_modedef *STm,
|
||||
struct file *file, unsigned int cmd_in,
|
||||
unsigned long arg)
|
||||
{
|
||||
int i, retval = 0;
|
||||
|
||||
if (!STm->defined) {
|
||||
retval = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (cmd_in) {
|
||||
case SCSI_IOCTL_GET_IDLUN:
|
||||
case SCSI_IOCTL_GET_BUS_NUMBER:
|
||||
case SCSI_IOCTL_GET_PCI:
|
||||
break;
|
||||
case SG_IO:
|
||||
case SCSI_IOCTL_SEND_COMMAND:
|
||||
case CDROM_SEND_PACKET:
|
||||
if (!capable(CAP_SYS_RAWIO)) {
|
||||
retval = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
if ((i = flush_buffer(STp, 0)) < 0) {
|
||||
retval = i;
|
||||
goto out;
|
||||
} else { /* flush_buffer succeeds */
|
||||
if (STp->can_partitions) {
|
||||
i = switch_partition(STp);
|
||||
if (i < 0) {
|
||||
retval = i;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&STp->lock);
|
||||
|
||||
retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE,
|
||||
cmd_in, (void __user *)arg);
|
||||
if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) {
|
||||
/* unload */
|
||||
STp->rew_at_close = 0;
|
||||
STp->ready = ST_NO_TAPE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
out:
|
||||
mutex_unlock(&STp->lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* The ioctl command */
|
||||
static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
|
||||
@ -3565,6 +3621,15 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
switch (cmd_in) {
|
||||
case MTIOCPOS:
|
||||
case MTIOCGET:
|
||||
case MTIOCTOP:
|
||||
break;
|
||||
default:
|
||||
return st_common_ioctl(STp, STm, file, cmd_in, arg);
|
||||
}
|
||||
|
||||
cmd_type = _IOC_TYPE(cmd_in);
|
||||
cmd_nr = _IOC_NR(cmd_in);
|
||||
|
||||
@ -3876,29 +3941,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
|
||||
}
|
||||
mt_pos.mt_blkno = blk;
|
||||
retval = put_user_mtpos(p, &mt_pos);
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&STp->lock);
|
||||
|
||||
switch (cmd_in) {
|
||||
case SG_IO:
|
||||
case SCSI_IOCTL_SEND_COMMAND:
|
||||
case CDROM_SEND_PACKET:
|
||||
if (!capable(CAP_SYS_RAWIO))
|
||||
return -EPERM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
retval = scsi_ioctl(STp->device, file->f_mode & FMODE_WRITE, cmd_in, p);
|
||||
if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) {
|
||||
/* unload */
|
||||
STp->rew_at_close = 0;
|
||||
STp->ready = ST_NO_TAPE;
|
||||
}
|
||||
return retval;
|
||||
|
||||
out:
|
||||
mutex_unlock(&STp->lock);
|
||||
return retval;
|
||||
|
||||
@ -994,6 +994,11 @@ void nfs_delegation_mark_returned(struct inode *inode,
|
||||
}
|
||||
|
||||
nfs_mark_delegation_revoked(delegation);
|
||||
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
||||
spin_unlock(&delegation->lock);
|
||||
if (nfs_detach_delegation(NFS_I(inode), delegation, NFS_SERVER(inode)))
|
||||
nfs_put_delegation(delegation);
|
||||
goto out_rcu_unlock;
|
||||
|
||||
out_clear_returning:
|
||||
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
||||
|
||||
@ -600,6 +600,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
|
||||
extern struct TCP_Server_Info *
|
||||
cifs_find_tcp_session(struct smb3_fs_context *ctx);
|
||||
|
||||
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal);
|
||||
|
||||
void __cifs_put_smb_ses(struct cifs_ses *ses);
|
||||
|
||||
extern struct cifs_ses *
|
||||
|
||||
@ -2017,39 +2017,31 @@ static int match_session(struct cifs_ses *ses,
|
||||
/**
|
||||
* cifs_setup_ipc - helper to setup the IPC tcon for the session
|
||||
* @ses: smb session to issue the request on
|
||||
* @ctx: the superblock configuration context to use for building the
|
||||
* new tree connection for the IPC (interprocess communication RPC)
|
||||
* @seal: if encryption is requested
|
||||
*
|
||||
* A new IPC connection is made and stored in the session
|
||||
* tcon_ipc. The IPC tcon has the same lifetime as the session.
|
||||
*/
|
||||
static int
|
||||
cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal)
|
||||
{
|
||||
int rc = 0, xid;
|
||||
struct cifs_tcon *tcon;
|
||||
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
|
||||
bool seal = false;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
|
||||
/*
|
||||
* If the mount request that resulted in the creation of the
|
||||
* session requires encryption, force IPC to be encrypted too.
|
||||
*/
|
||||
if (ctx->seal) {
|
||||
if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
|
||||
seal = true;
|
||||
else {
|
||||
cifs_server_dbg(VFS,
|
||||
"IPC: server doesn't support encryption\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (seal && !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) {
|
||||
cifs_server_dbg(VFS, "IPC: server doesn't support encryption\n");
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/* no need to setup directory caching on IPC share, so pass in false */
|
||||
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc);
|
||||
if (tcon == NULL)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
|
||||
@ -2059,13 +2051,13 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
tcon->ses = ses;
|
||||
tcon->ipc = true;
|
||||
tcon->seal = seal;
|
||||
rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
|
||||
rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls);
|
||||
free_xid(xid);
|
||||
|
||||
if (rc) {
|
||||
cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
|
||||
cifs_server_dbg(VFS | ONCE, "failed to connect to IPC (rc=%d)\n", rc);
|
||||
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail);
|
||||
goto out;
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
|
||||
@ -2073,9 +2065,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
spin_lock(&tcon->tc_lock);
|
||||
tcon->status = TID_GOOD;
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
ses->tcon_ipc = tcon;
|
||||
out:
|
||||
return rc;
|
||||
return tcon;
|
||||
}
|
||||
|
||||
static struct cifs_ses *
|
||||
@ -2349,6 +2339,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
{
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
|
||||
struct cifs_tcon *ipc;
|
||||
struct cifs_ses *ses;
|
||||
unsigned int xid;
|
||||
int retries = 0;
|
||||
@ -2527,7 +2518,12 @@ retry_new_session:
|
||||
list_add(&ses->smb_ses_list, &server->smb_ses_list);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
cifs_setup_ipc(ses, ctx);
|
||||
ipc = cifs_setup_ipc(ses, ctx->seal);
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
ses->tcon_ipc = !IS_ERR(ipc) ? ipc : NULL;
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
free_xid(xid);
|
||||
|
||||
|
||||
@ -1120,24 +1120,63 @@ static bool target_share_equal(struct cifs_tcon *tcon, const char *s1)
|
||||
return match;
|
||||
}
|
||||
|
||||
static bool is_ses_good(struct cifs_ses *ses)
|
||||
static bool is_ses_good(struct cifs_tcon *tcon, struct cifs_ses *ses)
|
||||
{
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
struct cifs_tcon *tcon = ses->tcon_ipc;
|
||||
struct cifs_tcon *ipc = NULL;
|
||||
bool ret;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
spin_lock(&ses->chan_lock);
|
||||
|
||||
ret = !cifs_chan_needs_reconnect(ses, server) &&
|
||||
ses->ses_status == SES_GOOD &&
|
||||
!tcon->need_reconnect;
|
||||
ses->ses_status == SES_GOOD;
|
||||
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
if (likely(ses->tcon_ipc)) {
|
||||
if (ses->tcon_ipc->need_reconnect) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
ipc = cifs_setup_ipc(ses, tcon->seal);
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
if (!IS_ERR(ipc)) {
|
||||
if (!ses->tcon_ipc) {
|
||||
ses->tcon_ipc = ipc;
|
||||
ipc = NULL;
|
||||
}
|
||||
} else {
|
||||
ret = false;
|
||||
ipc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
if (ipc && server->ops->tree_disconnect) {
|
||||
unsigned int xid = get_xid();
|
||||
|
||||
(void)server->ops->tree_disconnect(xid, ipc);
|
||||
_free_xid(xid);
|
||||
}
|
||||
tconInfoFree(ipc, netfs_trace_tcon_ref_free_ipc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Refresh dfs referral of @ses */
|
||||
static void refresh_ses_referral(struct cifs_ses *ses)
|
||||
static void refresh_ses_referral(struct cifs_tcon *tcon, struct cifs_ses *ses)
|
||||
{
|
||||
struct cache_entry *ce;
|
||||
unsigned int xid;
|
||||
@ -1153,7 +1192,7 @@ static void refresh_ses_referral(struct cifs_ses *ses)
|
||||
}
|
||||
|
||||
ses = CIFS_DFS_ROOT_SES(ses);
|
||||
if (!is_ses_good(ses)) {
|
||||
if (!is_ses_good(tcon, ses)) {
|
||||
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
|
||||
__func__);
|
||||
goto out;
|
||||
@ -1241,7 +1280,7 @@ static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh)
|
||||
up_read(&htable_rw_lock);
|
||||
|
||||
ses = CIFS_DFS_ROOT_SES(ses);
|
||||
if (!is_ses_good(ses)) {
|
||||
if (!is_ses_good(tcon, ses)) {
|
||||
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
|
||||
__func__);
|
||||
goto out;
|
||||
@ -1309,7 +1348,7 @@ void dfs_cache_refresh(struct work_struct *work)
|
||||
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
|
||||
|
||||
list_for_each_entry(ses, &tcon->dfs_ses_list, dlist)
|
||||
refresh_ses_referral(ses);
|
||||
refresh_ses_referral(tcon, ses);
|
||||
refresh_tcon_referral(tcon, false);
|
||||
|
||||
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
|
||||
|
||||
@ -2462,11 +2462,8 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
|
||||
}
|
||||
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
|
||||
do_rename_exit:
|
||||
if (rc == 0) {
|
||||
if (rc == 0)
|
||||
d_move(from_dentry, to_dentry);
|
||||
/* Force a new lookup */
|
||||
d_drop(from_dentry);
|
||||
}
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -57,9 +57,11 @@ struct landlock_ruleset_attr {
|
||||
*
|
||||
* - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI
|
||||
* version.
|
||||
* - %LANDLOCK_CREATE_RULESET_ERRATA: Get a bitmask of fixed issues.
|
||||
*/
|
||||
/* clang-format off */
|
||||
#define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
|
||||
#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
@ -296,9 +298,12 @@ struct landlock_net_port_attr {
|
||||
* - %LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET: Restrict a sandboxed process from
|
||||
* connecting to an abstract UNIX socket created by a process outside the
|
||||
* related Landlock domain (e.g. a parent domain or a non-sandboxed process).
|
||||
* - %LANDLOCK_SCOPE_SIGNAL: Restrict a sandboxed process from sending a signal
|
||||
* to another process outside the domain.
|
||||
*/
|
||||
/* clang-format off */
|
||||
#define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0)
|
||||
#define LANDLOCK_SCOPE_SIGNAL (1ULL << 1)
|
||||
/* clang-format on*/
|
||||
|
||||
#endif /* _UAPI_LINUX_LANDLOCK_H */
|
||||
|
||||
@ -1325,7 +1325,7 @@ int audit_compare_dname_path(const struct qstr *dname, const char *path, int par
|
||||
|
||||
/* handle trailing slashes */
|
||||
pathlen -= parentlen;
|
||||
while (p[pathlen - 1] == '/')
|
||||
while (pathlen > 0 && p[pathlen - 1] == '/')
|
||||
pathlen--;
|
||||
|
||||
if (pathlen != dlen)
|
||||
|
||||
@ -2541,10 +2541,9 @@ int unpoison_memory(unsigned long pfn)
|
||||
static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL,
|
||||
DEFAULT_RATELIMIT_BURST);
|
||||
|
||||
if (!pfn_valid(pfn))
|
||||
return -ENXIO;
|
||||
|
||||
p = pfn_to_page(pfn);
|
||||
p = pfn_to_online_page(pfn);
|
||||
if (!p)
|
||||
return -EIO;
|
||||
folio = page_folio(p);
|
||||
|
||||
mutex_lock(&mf_mutex);
|
||||
|
||||
@ -169,13 +169,14 @@ next_chunk:
|
||||
chunk->head_skb = chunk->skb;
|
||||
|
||||
/* skbs with "cover letter" */
|
||||
if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len)
|
||||
if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len) {
|
||||
if (WARN_ON(!skb_shinfo(chunk->skb)->frag_list)) {
|
||||
__SCTP_INC_STATS(dev_net(chunk->skb->dev),
|
||||
SCTP_MIB_IN_PKT_DISCARDS);
|
||||
sctp_chunk_free(chunk);
|
||||
goto next_chunk;
|
||||
}
|
||||
chunk->skb = skb_shinfo(chunk->skb)->frag_list;
|
||||
|
||||
if (WARN_ON(!chunk->skb)) {
|
||||
__SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS);
|
||||
sctp_chunk_free(chunk);
|
||||
goto next_chunk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -93,6 +93,13 @@ ifndef RHJOBS
|
||||
fi)
|
||||
endif
|
||||
|
||||
# for official builds use RELEASE_LOCALVERSION persisted in Makefile.variables
|
||||
ifneq ($(filter $(MAKECMDGOALS),dist-release dist-release-tag dist-release-git dist-rtg dist-get-tag),)
|
||||
DISTLOCALVERSION:=$(RELEASE_LOCALVERSION)
|
||||
ifeq (,$(findstring s,$(firstword -$(MAKEFLAGS))))
|
||||
$(info DISTLOCALVERSION is "$(DISTLOCALVERSION)".)
|
||||
endif
|
||||
else
|
||||
LOCVERFILE:=../localversion
|
||||
# create an empty localversion file if you don't want a local buildid
|
||||
ifneq ($(wildcard $(LOCVERFILE)),)
|
||||
@ -110,6 +117,7 @@ else
|
||||
endif
|
||||
$(info DISTLOCALVERSION is "$(DISTLOCALVERSION)".)
|
||||
endif
|
||||
endif # MAKECMDGOALS
|
||||
|
||||
# options for process_configs.sh script
|
||||
ifdef NO_CONFIGCHECKS
|
||||
|
||||
@ -114,6 +114,10 @@ NO_CONFIGCHECKS ?=
|
||||
# considered stable and may be changed or removed without warning.
|
||||
RHSELFTESTDATA ?=
|
||||
|
||||
# Local version to be used for official (non-scratch) builds. Makefile
|
||||
# dist-{release/tag/git} targets will ignore localversion and DISTLOCALVERSION
|
||||
RELEASE_LOCALVERSION:=
|
||||
|
||||
# This variable is used by the redhat/self-tests. It should not be
|
||||
# considered stable and my be changed or removed without warning.
|
||||
RHDISTDATADIR ?=
|
||||
|
||||
@ -1,3 +1,34 @@
|
||||
* Sat Dec 20 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.20.1.el9_7]
|
||||
- HID: multitouch: fix slab out-of-bounds access in mt_report_fixup() (CKI Backport Bot) [RHEL-124607] {CVE-2025-39806}
|
||||
- sctp: avoid NULL dereference when chunk data buffer is missing (CKI Backport Bot) [RHEL-134001] {CVE-2025-40240}
|
||||
- selftests/landlock: Add a new test for setuid() (Štěpán Horáček) [RHEL-132712]
|
||||
- selftests/landlock: Split signal_scoping_threads tests (Štěpán Horáček) [RHEL-132712]
|
||||
- landlock: Always allow signals between threads of the same process (Štěpán Horáček) [RHEL-132712]
|
||||
- landlock: Prepare to add second errata (Štěpán Horáček) [RHEL-132712]
|
||||
- landlock: Add the errata interface (Štěpán Horáček) [RHEL-132712]
|
||||
- selftests/landlock: Test signal scoping for threads (Štěpán Horáček) [RHEL-132712]
|
||||
- selftests/landlock: Test signal scoping (Štěpán Horáček) [RHEL-132712]
|
||||
- landlock: Add signal scoping (Štěpán Horáček) [RHEL-132712]
|
||||
Resolves: RHEL-124607, RHEL-132712, RHEL-134001
|
||||
|
||||
* Thu Dec 18 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.19.1.el9_7]
|
||||
- scsi: st: Skip buffer flush for information ioctls (John Meneghini) [RHEL-133543]
|
||||
- scsi: st: Separate st-unique ioctl handling from SCSI common ioctl handling (John Meneghini) [RHEL-133543]
|
||||
- audit: fix out-of-bounds read in audit_compare_dname_path() (Richard Guy Briggs) [RHEL-119176] {CVE-2025-39840}
|
||||
Resolves: RHEL-119176, RHEL-133543
|
||||
|
||||
* Sat Dec 13 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.18.1.el9_7]
|
||||
- NFS: remove revoked delegation from server's delegation list (Benjamin Coddington) [RHEL-134237]
|
||||
- redhat: use RELEASE_LOCALVERSION also for dist-get-tag (Jan Stancek)
|
||||
- redhat: introduce RELEASE_LOCALVERSION variable (Jan Stancek)
|
||||
Resolves: RHEL-134237
|
||||
|
||||
* Thu Dec 11 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.17.1.el9_7]
|
||||
- smb: client: handle lack of IPC in dfs_cache_refresh() (Paulo Alcantara) [RHEL-126165]
|
||||
- smb: client: get rid of d_drop() in cifs_do_rename() (Paulo Alcantara) [RHEL-124917]
|
||||
- mm/memory-failure: fix VM_BUG_ON_PAGE(PagePoisoned(page)) when unpoison memory (CKI Backport Bot) [RHEL-119150] {CVE-2025-39883}
|
||||
Resolves: RHEL-119150, RHEL-124917, RHEL-126165
|
||||
|
||||
* Sun Dec 07 2025 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-611.16.1.el9_7]
|
||||
- CVE-2025-38499 kernel: clone_private_mnt(): make sure that caller has CAP_SYS_ADMIN in the right userns (Abhi Das) [RHEL-129261] {CVE-2025-38499}
|
||||
- tls: wait for pending async decryptions if tls_strp_msg_hold fails (CKI Backport Bot) [RHEL-128860] {CVE-2025-40176}
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc4.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc4.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=c9s
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc4.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc4.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rawhide
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc4.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc4.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-0.rc5.6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -46,6 +46,7 @@ PROCESS_CONFIGS_CHECK_OPTS=-n -t -c
|
||||
PROCESS_CONFIGS_OPTS=-n -w -c
|
||||
REDHAT=../redhat
|
||||
RELEASETAG=kernel-5.12.0-6.test
|
||||
RELEASE_LOCALVERSION=
|
||||
RHDISTGIT_BRANCH=rhel-9.7.0
|
||||
RHDISTGIT_USER="shadowman"
|
||||
RHEL_MAJOR=9
|
||||
|
||||
@ -26,7 +26,7 @@ landlock_cred(const struct cred *cred)
|
||||
return cred->security + landlock_blob_sizes.lbs_cred;
|
||||
}
|
||||
|
||||
static inline const struct landlock_ruleset *landlock_get_current_domain(void)
|
||||
static inline struct landlock_ruleset *landlock_get_current_domain(void)
|
||||
{
|
||||
return landlock_cred(current_cred())->domain;
|
||||
}
|
||||
|
||||
99
security/landlock/errata.h
Normal file
99
security/landlock/errata.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Landlock - Errata information
|
||||
*
|
||||
* Copyright © 2025 Microsoft Corporation
|
||||
*/
|
||||
|
||||
#ifndef _SECURITY_LANDLOCK_ERRATA_H
|
||||
#define _SECURITY_LANDLOCK_ERRATA_H
|
||||
|
||||
#include <linux/init.h>
|
||||
|
||||
struct landlock_erratum {
|
||||
const int abi;
|
||||
const u8 number;
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
#define LANDLOCK_ERRATUM(NUMBER) \
|
||||
{ \
|
||||
.abi = LANDLOCK_ERRATA_ABI, \
|
||||
.number = NUMBER, \
|
||||
},
|
||||
/* clang-format on */
|
||||
|
||||
/*
|
||||
* Some fixes may require user space to check if they are applied on the running
|
||||
* kernel before using a specific feature. For instance, this applies when a
|
||||
* restriction was previously too restrictive and is now getting relaxed (for
|
||||
* compatibility or semantic reasons). However, non-visible changes for
|
||||
* legitimate use (e.g. security fixes) do not require an erratum.
|
||||
*/
|
||||
static const struct landlock_erratum landlock_errata_init[] __initconst = {
|
||||
|
||||
/*
|
||||
* Only Sparse may not implement __has_include. If a compiler does not
|
||||
* implement __has_include, a warning will be printed at boot time (see
|
||||
* setup.c).
|
||||
*/
|
||||
#ifdef __has_include
|
||||
|
||||
#define LANDLOCK_ERRATA_ABI 1
|
||||
#if __has_include("errata/abi-1.h")
|
||||
#include "errata/abi-1.h"
|
||||
#endif
|
||||
#undef LANDLOCK_ERRATA_ABI
|
||||
|
||||
#define LANDLOCK_ERRATA_ABI 2
|
||||
#if __has_include("errata/abi-2.h")
|
||||
#include "errata/abi-2.h"
|
||||
#endif
|
||||
#undef LANDLOCK_ERRATA_ABI
|
||||
|
||||
#define LANDLOCK_ERRATA_ABI 3
|
||||
#if __has_include("errata/abi-3.h")
|
||||
#include "errata/abi-3.h"
|
||||
#endif
|
||||
#undef LANDLOCK_ERRATA_ABI
|
||||
|
||||
#define LANDLOCK_ERRATA_ABI 4
|
||||
#if __has_include("errata/abi-4.h")
|
||||
#include "errata/abi-4.h"
|
||||
#endif
|
||||
#undef LANDLOCK_ERRATA_ABI
|
||||
|
||||
#define LANDLOCK_ERRATA_ABI 5
|
||||
#if __has_include("errata/abi-5.h")
|
||||
#include "errata/abi-5.h"
|
||||
#endif
|
||||
#undef LANDLOCK_ERRATA_ABI
|
||||
|
||||
#define LANDLOCK_ERRATA_ABI 6
|
||||
#if __has_include("errata/abi-6.h")
|
||||
#include "errata/abi-6.h"
|
||||
#endif
|
||||
#undef LANDLOCK_ERRATA_ABI
|
||||
|
||||
/*
|
||||
* For each new erratum, we need to include all the ABI files up to the impacted
|
||||
* ABI to make all potential future intermediate errata easy to backport.
|
||||
*
|
||||
* If such change involves more than one ABI addition, then it must be in a
|
||||
* dedicated commit with the same Fixes tag as used for the actual fix.
|
||||
*
|
||||
* Each commit creating a new security/landlock/errata/abi-*.h file must have a
|
||||
* Depends-on tag to reference the commit that previously added the line to
|
||||
* include this new file, except if the original Fixes tag is enough.
|
||||
*
|
||||
* Each erratum must be documented in its related ABI file, and a dedicated
|
||||
* commit must update Documentation/userspace-api/landlock.rst to include this
|
||||
* erratum. This commit will not be backported.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
#endif /* _SECURITY_LANDLOCK_ERRATA_H */
|
||||
19
security/landlock/errata/abi-6.h
Normal file
19
security/landlock/errata/abi-6.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/**
|
||||
* DOC: erratum_2
|
||||
*
|
||||
* Erratum 2: Scoped signal handling
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* This fix addresses an issue where signal scoping was overly restrictive,
|
||||
* preventing sandboxed threads from signaling other threads within the same
|
||||
* process if they belonged to different domains. Because threads are not
|
||||
* security boundaries, user space might assume that any thread within the same
|
||||
* process can send signals between themselves (see :manpage:`nptl(7)` and
|
||||
* :manpage:`libpsx(3)`). Consistent with :manpage:`ptrace(2)` behavior, direct
|
||||
* interaction between threads of the same process should always be allowed.
|
||||
* This change ensures that any thread is allowed to send signals to any other
|
||||
* thread within the same process, regardless of their domain.
|
||||
*/
|
||||
LANDLOCK_ERRATUM(2)
|
||||
@ -27,7 +27,9 @@
|
||||
#include <linux/mount.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/path.h>
|
||||
#include <linux/pid.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/types.h>
|
||||
@ -1636,6 +1638,54 @@ static int hook_file_ioctl_compat(struct file *file, unsigned int cmd,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always allow sending signals between threads of the same process. This
|
||||
* ensures consistency with hook_task_kill().
|
||||
*/
|
||||
static bool control_current_fowner(struct fown_struct *const fown)
|
||||
{
|
||||
struct task_struct *p;
|
||||
|
||||
/*
|
||||
* Lock already held by __f_setown(), see commit 26f204380a3c ("fs: Fix
|
||||
* file_set_fowner LSM hook inconsistencies").
|
||||
*/
|
||||
lockdep_assert_held(&fown->lock);
|
||||
|
||||
/*
|
||||
* Some callers (e.g. fcntl_dirnotify) may not be in an RCU read-side
|
||||
* critical section.
|
||||
*/
|
||||
guard(rcu)();
|
||||
p = pid_task(fown->pid, fown->pid_type);
|
||||
if (!p)
|
||||
return true;
|
||||
|
||||
return !same_thread_group(p, current);
|
||||
}
|
||||
|
||||
static void hook_file_set_fowner(struct file *file)
|
||||
{
|
||||
struct landlock_ruleset *prev_dom;
|
||||
struct landlock_ruleset *new_dom = NULL;
|
||||
|
||||
if (control_current_fowner(&file->f_owner)) {
|
||||
new_dom = landlock_get_current_domain();
|
||||
landlock_get_ruleset(new_dom);
|
||||
}
|
||||
|
||||
prev_dom = landlock_file(file)->fown_domain;
|
||||
landlock_file(file)->fown_domain = new_dom;
|
||||
|
||||
/* May be called in an RCU read-side critical section. */
|
||||
landlock_put_ruleset_deferred(prev_dom);
|
||||
}
|
||||
|
||||
static void hook_file_free_security(struct file *file)
|
||||
{
|
||||
landlock_put_ruleset_deferred(landlock_file(file)->fown_domain);
|
||||
}
|
||||
|
||||
static struct security_hook_list landlock_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(inode_free_security, hook_inode_free_security),
|
||||
|
||||
@ -1660,6 +1710,8 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(file_truncate, hook_file_truncate),
|
||||
LSM_HOOK_INIT(file_ioctl, hook_file_ioctl),
|
||||
LSM_HOOK_INIT(file_ioctl_compat, hook_file_ioctl_compat),
|
||||
LSM_HOOK_INIT(file_set_fowner, hook_file_set_fowner),
|
||||
LSM_HOOK_INIT(file_free_security, hook_file_free_security),
|
||||
};
|
||||
|
||||
__init void landlock_add_fs_hooks(void)
|
||||
|
||||
@ -52,6 +52,13 @@ struct landlock_file_security {
|
||||
* needed to authorize later operations on the open file.
|
||||
*/
|
||||
access_mask_t allowed_access;
|
||||
/**
|
||||
* @fown_domain: Domain of the task that set the PID that may receive a
|
||||
* signal e.g., SIGURG when writing MSG_OOB to the related socket.
|
||||
* This pointer is protected by the related file->f_owner->lock, as for
|
||||
* fown_struct's members: pid, uid, and euid.
|
||||
*/
|
||||
struct landlock_ruleset *fown_domain;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
#define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1)
|
||||
#define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET)
|
||||
|
||||
#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
|
||||
#define LANDLOCK_LAST_SCOPE LANDLOCK_SCOPE_SIGNAL
|
||||
#define LANDLOCK_MASK_SCOPE ((LANDLOCK_LAST_SCOPE << 1) - 1)
|
||||
#define LANDLOCK_NUM_SCOPE __const_hweight64(LANDLOCK_MASK_SCOPE)
|
||||
/* clang-format on */
|
||||
|
||||
@ -6,12 +6,14 @@
|
||||
* Copyright © 2018-2020 ANSSI
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/lsm_hooks.h>
|
||||
#include <uapi/linux/lsm.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "cred.h"
|
||||
#include "errata.h"
|
||||
#include "fs.h"
|
||||
#include "net.h"
|
||||
#include "setup.h"
|
||||
@ -31,8 +33,36 @@ const struct lsm_id landlock_lsmid = {
|
||||
.id = LSM_ID_LANDLOCK,
|
||||
};
|
||||
|
||||
int landlock_errata __ro_after_init;
|
||||
|
||||
static void __init compute_errata(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
#ifndef __has_include
|
||||
/*
|
||||
* This is a safeguard to make sure the compiler implements
|
||||
* __has_include (see errata.h).
|
||||
*/
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (i = 0; landlock_errata_init[i].number; i++) {
|
||||
const int prev_errata = landlock_errata;
|
||||
|
||||
if (WARN_ON_ONCE(landlock_errata_init[i].abi >
|
||||
landlock_abi_version))
|
||||
continue;
|
||||
|
||||
landlock_errata |= BIT(landlock_errata_init[i].number - 1);
|
||||
WARN_ON_ONCE(prev_errata == landlock_errata);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init landlock_init(void)
|
||||
{
|
||||
compute_errata();
|
||||
landlock_add_cred_hooks();
|
||||
landlock_add_task_hooks();
|
||||
landlock_add_fs_hooks();
|
||||
|
||||
@ -11,7 +11,10 @@
|
||||
|
||||
#include <linux/lsm_hooks.h>
|
||||
|
||||
extern const int landlock_abi_version;
|
||||
|
||||
extern bool landlock_initialized;
|
||||
extern int landlock_errata;
|
||||
|
||||
extern struct lsm_blob_sizes landlock_blob_sizes;
|
||||
extern const struct lsm_id landlock_lsmid;
|
||||
|
||||
@ -159,7 +159,9 @@ static const struct file_operations ruleset_fops = {
|
||||
* the new ruleset.
|
||||
* @size: Size of the pointed &struct landlock_ruleset_attr (needed for
|
||||
* backward and forward compatibility).
|
||||
* @flags: Supported value: %LANDLOCK_CREATE_RULESET_VERSION.
|
||||
* @flags: Supported value:
|
||||
* - %LANDLOCK_CREATE_RULESET_VERSION
|
||||
* - %LANDLOCK_CREATE_RULESET_ERRATA
|
||||
*
|
||||
* This system call enables to create a new Landlock ruleset, and returns the
|
||||
* related file descriptor on success.
|
||||
@ -168,6 +170,10 @@ static const struct file_operations ruleset_fops = {
|
||||
* 0, then the returned value is the highest supported Landlock ABI version
|
||||
* (starting at 1).
|
||||
*
|
||||
* If @flags is %LANDLOCK_CREATE_RULESET_ERRATA and @attr is NULL and @size is
|
||||
* 0, then the returned value is a bitmask of fixed issues for the current
|
||||
* Landlock ABI version.
|
||||
*
|
||||
* Possible returned errors are:
|
||||
*
|
||||
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
|
||||
@ -191,9 +197,15 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (flags) {
|
||||
if ((flags == LANDLOCK_CREATE_RULESET_VERSION) && !attr &&
|
||||
!size)
|
||||
return LANDLOCK_ABI_VERSION;
|
||||
if (attr || size)
|
||||
return -EINVAL;
|
||||
|
||||
if (flags == LANDLOCK_CREATE_RULESET_VERSION)
|
||||
return landlock_abi_version;
|
||||
|
||||
if (flags == LANDLOCK_CREATE_RULESET_ERRATA)
|
||||
return landlock_errata;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -234,6 +246,8 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
|
||||
return ruleset_fd;
|
||||
}
|
||||
|
||||
const int landlock_abi_version = LANDLOCK_ABI_VERSION;
|
||||
|
||||
/*
|
||||
* Returns an owned ruleset from a FD. It is thus needed to call
|
||||
* landlock_put_ruleset() on the return value.
|
||||
|
||||
@ -13,11 +13,13 @@
|
||||
#include <linux/lsm_hooks.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <net/af_unix.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "cred.h"
|
||||
#include "fs.h"
|
||||
#include "ruleset.h"
|
||||
#include "setup.h"
|
||||
#include "task.h"
|
||||
@ -242,12 +244,78 @@ static int hook_unix_may_send(struct socket *const sock,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hook_task_kill(struct task_struct *const p,
|
||||
struct kernel_siginfo *const info, const int sig,
|
||||
const struct cred *const cred)
|
||||
{
|
||||
bool is_scoped;
|
||||
const struct landlock_ruleset *dom;
|
||||
|
||||
if (cred) {
|
||||
/* Dealing with USB IO. */
|
||||
dom = landlock_cred(cred)->domain;
|
||||
} else {
|
||||
/*
|
||||
* Always allow sending signals between threads of the same process.
|
||||
* This is required for process credential changes by the Native POSIX
|
||||
* Threads Library and implemented by the set*id(2) wrappers and
|
||||
* libcap(3) with tgkill(2). See nptl(7) and libpsx(3).
|
||||
*
|
||||
* This exception is similar to the __ptrace_may_access() one.
|
||||
*/
|
||||
if (same_thread_group(p, current))
|
||||
return 0;
|
||||
|
||||
dom = landlock_get_current_domain();
|
||||
}
|
||||
|
||||
/* Quick return for non-landlocked tasks. */
|
||||
if (!dom)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
is_scoped = domain_is_scoped(dom, landlock_get_task_domain(p),
|
||||
LANDLOCK_SCOPE_SIGNAL);
|
||||
rcu_read_unlock();
|
||||
if (is_scoped)
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hook_file_send_sigiotask(struct task_struct *tsk,
|
||||
struct fown_struct *fown, int signum)
|
||||
{
|
||||
const struct landlock_ruleset *dom;
|
||||
bool is_scoped = false;
|
||||
|
||||
/* Lock already held by send_sigio() and send_sigurg(). */
|
||||
lockdep_assert_held(&fown->lock);
|
||||
dom = landlock_file(container_of(fown, struct file, f_owner))->fown_domain;
|
||||
|
||||
/* Quick return for unowned socket. */
|
||||
if (!dom)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
is_scoped = domain_is_scoped(dom, landlock_get_task_domain(tsk),
|
||||
LANDLOCK_SCOPE_SIGNAL);
|
||||
rcu_read_unlock();
|
||||
if (is_scoped)
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct security_hook_list landlock_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
|
||||
LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
|
||||
|
||||
LSM_HOOK_INIT(unix_stream_connect, hook_unix_stream_connect),
|
||||
LSM_HOOK_INIT(unix_may_send, hook_unix_may_send),
|
||||
|
||||
LSM_HOOK_INIT(task_kill, hook_task_kill),
|
||||
LSM_HOOK_INIT(file_send_sigiotask, hook_file_send_sigiotask),
|
||||
};
|
||||
|
||||
__init void landlock_add_task_hooks(void)
|
||||
|
||||
@ -98,10 +98,54 @@ TEST(abi_version)
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Old source trees might not have the set of Kselftest fixes related to kernel
|
||||
* UAPI headers.
|
||||
*/
|
||||
#ifndef LANDLOCK_CREATE_RULESET_ERRATA
|
||||
#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
|
||||
#endif
|
||||
|
||||
TEST(errata)
|
||||
{
|
||||
const struct landlock_ruleset_attr ruleset_attr = {
|
||||
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
|
||||
};
|
||||
int errata;
|
||||
|
||||
errata = landlock_create_ruleset(NULL, 0,
|
||||
LANDLOCK_CREATE_RULESET_ERRATA);
|
||||
/* The errata bitmask will not be backported to tests. */
|
||||
ASSERT_LE(0, errata);
|
||||
TH_LOG("errata: 0x%x", errata);
|
||||
|
||||
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
|
||||
LANDLOCK_CREATE_RULESET_ERRATA));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
|
||||
ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
|
||||
LANDLOCK_CREATE_RULESET_ERRATA));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
|
||||
ASSERT_EQ(-1,
|
||||
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
|
||||
LANDLOCK_CREATE_RULESET_ERRATA));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
|
||||
ASSERT_EQ(-1, landlock_create_ruleset(
|
||||
NULL, 0,
|
||||
LANDLOCK_CREATE_RULESET_VERSION |
|
||||
LANDLOCK_CREATE_RULESET_ERRATA));
|
||||
ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
|
||||
LANDLOCK_CREATE_RULESET_ERRATA |
|
||||
1 << 31));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
}
|
||||
|
||||
/* Tests ordering of syscall argument checks. */
|
||||
TEST(create_ruleset_checks_ordering)
|
||||
{
|
||||
const int last_flag = LANDLOCK_CREATE_RULESET_VERSION;
|
||||
const int last_flag = LANDLOCK_CREATE_RULESET_ERRATA;
|
||||
const int invalid_flag = last_flag << 1;
|
||||
int ruleset_fd;
|
||||
const struct landlock_ruleset_attr ruleset_attr = {
|
||||
|
||||
@ -68,6 +68,7 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
|
||||
CAP_MKNOD,
|
||||
CAP_NET_ADMIN,
|
||||
CAP_NET_BIND_SERVICE,
|
||||
CAP_SETUID,
|
||||
CAP_SYS_ADMIN,
|
||||
CAP_SYS_CHROOT,
|
||||
/* clang-format on */
|
||||
|
||||
378
tools/testing/selftests/landlock/scoped_signal_test.c
Normal file
378
tools/testing/selftests/landlock/scoped_signal_test.c
Normal file
@ -0,0 +1,378 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Landlock tests - Signal Scoping
|
||||
*
|
||||
* Copyright © 2024 Tahera Fahimi <fahimitahera@gmail.com>
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/landlock.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "scoped_common.h"
|
||||
|
||||
/* This variable is used for handling several signals. */
|
||||
static volatile sig_atomic_t is_signaled;
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE(scoping_signals) {};
|
||||
/* clang-format on */
|
||||
|
||||
FIXTURE_VARIANT(scoping_signals)
|
||||
{
|
||||
int sig;
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(scoping_signals, sigtrap) {
|
||||
/* clang-format on */
|
||||
.sig = SIGTRAP,
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(scoping_signals, sigurg) {
|
||||
/* clang-format on */
|
||||
.sig = SIGURG,
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(scoping_signals, sighup) {
|
||||
/* clang-format on */
|
||||
.sig = SIGHUP,
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE_VARIANT_ADD(scoping_signals, sigtstp) {
|
||||
/* clang-format on */
|
||||
.sig = SIGTSTP,
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(scoping_signals)
|
||||
{
|
||||
drop_caps(_metadata);
|
||||
|
||||
is_signaled = 0;
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(scoping_signals)
|
||||
{
|
||||
}
|
||||
|
||||
static void scope_signal_handler(int sig, siginfo_t *info, void *ucontext)
|
||||
{
|
||||
if (sig == SIGTRAP || sig == SIGURG || sig == SIGHUP || sig == SIGTSTP)
|
||||
is_signaled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* In this test, a child process sends a signal to parent before and
|
||||
* after getting scoped.
|
||||
*/
|
||||
TEST_F(scoping_signals, send_sig_to_parent)
|
||||
{
|
||||
int pipe_parent[2];
|
||||
int status;
|
||||
pid_t child;
|
||||
pid_t parent = getpid();
|
||||
struct sigaction action = {
|
||||
.sa_sigaction = scope_signal_handler,
|
||||
.sa_flags = SA_SIGINFO,
|
||||
|
||||
};
|
||||
|
||||
ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
|
||||
ASSERT_LE(0, sigaction(variant->sig, &action, NULL));
|
||||
|
||||
/* The process should not have already been signaled. */
|
||||
EXPECT_EQ(0, is_signaled);
|
||||
|
||||
child = fork();
|
||||
ASSERT_LE(0, child);
|
||||
if (child == 0) {
|
||||
char buf_child;
|
||||
int err;
|
||||
|
||||
EXPECT_EQ(0, close(pipe_parent[1]));
|
||||
|
||||
/*
|
||||
* The child process can send signal to parent when
|
||||
* domain is not scoped.
|
||||
*/
|
||||
err = kill(parent, variant->sig);
|
||||
ASSERT_EQ(0, err);
|
||||
ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
|
||||
EXPECT_EQ(0, close(pipe_parent[0]));
|
||||
|
||||
create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
|
||||
|
||||
/*
|
||||
* The child process cannot send signal to the parent
|
||||
* anymore.
|
||||
*/
|
||||
err = kill(parent, variant->sig);
|
||||
ASSERT_EQ(-1, err);
|
||||
ASSERT_EQ(EPERM, errno);
|
||||
|
||||
/*
|
||||
* No matter of the domain, a process should be able to
|
||||
* send a signal to itself.
|
||||
*/
|
||||
ASSERT_EQ(0, is_signaled);
|
||||
ASSERT_EQ(0, raise(variant->sig));
|
||||
ASSERT_EQ(1, is_signaled);
|
||||
|
||||
_exit(_metadata->exit_code);
|
||||
return;
|
||||
}
|
||||
EXPECT_EQ(0, close(pipe_parent[0]));
|
||||
|
||||
/* Waits for a first signal to be received, without race condition. */
|
||||
while (!is_signaled && !usleep(1))
|
||||
;
|
||||
ASSERT_EQ(1, is_signaled);
|
||||
ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
|
||||
EXPECT_EQ(0, close(pipe_parent[1]));
|
||||
is_signaled = 0;
|
||||
|
||||
ASSERT_EQ(child, waitpid(child, &status, 0));
|
||||
if (WIFSIGNALED(status) || !WIFEXITED(status) ||
|
||||
WEXITSTATUS(status) != EXIT_SUCCESS)
|
||||
_metadata->exit_code = KSFT_FAIL;
|
||||
|
||||
EXPECT_EQ(0, is_signaled);
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
FIXTURE(scoped_domains) {};
|
||||
/* clang-format on */
|
||||
|
||||
#include "scoped_base_variants.h"
|
||||
|
||||
FIXTURE_SETUP(scoped_domains)
|
||||
{
|
||||
drop_caps(_metadata);
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(scoped_domains)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* This test ensures that a scoped process cannot send signal out of
|
||||
* scoped domain.
|
||||
*/
|
||||
TEST_F(scoped_domains, check_access_signal)
|
||||
{
|
||||
pid_t child;
|
||||
pid_t parent = getpid();
|
||||
int status;
|
||||
bool can_signal_child, can_signal_parent;
|
||||
int pipe_parent[2], pipe_child[2];
|
||||
char buf_parent;
|
||||
int err;
|
||||
|
||||
can_signal_parent = !variant->domain_child;
|
||||
can_signal_child = !variant->domain_parent;
|
||||
|
||||
if (variant->domain_both)
|
||||
create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
|
||||
|
||||
ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
|
||||
ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
|
||||
|
||||
child = fork();
|
||||
ASSERT_LE(0, child);
|
||||
if (child == 0) {
|
||||
char buf_child;
|
||||
|
||||
EXPECT_EQ(0, close(pipe_child[0]));
|
||||
EXPECT_EQ(0, close(pipe_parent[1]));
|
||||
|
||||
if (variant->domain_child)
|
||||
create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
|
||||
|
||||
ASSERT_EQ(1, write(pipe_child[1], ".", 1));
|
||||
EXPECT_EQ(0, close(pipe_child[1]));
|
||||
|
||||
/* Waits for the parent to send signals. */
|
||||
ASSERT_EQ(1, read(pipe_parent[0], &buf_child, 1));
|
||||
EXPECT_EQ(0, close(pipe_parent[0]));
|
||||
|
||||
err = kill(parent, 0);
|
||||
if (can_signal_parent) {
|
||||
ASSERT_EQ(0, err);
|
||||
} else {
|
||||
ASSERT_EQ(-1, err);
|
||||
ASSERT_EQ(EPERM, errno);
|
||||
}
|
||||
/*
|
||||
* No matter of the domain, a process should be able to
|
||||
* send a signal to itself.
|
||||
*/
|
||||
ASSERT_EQ(0, raise(0));
|
||||
|
||||
_exit(_metadata->exit_code);
|
||||
return;
|
||||
}
|
||||
EXPECT_EQ(0, close(pipe_parent[0]));
|
||||
EXPECT_EQ(0, close(pipe_child[1]));
|
||||
|
||||
if (variant->domain_parent)
|
||||
create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
|
||||
|
||||
ASSERT_EQ(1, read(pipe_child[0], &buf_parent, 1));
|
||||
EXPECT_EQ(0, close(pipe_child[0]));
|
||||
|
||||
err = kill(child, 0);
|
||||
if (can_signal_child) {
|
||||
ASSERT_EQ(0, err);
|
||||
} else {
|
||||
ASSERT_EQ(-1, err);
|
||||
ASSERT_EQ(EPERM, errno);
|
||||
}
|
||||
ASSERT_EQ(0, raise(0));
|
||||
|
||||
ASSERT_EQ(1, write(pipe_parent[1], ".", 1));
|
||||
EXPECT_EQ(0, close(pipe_parent[1]));
|
||||
ASSERT_EQ(child, waitpid(child, &status, 0));
|
||||
|
||||
if (WIFSIGNALED(status) || !WIFEXITED(status) ||
|
||||
WEXITSTATUS(status) != EXIT_SUCCESS)
|
||||
_metadata->exit_code = KSFT_FAIL;
|
||||
}
|
||||
|
||||
enum thread_return {
|
||||
THREAD_INVALID = 0,
|
||||
THREAD_SUCCESS = 1,
|
||||
THREAD_ERROR = 2,
|
||||
THREAD_TEST_FAILED = 3,
|
||||
};
|
||||
|
||||
static void *thread_sync(void *arg)
|
||||
{
|
||||
const int pipe_read = *(int *)arg;
|
||||
char buf;
|
||||
|
||||
if (read(pipe_read, &buf, 1) != 1)
|
||||
return (void *)THREAD_ERROR;
|
||||
|
||||
return (void *)THREAD_SUCCESS;
|
||||
}
|
||||
|
||||
TEST(signal_scoping_thread_before)
|
||||
{
|
||||
pthread_t no_sandbox_thread;
|
||||
enum thread_return ret = THREAD_INVALID;
|
||||
int thread_pipe[2];
|
||||
|
||||
drop_caps(_metadata);
|
||||
ASSERT_EQ(0, pipe2(thread_pipe, O_CLOEXEC));
|
||||
|
||||
ASSERT_EQ(0, pthread_create(&no_sandbox_thread, NULL, thread_sync,
|
||||
&thread_pipe[0]));
|
||||
|
||||
/* Enforces restriction after creating the thread. */
|
||||
create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
|
||||
|
||||
EXPECT_EQ(0, pthread_kill(no_sandbox_thread, 0));
|
||||
EXPECT_EQ(1, write(thread_pipe[1], ".", 1));
|
||||
|
||||
EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret));
|
||||
EXPECT_EQ(THREAD_SUCCESS, ret);
|
||||
|
||||
EXPECT_EQ(0, close(thread_pipe[0]));
|
||||
EXPECT_EQ(0, close(thread_pipe[1]));
|
||||
}
|
||||
|
||||
TEST(signal_scoping_thread_after)
|
||||
{
|
||||
pthread_t scoped_thread;
|
||||
enum thread_return ret = THREAD_INVALID;
|
||||
int thread_pipe[2];
|
||||
|
||||
drop_caps(_metadata);
|
||||
ASSERT_EQ(0, pipe2(thread_pipe, O_CLOEXEC));
|
||||
|
||||
/* Enforces restriction before creating the thread. */
|
||||
create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
|
||||
|
||||
ASSERT_EQ(0, pthread_create(&scoped_thread, NULL, thread_sync,
|
||||
&thread_pipe[0]));
|
||||
|
||||
EXPECT_EQ(0, pthread_kill(scoped_thread, 0));
|
||||
EXPECT_EQ(1, write(thread_pipe[1], ".", 1));
|
||||
|
||||
EXPECT_EQ(0, pthread_join(scoped_thread, (void **)&ret));
|
||||
EXPECT_EQ(THREAD_SUCCESS, ret);
|
||||
|
||||
EXPECT_EQ(0, close(thread_pipe[0]));
|
||||
EXPECT_EQ(0, close(thread_pipe[1]));
|
||||
}
|
||||
|
||||
struct thread_setuid_args {
|
||||
int pipe_read, new_uid;
|
||||
};
|
||||
|
||||
void *thread_setuid(void *ptr)
|
||||
{
|
||||
const struct thread_setuid_args *arg = ptr;
|
||||
char buf;
|
||||
|
||||
if (read(arg->pipe_read, &buf, 1) != 1)
|
||||
return (void *)THREAD_ERROR;
|
||||
|
||||
/* libc's setuid() should update all thread's credentials. */
|
||||
if (getuid() != arg->new_uid)
|
||||
return (void *)THREAD_TEST_FAILED;
|
||||
|
||||
return (void *)THREAD_SUCCESS;
|
||||
}
|
||||
|
||||
TEST(signal_scoping_thread_setuid)
|
||||
{
|
||||
struct thread_setuid_args arg;
|
||||
pthread_t no_sandbox_thread;
|
||||
enum thread_return ret = THREAD_INVALID;
|
||||
int pipe_parent[2];
|
||||
int prev_uid;
|
||||
|
||||
disable_caps(_metadata);
|
||||
|
||||
/* This test does not need to be run as root. */
|
||||
prev_uid = getuid();
|
||||
arg.new_uid = prev_uid + 1;
|
||||
EXPECT_LT(0, arg.new_uid);
|
||||
|
||||
ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
|
||||
arg.pipe_read = pipe_parent[0];
|
||||
|
||||
/* Capabilities must be set before creating a new thread. */
|
||||
set_cap(_metadata, CAP_SETUID);
|
||||
ASSERT_EQ(0, pthread_create(&no_sandbox_thread, NULL, thread_setuid,
|
||||
&arg));
|
||||
|
||||
/* Enforces restriction after creating the thread. */
|
||||
create_scoped_domain(_metadata, LANDLOCK_SCOPE_SIGNAL);
|
||||
|
||||
EXPECT_NE(arg.new_uid, getuid());
|
||||
EXPECT_EQ(0, setuid(arg.new_uid));
|
||||
EXPECT_EQ(arg.new_uid, getuid());
|
||||
EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
|
||||
|
||||
EXPECT_EQ(0, pthread_join(no_sandbox_thread, (void **)&ret));
|
||||
EXPECT_EQ(THREAD_SUCCESS, ret);
|
||||
|
||||
clear_cap(_metadata, CAP_SETUID);
|
||||
EXPECT_EQ(0, close(pipe_parent[0]));
|
||||
EXPECT_EQ(0, close(pipe_parent[1]));
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define ACCESS_LAST LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
|
||||
#define ACCESS_LAST LANDLOCK_SCOPE_SIGNAL
|
||||
|
||||
TEST(ruleset_with_unknown_scope)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user