mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 09:43:59 +08:00
\n
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAmPvZJwACgkQnJ2qBz9k QNlPcAf/UL7DDv37vnvfcFTa9lRyC0dXsgxnVZUwMU0hJs/ewbmueYGnJSBRTVLG 7ad7bKYQVWsjhas4YulofgRrFWxVDcR32qbC+pDo/X6vGjo4tDl2CNPYREY3n3kN xR6Ca7nPxBH5AVYwwOqBJSTqhWGy1TSDeuskndS0P+YtTv6Y4Zvm4UEiNAXJ4nwo 5Nd+bsPpkrEgQqO/NK2rCXfBfkJr4jAMcp+Nn2zAP44icZAXJYn8QrN3gVL6OZlN RKq36MGQf52lxyufVyFCulWKRbxhEKUS0nURZgAG+Sv87DlSuBJgRVG7xJ1baPpK 2g7wG2jaT7YMfA4PWms/rwAj/CkGLA== =NRh0 -----END PGP SIGNATURE----- Merge tag 'fsnotify_for_v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs Pull fsnotify updates from Jan Kara: "Support for auditing decisions regarding fanotify permission events" * tag 'fsnotify_for_v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fanotify,audit: Allow audit to use the full permission event response fanotify: define struct members to hold response decision context fanotify: Ensure consistent variable type for response
This commit is contained in:
commit
cd776a4342
@ -262,7 +262,7 @@ static int fanotify_get_response(struct fsnotify_group *group,
|
||||
}
|
||||
|
||||
/* userspace responded, convert to something usable */
|
||||
switch (event->response & ~FAN_AUDIT) {
|
||||
switch (event->response & FANOTIFY_RESPONSE_ACCESS) {
|
||||
case FAN_ALLOW:
|
||||
ret = 0;
|
||||
break;
|
||||
@ -273,7 +273,8 @@ static int fanotify_get_response(struct fsnotify_group *group,
|
||||
|
||||
/* Check if the response should be audited */
|
||||
if (event->response & FAN_AUDIT)
|
||||
audit_fanotify(event->response & ~FAN_AUDIT);
|
||||
audit_fanotify(event->response & ~FAN_AUDIT,
|
||||
&event->audit_rule);
|
||||
|
||||
pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
|
||||
group, event, ret);
|
||||
@ -563,6 +564,9 @@ static struct fanotify_event *fanotify_alloc_perm_event(const struct path *path,
|
||||
|
||||
pevent->fae.type = FANOTIFY_EVENT_TYPE_PATH_PERM;
|
||||
pevent->response = 0;
|
||||
pevent->hdr.type = FAN_RESPONSE_INFO_NONE;
|
||||
pevent->hdr.pad = 0;
|
||||
pevent->hdr.len = 0;
|
||||
pevent->state = FAN_EVENT_INIT;
|
||||
pevent->path = *path;
|
||||
path_get(path);
|
||||
|
@ -425,9 +425,13 @@ FANOTIFY_PE(struct fanotify_event *event)
|
||||
struct fanotify_perm_event {
|
||||
struct fanotify_event fae;
|
||||
struct path path;
|
||||
unsigned short response; /* userspace answer to the event */
|
||||
u32 response; /* userspace answer to the event */
|
||||
unsigned short state; /* state of the event */
|
||||
int fd; /* fd we passed to userspace for this event */
|
||||
union {
|
||||
struct fanotify_response_info_header hdr;
|
||||
struct fanotify_response_info_audit_rule audit_rule;
|
||||
};
|
||||
};
|
||||
|
||||
static inline struct fanotify_perm_event *
|
||||
|
@ -283,19 +283,42 @@ static int create_fd(struct fsnotify_group *group, const struct path *path,
|
||||
return client_fd;
|
||||
}
|
||||
|
||||
static int process_access_response_info(const char __user *info,
|
||||
size_t info_len,
|
||||
struct fanotify_response_info_audit_rule *friar)
|
||||
{
|
||||
if (info_len != sizeof(*friar))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(friar, info, sizeof(*friar)))
|
||||
return -EFAULT;
|
||||
|
||||
if (friar->hdr.type != FAN_RESPONSE_INFO_AUDIT_RULE)
|
||||
return -EINVAL;
|
||||
if (friar->hdr.pad != 0)
|
||||
return -EINVAL;
|
||||
if (friar->hdr.len != sizeof(*friar))
|
||||
return -EINVAL;
|
||||
|
||||
return info_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish processing of permission event by setting it to ANSWERED state and
|
||||
* drop group->notification_lock.
|
||||
*/
|
||||
static void finish_permission_event(struct fsnotify_group *group,
|
||||
struct fanotify_perm_event *event,
|
||||
unsigned int response)
|
||||
struct fanotify_perm_event *event, u32 response,
|
||||
struct fanotify_response_info_audit_rule *friar)
|
||||
__releases(&group->notification_lock)
|
||||
{
|
||||
bool destroy = false;
|
||||
|
||||
assert_spin_locked(&group->notification_lock);
|
||||
event->response = response;
|
||||
event->response = response & ~FAN_INFO;
|
||||
if (response & FAN_INFO)
|
||||
memcpy(&event->audit_rule, friar, sizeof(*friar));
|
||||
|
||||
if (event->state == FAN_EVENT_CANCELED)
|
||||
destroy = true;
|
||||
else
|
||||
@ -306,20 +329,27 @@ static void finish_permission_event(struct fsnotify_group *group,
|
||||
}
|
||||
|
||||
static int process_access_response(struct fsnotify_group *group,
|
||||
struct fanotify_response *response_struct)
|
||||
struct fanotify_response *response_struct,
|
||||
const char __user *info,
|
||||
size_t info_len)
|
||||
{
|
||||
struct fanotify_perm_event *event;
|
||||
int fd = response_struct->fd;
|
||||
int response = response_struct->response;
|
||||
u32 response = response_struct->response;
|
||||
int ret = info_len;
|
||||
struct fanotify_response_info_audit_rule friar;
|
||||
|
||||
pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
|
||||
fd, response);
|
||||
pr_debug("%s: group=%p fd=%d response=%u buf=%p size=%zu\n", __func__,
|
||||
group, fd, response, info, info_len);
|
||||
/*
|
||||
* make sure the response is valid, if invalid we do nothing and either
|
||||
* userspace can send a valid response or we will clean it up after the
|
||||
* timeout
|
||||
*/
|
||||
switch (response & ~FAN_AUDIT) {
|
||||
if (response & ~FANOTIFY_RESPONSE_VALID_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
switch (response & FANOTIFY_RESPONSE_ACCESS) {
|
||||
case FAN_ALLOW:
|
||||
case FAN_DENY:
|
||||
break;
|
||||
@ -327,10 +357,20 @@ static int process_access_response(struct fsnotify_group *group,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
|
||||
return -EINVAL;
|
||||
|
||||
if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
|
||||
if (response & FAN_INFO) {
|
||||
ret = process_access_response_info(info, info_len, &friar);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (fd == FAN_NOFD)
|
||||
return ret;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&group->notification_lock);
|
||||
@ -340,9 +380,9 @@ static int process_access_response(struct fsnotify_group *group,
|
||||
continue;
|
||||
|
||||
list_del_init(&event->fae.fse.list);
|
||||
finish_permission_event(group, event, response);
|
||||
finish_permission_event(group, event, response, &friar);
|
||||
wake_up(&group->fanotify_data.access_waitq);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
spin_unlock(&group->notification_lock);
|
||||
|
||||
@ -804,7 +844,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
|
||||
if (ret <= 0) {
|
||||
spin_lock(&group->notification_lock);
|
||||
finish_permission_event(group,
|
||||
FANOTIFY_PERM(event), FAN_DENY);
|
||||
FANOTIFY_PERM(event), FAN_DENY, NULL);
|
||||
wake_up(&group->fanotify_data.access_waitq);
|
||||
} else {
|
||||
spin_lock(&group->notification_lock);
|
||||
@ -827,28 +867,32 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
|
||||
|
||||
static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
|
||||
{
|
||||
struct fanotify_response response = { .fd = -1, .response = -1 };
|
||||
struct fanotify_response response;
|
||||
struct fsnotify_group *group;
|
||||
int ret;
|
||||
const char __user *info_buf = buf + sizeof(struct fanotify_response);
|
||||
size_t info_len;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
|
||||
return -EINVAL;
|
||||
|
||||
group = file->private_data;
|
||||
|
||||
pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
|
||||
|
||||
if (count < sizeof(response))
|
||||
return -EINVAL;
|
||||
|
||||
count = sizeof(response);
|
||||
|
||||
pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
|
||||
|
||||
if (copy_from_user(&response, buf, count))
|
||||
if (copy_from_user(&response, buf, sizeof(response)))
|
||||
return -EFAULT;
|
||||
|
||||
ret = process_access_response(group, &response);
|
||||
info_len = count - sizeof(response);
|
||||
|
||||
ret = process_access_response(group, &response, info_buf, info_len);
|
||||
if (ret < 0)
|
||||
count = ret;
|
||||
else
|
||||
count = sizeof(response) + ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -876,7 +920,7 @@ static int fanotify_release(struct inode *ignored, struct file *file)
|
||||
event = list_first_entry(&group->fanotify_data.access_list,
|
||||
struct fanotify_perm_event, fae.fse.list);
|
||||
list_del_init(&event->fae.fse.list);
|
||||
finish_permission_event(group, event, FAN_ALLOW);
|
||||
finish_permission_event(group, event, FAN_ALLOW, NULL);
|
||||
spin_lock(&group->notification_lock);
|
||||
}
|
||||
|
||||
@ -893,7 +937,7 @@ static int fanotify_release(struct inode *ignored, struct file *file)
|
||||
fsnotify_destroy_event(group, fsn_event);
|
||||
} else {
|
||||
finish_permission_event(group, FANOTIFY_PERM(event),
|
||||
FAN_ALLOW);
|
||||
FAN_ALLOW, NULL);
|
||||
}
|
||||
spin_lock(&group->notification_lock);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/audit_arch.h>
|
||||
#include <uapi/linux/audit.h>
|
||||
#include <uapi/linux/netfilter/nf_tables.h>
|
||||
#include <uapi/linux/fanotify.h>
|
||||
|
||||
#define AUDIT_INO_UNSET ((unsigned long)-1)
|
||||
#define AUDIT_DEV_UNSET ((dev_t)-1)
|
||||
@ -416,7 +417,7 @@ extern void __audit_log_capset(const struct cred *new, const struct cred *old);
|
||||
extern void __audit_mmap_fd(int fd, int flags);
|
||||
extern void __audit_openat2_how(struct open_how *how);
|
||||
extern void __audit_log_kern_module(char *name);
|
||||
extern void __audit_fanotify(unsigned int response);
|
||||
extern void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar);
|
||||
extern void __audit_tk_injoffset(struct timespec64 offset);
|
||||
extern void __audit_ntp_log(const struct audit_ntp_data *ad);
|
||||
extern void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
|
||||
@ -523,10 +524,10 @@ static inline void audit_log_kern_module(char *name)
|
||||
__audit_log_kern_module(name);
|
||||
}
|
||||
|
||||
static inline void audit_fanotify(unsigned int response)
|
||||
static inline void audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
|
||||
{
|
||||
if (!audit_dummy_context())
|
||||
__audit_fanotify(response);
|
||||
__audit_fanotify(response, friar);
|
||||
}
|
||||
|
||||
static inline void audit_tk_injoffset(struct timespec64 offset)
|
||||
@ -679,7 +680,7 @@ static inline void audit_log_kern_module(char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void audit_fanotify(unsigned int response)
|
||||
static inline void audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
|
||||
{ }
|
||||
|
||||
static inline void audit_tk_injoffset(struct timespec64 offset)
|
||||
|
@ -122,6 +122,11 @@
|
||||
#define ALL_FANOTIFY_EVENT_BITS (FANOTIFY_OUTGOING_EVENTS | \
|
||||
FANOTIFY_EVENT_FLAGS)
|
||||
|
||||
/* These masks check for invalid bits in permission responses. */
|
||||
#define FANOTIFY_RESPONSE_ACCESS (FAN_ALLOW | FAN_DENY)
|
||||
#define FANOTIFY_RESPONSE_FLAGS (FAN_AUDIT | FAN_INFO)
|
||||
#define FANOTIFY_RESPONSE_VALID_MASK (FANOTIFY_RESPONSE_ACCESS | FANOTIFY_RESPONSE_FLAGS)
|
||||
|
||||
/* Do not use these old uapi constants internally */
|
||||
#undef FAN_ALL_CLASS_BITS
|
||||
#undef FAN_ALL_INIT_FLAGS
|
||||
|
@ -188,15 +188,43 @@ struct fanotify_event_info_error {
|
||||
__u32 error_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* User space may need to record additional information about its decision.
|
||||
* The extra information type records what kind of information is included.
|
||||
* The default is none. We also define an extra information buffer whose
|
||||
* size is determined by the extra information type.
|
||||
*
|
||||
* If the information type is Audit Rule, then the information following
|
||||
* is the rule number that triggered the user space decision that
|
||||
* requires auditing.
|
||||
*/
|
||||
|
||||
#define FAN_RESPONSE_INFO_NONE 0
|
||||
#define FAN_RESPONSE_INFO_AUDIT_RULE 1
|
||||
|
||||
struct fanotify_response {
|
||||
__s32 fd;
|
||||
__u32 response;
|
||||
};
|
||||
|
||||
struct fanotify_response_info_header {
|
||||
__u8 type;
|
||||
__u8 pad;
|
||||
__u16 len;
|
||||
};
|
||||
|
||||
struct fanotify_response_info_audit_rule {
|
||||
struct fanotify_response_info_header hdr;
|
||||
__u32 rule_number;
|
||||
__u32 subj_trust;
|
||||
__u32 obj_trust;
|
||||
};
|
||||
|
||||
/* Legit userspace responses to a _PERM event */
|
||||
#define FAN_ALLOW 0x01
|
||||
#define FAN_DENY 0x02
|
||||
#define FAN_AUDIT 0x10 /* Bit mask to create audit record for result */
|
||||
#define FAN_AUDIT 0x10 /* Bitmask to create audit record for result */
|
||||
#define FAN_INFO 0x20 /* Bitmask to indicate additional information */
|
||||
|
||||
/* No fd set in event */
|
||||
#define FAN_NOFD -1
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include <uapi/linux/limits.h>
|
||||
#include <uapi/linux/netfilter/nf_tables.h>
|
||||
#include <uapi/linux/openat2.h> // struct open_how
|
||||
#include <uapi/linux/fanotify.h>
|
||||
|
||||
#include "audit.h"
|
||||
|
||||
@ -2877,10 +2878,21 @@ void __audit_log_kern_module(char *name)
|
||||
context->type = AUDIT_KERN_MODULE;
|
||||
}
|
||||
|
||||
void __audit_fanotify(unsigned int response)
|
||||
void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
|
||||
{
|
||||
audit_log(audit_context(), GFP_KERNEL,
|
||||
AUDIT_FANOTIFY, "resp=%u", response);
|
||||
/* {subj,obj}_trust values are {0,1,2}: no,yes,unknown */
|
||||
switch (friar->hdr.type) {
|
||||
case FAN_RESPONSE_INFO_NONE:
|
||||
audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
|
||||
"resp=%u fan_type=%u fan_info=0 subj_trust=2 obj_trust=2",
|
||||
response, FAN_RESPONSE_INFO_NONE);
|
||||
break;
|
||||
case FAN_RESPONSE_INFO_AUDIT_RULE:
|
||||
audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
|
||||
"resp=%u fan_type=%u fan_info=%X subj_trust=%u obj_trust=%u",
|
||||
response, friar->hdr.type, friar->rule_number,
|
||||
friar->subj_trust, friar->obj_trust);
|
||||
}
|
||||
}
|
||||
|
||||
void __audit_tk_injoffset(struct timespec64 offset)
|
||||
|
Loading…
Reference in New Issue
Block a user