当前位置: 首页 > news >正文

Linux keyring_search密钥环搜索与key_ref_validate

Linux keyring_search密钥环搜索与key_ref_validate

内核密钥管理框架的主搜索接口是keyring_search,定义在security/keys/keyring.c中。该函数在指定密钥环及其链接的子密钥环中递归查找匹配特定描述和类型的密钥。

函数原型及参数说明:

key_ref_t keyring_search(key_ref_t keyring_ref, struct key_type *type,
const char *description, bool recurse)
{
struct key *keyring;
key_ref_t key_ref;
bool possessed;

keyring = key_ref_to_ptr(keyring_ref);
possessed = is_key_possessed(keyring_ref);

if (!(keyring->flags & ((1 << KEY_FLAG_SET) |
(1 << KEY_FLAG_ROOT_CAN_CLEAR))))
return ERR_PTR(-ENOKEY);

rcu_read_lock();
if (recurse)
key_ref = search_rcu(keyring, type, description, possessed,
KEYRING_SEARCH_DO_STATE_CHECK);
else
key_ref = search_link_rcu(keyring, type, description, possessed,
KEYRING_SEARCH_DO_STATE_CHECK);
rcu_read_unlock();

if (IS_ERR(key_ref))
return key_ref;

return key_ref;
}

search_rcu是递归搜索的核心实现,在RCU读锁保护下遍历密钥环的链接链表:

static key_ref_t search_rcu(struct key *keyring, struct key_type *type,
const char *description, bool possessed,
unsigned int flags)
{
struct keyring_search_context ctx = {
.index_key.type = type,
.index_key.description = description,
.index_key.desc_len = strlen(description),
.possessed = possessed,
.flags = flags,
.skip = NULL,
.matched_key_ref = NULL,
.result = ERR_PTR(-EAGAIN),
};
int ret;

ret = keyring_search_rcu(keyring, &ctx);
if (ret < 0)
return ERR_PTR(ret);
return ctx.result;
}

搜索上下文struct keyring_search_context携带索引匹配参数:

struct keyring_search_context {
struct keyring_index_key index_key;
const struct cred *cred;
key_perm_t permit;
int (*match)(const struct key *key, const struct keyring_index_key *index_key);
bool possessed;
unsigned int flags;
struct key *skip;
key_ref_t result;
};

keyring_search_rcu对密钥环的keyring_assoc_array进行递归遍历:

static int keyring_search_rcu(struct key *keyring, struct keyring_search_context *ctx)
{
struct keyring_assoc *assoc;
struct key *key;
int ret;

assoc = rcu_dereference(keyring->assoc_array);
if (!assoc)
return -ENOKEY;

ret = assoc_array_find(&assoc->array,
&keyring_assoc_ops,
&ctx->index_key);
if (ret == 0)
return -ENOKEY;

key = keyring_ptr_to_key(keyring, assoc);
if (!key)
return -ENOKEY;

ctx->result = make_key_ref(key, ctx->possessed);
return 0;
}

当搜索命中后,key_ref_validate对返回的key_ref进行权限和状态检查:

key_ref_t key_ref_validate(key_ref_t key_ref, unsigned long op)
{
struct key *key = key_ref_to_ptr(key_ref);
key_perm_t perm;
int ret;

if (!key)
return ERR_PTR(-ENOKEY);

ret = key_validate(key);
if (ret < 0)
return ERR_PTR(ret);

perm = key_permission(key_ref, op);
if (perm)
return ERR_PTR(perm);

if (test_bit(KEY_FLAG_BUILTIN, &key->flags))
return key_ref;

return key_ref;
}

key_validate检查密钥的生命周期状态:

int key_validate(const struct key *key)
{
if (test_bit(KEY_FLAG_DEAD, &key->flags) ||
test_bit(KEY_FLAG_INVALIDATED, &key->flags))
return -ENOKEY;

if (test_bit(KEY_FLAG_REVOKED, &key->flags))
return -EKEYREVOKED;

if (key->expiry && key->expiry <= ktime_get_real_seconds())
return -EKEYEXPIRED;

return 0;
}

key_permission根据操作码(op)检查访问权限:

int key_permission(key_ref_t key_ref, unsigned long op)
{
struct key *key = key_ref_to_ptr(key_ref);
kuid_t uid;
unsigned long perm;
bool possessed = is_key_possessed(key_ref);

if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR, &key->flags) && capable(CAP_SYS_ADMIN))
goto ok;

uid = current_fsuid();
if (uid_eq(key->uid, uid)) {
perm = KEY_POS_SEE | KEY_POS_READ | KEY_POS_WRITE |
KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
} else if (uid_eq(key->uid, GLOBAL_ROOT_UID)) {
perm = KEY_USR_SEE | KEY_USR_READ | KEY_USR_WRITE |
KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
} else {
if (in_group_p(key->gid))
perm = KEY_GRP_ALL;
else
perm = KEY_OTH_ALL;
}

if (possessed)
perm &= KEY_POSS_ALL;

if ((perm & op) != op)
return -EACCES;
ok:
return 0;
}

实际的keyring搜索使用标记包含了KEYRING_SEARCH_DO_STATE_CHECK标志,它控制是否在搜索时跳过过期或被撤销的密钥。搜索过程中调用keyring_match检查description精确匹配。

keyring_search的典型使用场景:

static int verify_signature_with_keyring(struct key *keyring,
struct public_key_signature *sig)
{
key_ref_t key_ref;
struct key *key;
int ret;

key_ref = keyring_search(make_key_ref(keyring, true),
&key_type_asymmetric,
sig->key_id->data,
true);
if (IS_ERR(key_ref))
return PTR_ERR(key_ref);

key_ref = key_ref_validate(key_ref, KEY_NEED_SEARCH);
if (IS_ERR(key_ref))
return PTR_ERR(key_ref);

key = key_ref_to_ptr(key_ref);
ret = verify_signature(key, sig);
key_put(key);
return ret;
}

密钥环搜索从指定keyref开始,recurse=true时递归遍历嵌套密钥环。搜索优先级按assoc_array的排序规则,遍历所有匹配项,返回第一个符合条件的结果。

http://www.jsqmd.com/news/1006604/

相关文章:

  • MC68341定时器模块:可变宽度单脉冲生成与脉冲宽度测量实战解析
  • Linux jbd2_journal_recover日志恢复与superblock标记
  • UUV Simulator终极指南:快速构建高保真水下机器人仿真系统
  • 深入解析MC9328MX1 UART驱动:从寄存器配置到中断处理的嵌入式实战
  • 2026年6月最新|充气帐篷厂家哪家好?专业生产厂家实力口碑排行推荐 - 商业新知
  • 革命性开源5G测试平台:UERANSIM如何让5G研发变得简单高效
  • 【Springboot毕设全套源码+文档】基于Spring Boot的奖学金评定管理系统设计与实现(丰富项目+远程调试+讲解+定制)
  • 2026甄选郑州名酒回收实体店联系方式,专业鉴定与诚信回收的可靠选择 - 企业推荐官【官方】
  • 漳州报名 CPPM 注册采购经理哪家靠谱?机构选择避坑指南 - 众智商学院课程中心
  • 2026湖北电大中专报名条件及报考须知|湖北成人中专报考答疑 - 善良的阿良
  • 2026年6月南通劳保手套工厂排行:服务与品质双维度深度盘点 - 奔跑123
  • 刷CF #1900 二周目
  • Python 高手编程系列三千三百七十八:构建自己的文档集
  • 2026年6月国内松木镜框油画布框套装定制服务商排行top5,资质与专业评测推荐 - 奔跑123
  • 如何快速部署AI模型到嵌入式设备:5大实用技巧与RKNN-Toolkit2终极指南
  • 2026温州打捞队真实记录:本地榜单TOP1,这些水域都靠他们 - 速递信息
  • Linux jbd2_journal_commit_transaction日志提交与forget链表
  • 从ImageNet-22k到ImageNet-1k:swinv2_base_window12to16_192to256.ms_in22k_ft_in1k训练策略分析
  • 2026 青岛汽车音响改装靠谱度榜首:鼎峰汇汽车音响,被低估的技术标杆 - 汽车音响改装
  • 3分钟掌握Blender建筑生成:Building Tools终极指南
  • 鸿蒙原生应用实战(五):教程、主题与项目总结 — 从开发到上线的完整回顾
  • 3种高效WebRTC流媒体架构方案对比与Metahuman-Stream部署优化指南
  • League Akari:本地化英雄联盟智能助手完整实用指南
  • Visual Syslog Server:为Windows系统打造的专业级集中日志管理解决方案
  • 2026西安钻石回收翘楚,本地赛道顶流王机构测评 - 讯息早知道
  • 别再乱用快照了!QEMU磁盘快照和检查点快照的保姆级区别与实战(Windows+Debian)
  • texture-vs-shape项目FAQ全解答:从刺激集获取到模型评估的常见问题
  • DLSS Swapper终极指南:智能游戏性能优化方案
  • 2026石家庄翡翠回收深度实测:七家机构种水色工专项横评 - 薛定谔的梨花猫
  • 2026 南宁装修公司哪家靠谱?实测十大口碑品牌汇总 - 装修新知