Re: [PATCH] Allow restricting permissions in /proc/sys

From: Christian Brauner
Date: Tue Nov 12 2019 - 18:22:47 EST


[Cc+ linux-api@xxxxxxxxxxxxxxx]

since that's potentially relevant to quite a few people.

On Sun, Nov 03, 2019 at 04:55:48PM +0200, Topi Miettinen wrote:
> Several items in /proc/sys need not be accessible to unprivileged
> tasks. Let the system administrator change the permissions, but only
> to more restrictive modes than what the sysctl tables allow.
>
> Signed-off-by: Topi Miettinen <toiwoton@xxxxxxxxx>
> ---
> fs/proc/proc_sysctl.c | 41 +++++++++++++++++++++++++++++++----------
> 1 file changed, 31 insertions(+), 10 deletions(-)
>
> diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> index d80989b6c344..88c4ca7d2782 100644
> --- a/fs/proc/proc_sysctl.c
> +++ b/fs/proc/proc_sysctl.c
> @@ -818,6 +818,10 @@ static int proc_sys_permission(struct inode *inode, int
> mask)
> if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
> return -EACCES;
>
> + error = generic_permission(inode, mask);
> + if (error)
> + return error;
> +
> head = grab_header(inode);
> if (IS_ERR(head))
> return PTR_ERR(head);
> @@ -837,9 +841,35 @@ static int proc_sys_setattr(struct dentry *dentry,
> struct iattr *attr)
> struct inode *inode = d_inode(dentry);
> int error;
>
> - if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
> + if (attr->ia_valid & (ATTR_UID | ATTR_GID))
> return -EPERM;
>
> + if (attr->ia_valid & ATTR_MODE) {
> + struct ctl_table_header *head = grab_header(inode);
> + struct ctl_table *table = PROC_I(inode)->sysctl_entry;
> + umode_t max_mode = 0777; /* Only these bits may change */
> +
> + if (IS_ERR(head))
> + return PTR_ERR(head);
> +
> + if (!table) /* global root - r-xr-xr-x */
> + max_mode &= ~0222;
> + else /*
> + * Don't allow permissions to become less
> + * restrictive than the sysctl table entry
> + */
> + max_mode &= table->mode;
> +
> + sysctl_head_finish(head);
> +
> + /* Execute bits only allowed for directories */
> + if (!S_ISDIR(inode->i_mode))
> + max_mode &= ~0111;
> +
> + if (attr->ia_mode & ~S_IFMT & ~max_mode)
> + return -EPERM;
> + }
> +
> error = setattr_prepare(dentry, attr);
> if (error)
> return error;
> @@ -853,17 +883,8 @@ static int proc_sys_getattr(const struct path *path,
> struct kstat *stat,
> u32 request_mask, unsigned int query_flags)
> {
> struct inode *inode = d_inode(path->dentry);
> - struct ctl_table_header *head = grab_header(inode);
> - struct ctl_table *table = PROC_I(inode)->sysctl_entry;
> -
> - if (IS_ERR(head))
> - return PTR_ERR(head);
>
> generic_fillattr(inode, stat);
> - if (table)
> - stat->mode = (stat->mode & S_IFMT) | table->mode;
> -
> - sysctl_head_finish(head);
> return 0;
> }
>
> --
> 2.24.0.rc1
>