psp: add admin/non-admin version of psp_device_get_locked

Introduce 2 versions of psp_device_get_locked:
1. psp_device_get_locked_admin(): This version is used for operations
   that would change the status of the psd, and are currently used for
   dev-set and key-rotation.
2. psp_device_get_locked(): This is the non-admin version, which are
   used for broader user issued operations including: dev-get, rx-assoc,
   tx-assoc, get-stats.

Following commit will be implementing both of the checks.

Signed-off-by: Wei Wang <weibunny@fb.com>
Reviewed-by: Daniel Zahka <daniel.zahka@gmail.com>
Link: https://patch.msgid.link/20260608233118.2694144-2-weibunny.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Wei Wang
2026-06-08 16:31:09 -07:00
committed by Jakub Kicinski
parent eee2d0676d
commit 1c88a46647
6 changed files with 37 additions and 15 deletions

View File

@@ -196,7 +196,7 @@ operations:
- psp-versions-ena
reply:
attributes: []
pre: psp-device-get-locked
pre: psp-device-get-locked-admin
post: psp-device-unlock
-
name: dev-change-ntf
@@ -216,7 +216,7 @@ operations:
reply:
attributes:
- id
pre: psp-device-get-locked
pre: psp-device-get-locked-admin
post: psp-device-unlock
-
name: key-rotate-ntf

View File

@@ -71,7 +71,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
},
{
.cmd = PSP_CMD_DEV_SET,
.pre_doit = psp_device_get_locked,
.pre_doit = psp_device_get_locked_admin,
.doit = psp_nl_dev_set_doit,
.post_doit = psp_device_unlock,
.policy = psp_dev_set_nl_policy,
@@ -80,7 +80,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
},
{
.cmd = PSP_CMD_KEY_ROTATE,
.pre_doit = psp_device_get_locked,
.pre_doit = psp_device_get_locked_admin,
.doit = psp_nl_key_rotate_doit,
.post_doit = psp_device_unlock,
.policy = psp_key_rotate_nl_policy,

View File

@@ -17,6 +17,8 @@ extern const struct nla_policy psp_keys_nl_policy[PSP_A_KEYS_SPI + 1];
int psp_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int psp_device_get_locked_admin(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
void

View File

@@ -14,7 +14,7 @@ extern struct xarray psp_devs;
extern struct mutex psp_devs_lock;
void psp_dev_free(struct psp_dev *psd);
int psp_dev_check_access(struct psp_dev *psd, struct net *net);
int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin);
void psp_nl_notify_dev(struct psp_dev *psd, u32 cmd);

View File

@@ -27,10 +27,15 @@ struct mutex psp_devs_lock;
* psp_dev_check_access() - check if user in a given net ns can access PSP dev
* @psd: PSP device structure user is trying to access
* @net: net namespace user is in
* @admin: If true, only allow access from @psd's main device's netns,
* for admin operations like config changes and key rotation.
* If false, also allow access from network namespaces that have
* an associated device with @psd, for read-only and association
* management operations.
*
* Return: 0 if PSP device should be visible in @net, errno otherwise.
*/
int psp_dev_check_access(struct psp_dev *psd, struct net *net)
int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin)
{
if (dev_net(psd->main_netdev) == net)
return 0;

View File

@@ -41,7 +41,8 @@ static int psp_nl_reply_send(struct sk_buff *rsp, struct genl_info *info)
/* Device stuff */
static struct psp_dev *
psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
psp_device_get_and_lock(struct net *net, struct nlattr *dev_id,
bool admin)
{
struct psp_dev *psd;
int err;
@@ -56,7 +57,7 @@ psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
mutex_lock(&psd->lock);
mutex_unlock(&psp_devs_lock);
err = psp_dev_check_access(psd, net);
err = psp_dev_check_access(psd, net, admin);
if (err) {
mutex_unlock(&psd->lock);
return ERR_PTR(err);
@@ -65,17 +66,31 @@ psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
return psd;
}
int psp_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
static int __psp_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info,
bool admin)
{
if (GENL_REQ_ATTR_CHECK(info, PSP_A_DEV_ID))
return -EINVAL;
info->user_ptr[0] = psp_device_get_and_lock(genl_info_net(info),
info->attrs[PSP_A_DEV_ID]);
info->attrs[PSP_A_DEV_ID],
admin);
return PTR_ERR_OR_ZERO(info->user_ptr[0]);
}
int psp_device_get_locked_admin(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
return __psp_device_get_locked(ops, skb, info, true);
}
int psp_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info)
{
return __psp_device_get_locked(ops, skb, info, false);
}
void
psp_device_unlock(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info)
@@ -160,7 +175,7 @@ static int
psp_nl_dev_get_dumpit_one(struct sk_buff *rsp, struct netlink_callback *cb,
struct psp_dev *psd)
{
if (psp_dev_check_access(psd, sock_net(rsp->sk)))
if (psp_dev_check_access(psd, sock_net(rsp->sk), false))
return 0;
return psp_nl_dev_fill(psd, rsp, genl_info_dump(cb));
@@ -310,7 +325,7 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
*/
mutex_lock(&psd->lock);
if (!psp_dev_is_registered(psd) ||
psp_dev_check_access(psd, genl_info_net(info))) {
psp_dev_check_access(psd, genl_info_net(info), false)) {
mutex_unlock(&psd->lock);
psp_dev_put(psd);
psd = NULL;
@@ -334,7 +349,7 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
psp_dev_put(psd);
} else {
psd = psp_device_get_and_lock(genl_info_net(info), id);
psd = psp_device_get_and_lock(genl_info_net(info), id, false);
if (IS_ERR(psd)) {
err = PTR_ERR(psd);
goto err_sock_put;
@@ -577,7 +592,7 @@ static int
psp_nl_stats_get_dumpit_one(struct sk_buff *rsp, struct netlink_callback *cb,
struct psp_dev *psd)
{
if (psp_dev_check_access(psd, sock_net(rsp->sk)))
if (psp_dev_check_access(psd, sock_net(rsp->sk), false))
return 0;
return psp_nl_stats_fill(psd, rsp, genl_info_dump(cb));