Linux 安全 - Capabilities机制

文章目录

  • 前言
  • 一、简介
  • 二、Capabilities list
    • 2.1 POSIX-draft defined capabilities
    • 2.2 Linux-specific capabilities
  • 三、 Past and current implementation
  • 四、Thread capability sets
  • 五、File capabilities
  • 六、Transformation of capabilities during execve()
  • 七、Capabilities and execution of programs by root
  • 八、Capability bounding set
  • 九、Effect of user ID changes on capabilities
  • 十、 Programmatically adjusting capability sets
  • 参考资料

前言

在这两篇文章中介绍了 Linux 安全机制 Credentials :Linux 安全 - Credentials,以及 Linux 安全 - SUID机制。

接下来我们详细介绍Capabilities,在介绍Capabilities之前先简单的和SUID机制对比一下:

在Linux中,除了SUID权限之外,还有一种更为细粒度的权限控制机制,称为Capabilities(能力)。Capabilities提供了对特定操作或系统资源的更细粒度的权限控制,以允许用户或进程执行特定的特权操作,而无需完全提升到超级用户(root)权限。

SUID权限和Capabilities的主要区别在于权限的粒度和授予权限的方式:
(1)SUID权限:SUID权限是应用于可执行文件的一种特殊权限位,允许普通用户在执行该文件时以文件所有者的权限运行。这意味着用户可以临时获得与文件所有者相同的权限级别,从而执行一些需要特权的操作。然而,SUID权限的授予是基于文件的整体权限,而不是基于特定操作。

(2)Capabilities:Capabilities是一种更细粒度的权限控制机制,它允许进程在不完全提升到超级用户权限的情况下执行特定的特权操作。相比于SUID权限,Capabilities允许对特定的系统功能或资源进行更细粒度的控制,而不必完全获得文件所有者的权限。例如,某些操作可能需要访问网络套接字、执行系统管理任务、挂载文件系统等。使用Capabilities,可以授予进程仅限于执行这些特定操作所需的权限,而不必提升到完全的超级用户权限。这使得权限控制更加细致,并可以减少潜在的安全风险。

SUID权限是一个文件级别的权限机制,允许以文件所有者的权限执行文件。而Capabilities是一种更细粒度的权限机制,允许进程在不完全提升到超级用户权限的情况下执行特定的特权操作。两者都提供了在普通用户环境下执行特权操作的机制,但Capabilities提供了更灵活和细粒度的权限控制。

一、简介

NAMEcapabilities - overview of Linux capabilities

为了进行权限检查,传统的UNIX实现将进程分为两类:特权进程(有效用户ID为0,也称为超级用户或root)和非特权进程(有效用户ID非零)。特权进程可以绕过所有内核权限检查,而非特权进程则需根据进程的凭据(通常是有效用户ID、有效组ID和附加组列表)进行完整的权限检查。

从内核2.2版本开始,Linux将传统上与超级用户相关联的特权分为不同的单元,称为能力(capabilities),这些能力可以独立地启用和禁用。能力是每个线程的属性。

在Linux中,能力提供了一种细粒度的权限控制机制。传统上,超级用户拥有完整的系统权限,但在使用能力的情况下,特权可以分解为多个单独的能力,每个能力都代表一项特定的权限。通过启用或禁用不同的能力,可以以更细粒度的方式控制进程的特权。这样可以提高系统的安全性,使特权进程只具有执行特定任务所需的必要权限,而非特权进程则受到更严格的权限检查。

需要注意的是,能力是线程级别的属性,因此不同线程可以具有不同的能力配置。它们可以通过使用prctl系统调用来设置和修改。能力的使用在Linux系统中提供了一种更灵活和精细的权限管理机制。

通俗来一点说就是:传统UNIX系统中控制进程的权限,要么是高权限的 root 用户,要么是一般权限的普通用户,这时候的问题是,root 用户权限太大,而普通用户权限太小。有时候一个普通用户想做一点高权限的事情,必须给他整个 root 的权限。这个太不安全了。

对于普通用户运行的进程,当有某个权限(权限请参考:Capabilities list)的时候,就能做这些操作;没有的时候,就不能做,这样粒度要小很多。

二、Capabilities list

以下列表显示了在Linux上实现的 capabilities ,以及每个 capabilities 允许的操作或行为:

2.1 POSIX-draft defined capabilities

CAP_CHOWN:允许覆盖更改文件所有者和组所有者的限制。
CAP_DAC_OVERRIDE:允许覆盖所有DAC(自主访问控制)访问限制,包括ACL(访问控制列表)的执行访问控制。
CAP_DAC_READ_SEARCH:允许覆盖对文件和目录的读取和搜索操作的所有限制。
CAP_FOWNER:允许覆盖对文件所有者ID必须等于用户ID的操作的限制。
CAP_FSETID:允许覆盖对文件设置S_ISUID和S_ISGID位的限制。
CAP_KILL:允许覆盖发送信号的进程的实际或有效用户ID必须与接收信号的进程的实际或有效用户ID相匹配的限制。
CAP_SETGID:允许操作组ID设置。
CAP_SETUID:允许操作用户ID设置。

更详细请参考 man Capabilities 和 文件:

linux-5.4.18/include/uapi/linux/capability.h

2.2 Linux-specific capabilities

CAP_SETPCAP:允许修改进程的能力。
CAP_LINUX_IMMUTABLE:允许修改文件属性S_IMMUTABLE和S_APPEND。
CAP_NET_BIND_SERVICE:允许绑定到低于1024的TCP/UDP套接字。
CAP_NET_BROADCAST:允许广播和监听多播。
CAP_NET_ADMIN:允许接口配置、管理IP防火墙和路由表、设置套接字的调试选项等。
CAP_NET_RAW:允许使用RAW和PACKET套接字。
CAP_IPC_LOCK:允许锁定共享内存段和mlock/mlockall调用。
CAP_IPC_OWNER:覆盖IPC所有权检查。
CAP_SYS_MODULE:允许插入和删除内核模块。
CAP_SYS_RAWIO:允许原始I/O访问和向任何设备发送USB消息。
CAP_SYS_CHROOT:允许使用chroot()。
CAP_SYS_PTRACE:允许对任何进程进行ptrace()。
CAP_SYS_PACCT:允许配置进程账户。
CAP_SYS_ADMIN:允许各种管理任务,如挂载/卸载、访问设备特定功能等。
CAP_SYS_BOOT:允许使用reboot()。
CAP_SYS_NICE:允许提高其他进程的优先级和设置优先级。
CAP_SYS_RESOURCE:允许覆盖资源限制和配额限制,修改数据日志模式等。
CAP_SYS_TIME:允许配置系统时钟和设置实时时钟。
CAP_SYS_TTY_CONFIG:允许配置tty设备和vhangup()tty。
CAP_MKNOD:允许特权方面的mknod()。
CAP_LEASE:允许对文件进行租约。
CAP_AUDIT_WRITE:允许通过单播netlink套接字写入审计日志。
CAP_AUDIT_CONTROL:允许通过单播netlink套接字配置审计。
CAP_SETFCAP:允许设置文件能力。
CAP_MAC_OVERRIDE:覆盖MAC(强制访问控制)访问。
CAP_MAC_ADMIN:允许MAC配置或状态更改。
CAP_SYSLOG:允许配置内核的系统日志。
CAP_WAKE_ALARM:允许触发将唤醒系统的事件。
CAP_BLOCK_SUSPEND:允许阻止系统挂起。
CAP_AUDIT_READ:允许通过多播netlink套接字读取审计日志。

更详细请参考 man Capabilities 和 文件:

linux-5.4.18/include/uapi/linux/capability.h

三、 Past and current implementation

完整的能力实现需要满足以下条件:
(1)对于所有特权操作,内核必须检查线程是否在其有效能力集中具有所需的能力。

(2)内核必须提供系统调用,允许更改和检索线程的能力集。

(3)文件系统必须支持将能力附加到可执行文件,以便在执行文件时进程获取这些能力。

四、Thread capability sets

每个线程都有以下 capability sets ,包含零个或多个上述的 capabilities :

struct cred {kernel_cap_t	cap_inheritable; /* caps our children can inherit */kernel_cap_t	cap_permitted;	/* caps we're permitted */kernel_cap_t	cap_effective;	/* caps we can actually use */kernel_cap_t	cap_bset;	/* capability bounding set */kernel_cap_t	cap_ambient;	/* Ambient capability set */
}

(1)Permitted:该权限集合是线程可以使用的权限的上限。它定义了线程能够拥有的最大权限。如果线程从允许的权限集合中删除了某个权限,那么除非它执行一个具有相应文件权限的程序,否则它将无法重新获取该权限。

(2)Inheritable:该权限集合中包含了在执行execve()系统调用时会保留的权限。可继承的权限在执行任何程序时都会被保留,并且如果某个程序的文件可继承权限集合中相应的位被设置了,那么这些权限将被添加到允许的权限集合中。然而,可继承的权限通常在以非root用户身份运行时不会被保留,因此需要以提升的权限运行辅助程序的应用程序应考虑使用环境权限(下面介绍)。

简而言之:cap_inheritable 表示当可执行文件的扩展属性设置了 inheritable 位时,调用 exec 执行该程序会继承调用者的 inheritable 集合,并将其加入到 permitted 集合。但在非 root 用户下执行 exec 时,通常不会保留 inheritable 集合,但是往往又是非 root 用户,才想保留权限,所以Inheritable没有什么作用,因此在Linux 4.3版本引入Ambient位。

(3)Effective:该权限集合包含了内核用于对线程进行权限检查的权限。内核会检查生效的权限集合,以确定线程是否被允许执行特定的特权操作。

(4)Bounding:capability bounding set 是一种机制,可用于限制execve()期间获取的能力。自Linux 2.6.25起,这是一个每个线程的能力集。在旧内核中,能力边界集是一个系统范围的属性,由系统上的所有线程共享。有关能力边界集的更多细节,请参考:Capability bounding set 这一章节。

(5)Ambient(自Linux 4.3版本引入):该权限集合包含了在执行非特权程序的execve()调用时会保留的权限。环境权限集合遵循一个原则,即只有同时在允许的和可继承的权限集合中的权限才能成为环境权限。可以使用prctl()系统调用直接修改环境权限集合。如果对应的允许的或可继承的权限被降低,环境权限也会被自动降低。当执行改变用户或组ID的程序(由于设置了set-user-ID或set-group-ID位)或具有设置了文件权限的程序时,环境权限集合会被清除。在执行execve()时,环境权限会被添加到允许的权限集合中,并赋予生效的权限集合。

“ambient"掩码的作用是满足大多数人对"inheritable”(可继承)掩码的期望。如果某个能力位在"inheritable"和"permitted"中没有设置,那么它永远也不会在"ambient"中设置。

如果你是非root用户但具有某种能力,你可以将其添加到"ambient"中。如果这样做,你的子进程将在"ambient"、"permitted"和"effective"中获得该能力。例如,你可以在"ambient"中设置CAP_NET_BIND_SERVICE,这样你的子进程就可以自动绑定低端口号。非特权用户可以创建用户命名空间,将自己映射到非零UID,并创建特权(相对于其命名空间而言)和非特权进程树。

通过fork()创建的子进程会继承其父进程的权限集合的副本。关于在execve()期间权限的处理,请参见:Transformation of capabilities during execve()。

使用capset(),线程可以操作自己的权限集合(请参见下面的说明)。

自Linux 3.2版本以来,文件/proc/sys/kernel/cap_last_cap公开了运行内核支持的最高权限的数值;这可以用于确定权限集合中可以设置的最高位。

# uname -r
3.10.0-1160.el7.x86_64
# cat /proc/sys/kernel/cap_last_cap
36

五、File capabilities

自内核版本2.6.24以来,内核支持使用setcap()将权限集合与可执行文件关联起来。文件权限集合存储在一个名为security.capability的扩展属性中(参见setxattr())。要写入该扩展属性,需要具有CAP_SETFCAP权限。文件权限集合与线程的权限集合一起确定了execve()后线程的权限。

文件权限集合分为三种:
(1)Permitted(以前称为 forced 的):无论线程的可继承权限如何,这些权限都会自动授予线程。

(2)Inheritable(以前称为 allowed 的):将此集合与线程的可继承集合进行逻辑与操作,确定在execve()后线程的允许集合中启用了哪些可继承权限。

(3)Effective:这不是一个集合,而只是一个单独的位。如果设置了该位,在execve()期间,线程的所有新允许的权限也会在生效集合中提升。如果未设置该位,在execve()之后,新的允许权限都不会出现在新的生效集合中。

启用文件的生效权限位意味着任何导致线程在execve()期间获取相应允许权限的文件允许或可继承权限(参见下面描述的转换规则),在其生效集合中也会获取该权限。因此,当为文件分配权限(使用setcap()、cap_set_file()、cap_set_fd())时,如果我们指定了任何权限的生效标志为启用状态,则对于所有其他启用了相应允许或可继承标志的权限,也必须指定生效标志为启用状态。

六、Transformation of capabilities during execve()

在execve()期间,内核使用以下算法计算进程的新权限:

P'(ambient) = (file is privileged) ? 0 : P(ambient)P'(permitted) = (P(inheritable) & F(inheritable)) |(F(permitted) & cap_bset) | P'(ambient)P'(effective) = F(effective) ? P'(permitted) : P'(ambient)P'(inheritable) = P(inheritable)    [i.e., unchanged]

其中:

P表示`execve(2)`之前线程的权限集合的值P'表示`execve(2)`之后的权限集合的值F表示文件的权限集合cap_bset是权限限制集合的值(下面描述)

特权文件是具有权限或设置了set-user-ID或set-group-ID位的文件。

解释说明:
P’(ambient):如果文件是特权文件,则设置为0,否则设置为P(ambient)的值。P(ambient)是execve()之前线程的环境权限集合。

P’(permitted):通过将P(inheritable)和F(inheritable)进行逻辑与操作,将可继承权限与文件的可继承权限进行逻辑与操作。然后,通过将F(permitted)和cap_bset进行逻辑与操作,将文件的允许权限与权限限制集合进行逻辑与操作。最后,将上述结果与P’(ambient)进行逻辑或操作,得到新的允许权限集合。

P’(effective):如果文件的生效权限位(F(effective))被设置,则P’(effective)等于P’(permitted);否则,P’(effective)等于P’(ambient)。

P’(inheritable):保持不变,即等于P(inheritable),即execve()之前线程的可继承权限集合。

七、Capabilities and execution of programs by root

当进程执行具有设置了set-user-ID-root(SUID)权限的程序,或者有效用户ID为0(即root)的进程执行程序时,权限处理遵循特定的规则,使用权限集合提供全能的root权限语义:
(1)文件的可继承和允许权限集合:如果正在执行的程序具有SUID权限或者进程的真实用户ID为0(即root),则文件的可继承和允许权限集合被设置为全1,表示启用了所有权限。这允许进程继承并拥有文件定义的所有权限。

(2)文件的生效权限位:如果正在执行的程序具有SUID权限,则文件的生效权限位被设置为1,表示新的允许权限也会在生效集合中提升。这确保进程获得文件定义的生效权限。

通过将这些规则与之前描述的权限转换相结合,结果是当进程执行SUID-root程序或有效UID为0的进程执行程序时,它会获取其允许和生效权限集合中的所有权限,除了被权限限制集合屏蔽的权限。权限限制集合充当了可以获取的权限的限制或屏蔽。

这些规则提供了与传统UNIX系统相同的语义,在传统UNIX系统中,root用户具有完全的权限,当执行特权程序时,所有与root用户相关的权限都会被授予。

值得注意的是,使用权限集合相比传统的二进制root/non-root区分提供了更精细和灵活的特权管理方法。它允许对授予进程的权限进行更细粒度的控制,通过限制特权用户执行的各个程序的权限,增强了安全性。

八、Capability bounding set

权限限制集合(capability bounding set)是Linux中的一种安全机制,用于限制进程在执行execve()系统调用时获取的权限和特权。它通过限制进程执行新程序时可以获取的能力集,来限制进程所能获得的特权。

权限限制集合的使用方式如下:
(1)在execve()期间,权限限制集合与文件的允许权限集合进行按位与运算,并将运算结果赋值给线程的允许权限集合。因此,权限限制集合限制了可执行文件可能被授予的允许权限。

(2)(自Linux 2.6.25起)权限限制集合作为一个限制的超集,限制了线程可以使用capset()将哪些权限添加到其可继承权限集合中。这意味着,如果一个权限不在限制集合中,线程就无法将该权限添加到其可继承权限集合中,即使它在其允许的权限中,也无法在execve()执行具有该权限在其可继承权限集合中的文件时保留该权限在其允许权限集合中。

权限限制集合的主要作用是减少潜在的安全风险,防止未经授权的访问或滥用特权操作。

权限限制集合的功能依赖于内核的配置。如果内核编译时启用了文件权限功能,那么权限限制集合可以用于删除特权。如果未启用文件权限功能,权限限制集合仍然存在,但只能屏蔽CAP_SETPCAP特权。

在Linux 2.6.25及以上的内核版本中,权限限制集合是线程级别的属性。在fork()系统调用期间,线程会从父线程继承权限限制集合,并在execve()调用时保持不变。可以通过prctl()系统调用以及相应的操作来修改权限限制集合。例如,可以使用PR_CAPBSET_DROP操作从权限限制集合中删除特权。

在执行execve()系统调用时,权限限制集合中的特权与文件的允许特权进行交集运算。运算结果成为进程的允许特权集合。这样可以确保进程获取的特权不会超出权限限制集合所允许的范围。

权限限制集合不会影响进程继承的特权集合。如果一个特权在继承的集合中存在但不在权限限制集合中,仍然可以通过执行继承集合中包含该特权的文件来获得该特权。

需要注意的是,一旦特权从权限限制集合中删除,就无法重新添加该特权。权限限制集合是单向限制,无法逆转。

通过仔细配置和管理权限限制集合,系统管理员可以实施更严格的安全策略,控制进程所获得的特权。这有助于减少系统的攻击面,最小化被入侵进程的潜在影响。

九、Effect of user ID changes on capabilities

用户ID的更改对能力(capabilities)的影响如下:
(1)能力清除:当从一个或多个实际(real)、有效(effective)或保存(saved)用户ID为0的情况过渡到所有这些ID都为非零值的情况时,所有能力将从允许(permitted)和有效能力集中清除。这确保在进程的特权状态发生变化时,与根用户(UID 0)相关的能力不会被保留。

(2)有效能力集清除:如果将有效用户ID从0(root)更改为非零值,则所有能力将从有效能力集中清除。这样做可以防止在有效用户ID更改为普通用户时保留与根用户相关的任何能力。

(3)允许能力集复制:如果将有效用户ID从非零值更改为0(root),允许能力集将被复制到有效能力集中。这意味着即使以特权状态运行,进程只能使用显式允许的能力。

(4)文件系统用户ID变更:当文件系统用户ID(FSUID)从0更改为非零值时,与文件系统操作相关的某些能力将从有效能力集中清除。这些能力包括CAP_CHOWN、CAP_DAC_OVERRIDE、CAP_DAC_READ_SEARCH、CAP_FOWNER、CAP_FSETID、CAP_LINUX_IMMUTABLE、CAP_MAC_OVERRIDE和CAP_MKNOD。相反,如果FSUID从非零值更改为0,则在允许能力集中启用的任何这些能力都将在有效能力集中启用,允许进程在操作文件系统时运用这些能力。

(5)PR_SET_KEEPCAPS:如果线程希望在将所有用户ID重置为非零值时防止其允许能力集被清除,可以使用prctl()系统调用中的PR_SET_KEEPCAPS操作。这允许进程在从特权状态(UID 0)过渡到普通用户状态时保留其能力。

这些机制确保根据用户ID的变化调整能力,保持系统的安全性和特权分离。它们有助于防止进程保留不必要的特权,并减少特权提升攻击的潜在影响。

十、 Programmatically adjusting capability sets

可以通过使用capget()和capset()系统调用来检索和更改线程的能力集。然而,为此目的,推荐使用libcap软件包提供的cap_get_proc()和cap_set_proc()函数。以下规则适用于对线程能力集的更改:

(1)如果调用者没有CAP_SETPCAP能力,则新的可继承能力集必须是现有可继承能力集和可允许能力集的组合的子集。换句话说,调用者只能在现有可继承能力集和可允许能力集的基础上添加或保留能力。

(2)(自Linux 2.6.25起)新的可继承能力集必须是现有可继承能力集和能力边界集的组合的子集。能力边界集是一个系统范围的能力集,限制了任何进程可以拥有的最大能力。

(3)新的可允许能力集必须是现有可允许能力集的子集。也就是说,线程无法获取当前没有的可允许能力。可允许能力集表示线程当前可以获得的最大能力。

(4)新的有效能力集必须是新的可允许能力集的子集。有效能力集表示当前线程正在使用的能力。通过设置有效能力集,线程可以根据需要激活或禁用特定的能力。

参考资料

https://cloud.tencent.com/developer/article/1529342

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/90820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mmpretrain学习笔记

深度学习模型的训练涉及几个方面 1、模型结构:模型有几层、每层多少通道数等 2、数据:数据集划分、数据文件路径、批大小、数据增强策略等 3、训练优化 :梯度下降算法、学习率参数、训练总轮次、学习率变化策略等 4、运行时:GPU、…

【数据集】1985-2022年CLCD逐年土地利用分类数据

1985-2022年CLCD逐年土地利用分类数据 目前,CLCD 1985-2022年土地覆被数据集是较少的目前可公开获取的30m分辨率长时序逐年土地覆被数据。CLCD 反映了中国快速的城市化进程和一系列生态工程,揭示了气候变化条件下人为对土地覆盖的影响,其在全球变化研究中具有潜在应用价值。…

【多线程】线程安全的集合类

文章目录 1. 多线程环境使用ArrayList1.1 自己使用同步机制1.2 Collections.synchronizedList(new ArrayList);1.3 使用 CopyOnWriteArrayList 2. 多线程使用队列3. 多线程环境使用哈希表3.1 HashTable3.2 ConcurrentHashMap3.3 Hashtable和HashMap、ConcurrentHashMap 之间的区…

28 drf-Vue个人向总结-1

文章目录 前后端分离开发展示项目项补充知识开发问题浏览器解决跨域问题 drf 小tips设置资源root目录使用自定义的user表设置资源路径media数据库补充删除表中数据单页面与多页面模式过滤多层自关联后端提交的数据到底是什么jwt token登录设置普通的 token 原理使用流程解析 jw…

wallis匀色算法、直方图匹配、颜色转移方法比较

算法原理 这三种方法应该是比较基础的匀色处理算法 三个算法的原理比较简单,具体原理大家可以自己百度 (1)wallis匀色原理主要在于利用Wallis滤波器使原始图像的均值和标准差与参考影像相当,从而使原始影像和参考影像具有相近的色…

WebPack-打包工具

从图中我们可以看出,Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求. 下面举个例子 : main.js 我们只命名导出一个变量 export const name"老六"index.js import { name } from "./tset/…

第P7周—咖啡豆识别(1)

数据集及wen件目录介绍: 数据集:工作台 - Heywhale.com 一、前期工作 1.1 数据详情 import torch import torch.nn as nn import torchvision.transforms as transforms import torchvision from torchvision import transforms, datasets import os,…

聊聊KISS(Keep It Simple, Stupid)原则

文章目录 1. 前言2. KISS原则的几项描述3. KISS原则和奥卡姆剃刀原则区别 1. 前言 KISS原则,是Keep It Simple, Stupid的缩写,翻译成中文就是“保持简单,愚蠢的人也能懂”。这是一种鼓励简单设计的设计原则。 KISS原则的主要思想是&#x…

mysqlDM数据库中利用函数更新身份证字段,单表计算单表更新

#查询总数,男女的分别人数 SELECTcount( * ),sum( CASE WHEN gender 1 THEN 1 ELSE 0 END ) AS nan, sum( CASE WHEN gender 2 THEN 1 ELSE 0 END ) AS nv FROMt_user 写死版本的更新 #可以正确运行的sql,这样的话是写死版本 UPDATE t_user SET gender ( select sex fro…

python+pygame+opencv+gpt实现虚拟数字人直播(有趣的探索)

AI技术突飞猛进,不断的改变着人们的工作和生活。数字人直播作为新兴形式,必将成为未来趋势,具有巨大的、广阔的、惊人的市场前景。它将不断融合创新技术和跨界合作,提供更具个性化和多样化的互动体验,成为未来的一种趋…

Leetcode290. 单词规律

给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 解题思路:哈希 力扣(LeetCode&…

数据结构:堆的简单介绍

目录 堆的介绍:(PriorityQueue) 大根堆:根节点比左右孩子节点大 小根堆:根节点比左右孩子节点小 堆的存储结构: 为什么二叉树在逻辑上用满二叉树结构,而不是普通二叉树呢? 因为如果是普通二叉树会造成资源的浪费​编辑 堆的介绍:(PriorityQueue) 堆又称优先级队列,何为优先…

3 OpenCV两张图片实现稀疏点云的生成

前文: 1 基于SIFT图像特征识别的匹配方法比较与实现 2 OpenCV实现的F矩阵RANSAC原理与实践 1 E矩阵 1.1 由F到E E K T ∗ F ∗ K E K^T * F * K EKT∗F∗K E 矩阵可以直接通过之前算好的 F 矩阵与相机内参 K 矩阵获得 Mat E K.t() * F * K;相机内参获得的方式…

C/C++跨平台构建工具CMake入门

文章目录 1.概述2.环境准备2.1 安装编译工具2.2 安装CMake 3.编译一个示例程序总结 1.概述 本人一直对OpenGL的3d渲染很感兴趣,但是苦于自己一直是Android开发,没有机会接触这方面的知识。就在最近吗,机会来了,以前一个做3D渲染的…

【C/C++】C/C++面试八股

C/C面试八股 C和C语言的区别简单介绍一下三大特性多态的实现原理虚函数的构成原理虚函数的调用原理虚表指针在什么地方进行初始化的?构造函数为什么不能是虚函数虚函数和纯虚函数的区别抽象类类对象的对象模型内存对齐是什么?为什么要内存对齐static关键…

微信公众号网页授权登录获取用户基本信息

概述 微信公众号网页授权登录后微信获取用户基本信息,部署即可运行完整demo 详细 一、前言 (1)适合人群 1,JAVA服务端开发人员 2,初级人员开发人员 3,了解spring springboot maven 3,了…

k8s部署gin-vue-admin框架、gitlab-ci、jenkins pipeline 、CICD

测试环境使用的jenkins 正式环境使用的gitlab-ci 测试环境 创建yaml文件 apiVersion: v1 kind: ConfigMap metadata:name: dtk-go-tiktok-admin-configlabels:app.kubernetes.io/name: dtk-go-tiktok-adminapp.kubernetes.io/business: infrastructureapp.kubernetes.io/run…

中国312个历史文化名镇及景区空间点位数据集

一部中华史,既是人类创造丰富物质财富的奋头史,又是与自然共生共存的和谐史不仅留存下悠久丰富的人文思想和情怀,还在各处镌刻下可流传的生活场景,历史文化名镇(以下简称:名镇)就是这样真实的历史画卷。“镇”是一方的政治文化中心…

Elasticsearch:使用 Elasticsearch 进行语义搜索

在数字时代,搜索引擎在通过浏览互联网上的大量可用信息来检索数据方面发挥着重要作用。 此方法涉及用户在搜索栏中输入特定术语或短语,期望搜索引擎返回与这些确切关键字匹配的结果。 虽然关键字搜索对于简化信息检索非常有价值,但它也有其局…

红黑树是如何实现的?

文章目录 一、红黑树的概念二、红黑树的性质三、红黑树和AVL树对比四、红黑树的插入1. 红黑树的结点定义2. 父亲的颜色3. 叔叔的颜色为红色4. 叔叔不存在5. 叔叔存在且为黑6. 插入的抽象图 五、红黑树的验证1. 检查平衡2. 计算高度与旋转次数3. 验证 六、 红黑树与AVL树的比较 …