@@ -2331,6 +2331,9 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
error = nd_jump_root(nd);
if (unlikely(error))
return ERR_PTR(error);
+ error = security_resolve_path_at(&nd->path, NULL, flags);
+ if (error)
+ return ERR_PTR(error);
return s;
}
@@ -2350,6 +2353,9 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
get_fs_pwd(current->fs, &nd->path);
nd->inode = nd->path.dentry->d_inode;
}
+ error = security_resolve_path_at(&nd->path, NULL, flags);
+ if (error)
+ return ERR_PTR(error);
} else {
/* Caller must check execute permissions on the starting path component */
struct fd f = fdget_raw(nd->dfd);
@@ -2373,7 +2379,10 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
path_get(&nd->path);
nd->inode = nd->path.dentry->d_inode;
}
+ error = security_resolve_path_at(&nd->path, f.file, flags);
fdput(f);
+ if (error)
+ return ERR_PTR(error);
}
/* For scoped-lookups we need to set the root to the dirfd as well. */
@@ -178,6 +178,8 @@ LSM_HOOK(int, 0, file_send_sigiotask, struct task_struct *tsk,
struct fown_struct *fown, int sig)
LSM_HOOK(int, 0, file_receive, struct file *file)
LSM_HOOK(int, 0, file_open, struct file *file)
+LSM_HOOK(int, 0, resolve_path_at, const struct path *path_at,
+ struct file *file_at, int lookup_flags)
LSM_HOOK(int, 0, task_alloc, struct task_struct *task,
unsigned long clone_flags)
LSM_HOOK(void, LSM_RET_VOID, task_free, struct task_struct *task)
@@ -600,6 +600,14 @@
* Save open-time permission checking state for later use upon
* file_permission, and recheck access if anything has changed
* since inode_permission.
+ * @resolve_path_at:
+ * Check path resolution from a file descriptor, or the current working
+ * directory, or the current root directory.
+ * Can be called in RCU read-side critical section.
+ * @path_at points to the base path.
+ * @file_at can point to the file descriptor used to resolve the path, or
+ * be NULL for AT_FDCWD.
+ * @lookup_flags contains the lookup options (e.g. LOOKUP_IS_SCOPED).
*
* Security hooks for task operations.
*
@@ -391,6 +391,8 @@ int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
int security_file_open(struct file *file);
+int security_resolve_path_at(const struct path *path_at, struct file *file_at,
+ int lookup_flags);
int security_task_alloc(struct task_struct *task, unsigned long clone_flags);
void security_task_free(struct task_struct *task);
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
@@ -1011,6 +1013,13 @@ static inline int security_file_open(struct file *file)
return 0;
}
+static inline int security_resolve_path_at(const struct path *path_at,
+ struct file *file_at,
+ int lookup_flags)
+{
+ return 0;
+}
+
static inline int security_task_alloc(struct task_struct *task,
unsigned long clone_flags)
{
@@ -1637,6 +1637,12 @@ int security_file_open(struct file *file)
return fsnotify_perm(file, MAY_OPEN);
}
+int security_resolve_path_at(const struct path *path_at, struct file *file_at,
+ int lookup_flags)
+{
+ return call_int_hook(resolve_path_at, 0, path_at, file_at, lookup_flags);
+}
+
int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
{
int rc = lsm_task_alloc(task);