2011-03-21 09:58:24 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2010 Isilon Systems, Inc.
|
|
|
|
* Copyright (c) 2010 iX Systems, Inc.
|
|
|
|
* Copyright (c) 2010 Panasas, Inc.
|
2017-05-31 12:02:59 +00:00
|
|
|
* Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
|
2011-03-21 09:58:24 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice unmodified, this list of conditions, and the following
|
|
|
|
* disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2015-10-20 19:08:26 +00:00
|
|
|
*
|
|
|
|
* $FreeBSD$
|
2011-03-21 09:58:24 +00:00
|
|
|
*/
|
|
|
|
#ifndef _LINUX_FILE_H_
|
|
|
|
#define _LINUX_FILE_H_
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/filedesc.h>
|
|
|
|
#include <sys/refcount.h>
|
2015-06-16 09:52:36 +00:00
|
|
|
#include <sys/capsicum.h>
|
2011-03-21 09:58:24 +00:00
|
|
|
#include <sys/proc.h>
|
|
|
|
|
|
|
|
#include <linux/fs.h>
|
2017-02-21 12:43:02 +00:00
|
|
|
#include <linux/slab.h>
|
2011-03-21 09:58:24 +00:00
|
|
|
|
|
|
|
struct linux_file;
|
|
|
|
|
|
|
|
#undef file
|
|
|
|
|
|
|
|
extern struct fileops linuxfileops;
|
|
|
|
|
|
|
|
static inline struct linux_file *
|
|
|
|
linux_fget(unsigned int fd)
|
|
|
|
{
|
|
|
|
struct file *file;
|
|
|
|
|
2017-09-09 06:04:05 +00:00
|
|
|
/* lookup file pointer by file descriptor index */
|
2015-06-16 09:52:36 +00:00
|
|
|
if (fget_unlocked(curthread->td_proc->p_fd, fd,
|
2020-02-03 22:27:55 +00:00
|
|
|
&cap_no_rights, &file) != 0)
|
2017-09-09 06:04:05 +00:00
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
/* check if file handle really belongs to us */
|
|
|
|
if (file->f_data == NULL ||
|
|
|
|
file->f_ops != &linuxfileops) {
|
|
|
|
fdrop(file, curthread);
|
Merge Capsicum overhaul:
- Capability is no longer separate descriptor type. Now every descriptor
has set of its own capability rights.
- The cap_new(2) system call is left, but it is no longer documented and
should not be used in new code.
- The new syscall cap_rights_limit(2) should be used instead of
cap_new(2), which limits capability rights of the given descriptor
without creating a new one.
- The cap_getrights(2) syscall is renamed to cap_rights_get(2).
- If CAP_IOCTL capability right is present we can further reduce allowed
ioctls list with the new cap_ioctls_limit(2) syscall. List of allowed
ioctls can be retrived with cap_ioctls_get(2) syscall.
- If CAP_FCNTL capability right is present we can further reduce fcntls
that can be used with the new cap_fcntls_limit(2) syscall and retrive
them with cap_fcntls_get(2).
- To support ioctl and fcntl white-listing the filedesc structure was
heavly modified.
- The audit subsystem, kdump and procstat tools were updated to
recognize new syscalls.
- Capability rights were revised and eventhough I tried hard to provide
backward API and ABI compatibility there are some incompatible changes
that are described in detail below:
CAP_CREATE old behaviour:
- Allow for openat(2)+O_CREAT.
- Allow for linkat(2).
- Allow for symlinkat(2).
CAP_CREATE new behaviour:
- Allow for openat(2)+O_CREAT.
Added CAP_LINKAT:
- Allow for linkat(2). ABI: Reuses CAP_RMDIR bit.
- Allow to be target for renameat(2).
Added CAP_SYMLINKAT:
- Allow for symlinkat(2).
Removed CAP_DELETE. Old behaviour:
- Allow for unlinkat(2) when removing non-directory object.
- Allow to be source for renameat(2).
Removed CAP_RMDIR. Old behaviour:
- Allow for unlinkat(2) when removing directory.
Added CAP_RENAMEAT:
- Required for source directory for the renameat(2) syscall.
Added CAP_UNLINKAT (effectively it replaces CAP_DELETE and CAP_RMDIR):
- Allow for unlinkat(2) on any object.
- Required if target of renameat(2) exists and will be removed by this
call.
Removed CAP_MAPEXEC.
CAP_MMAP old behaviour:
- Allow for mmap(2) with any combination of PROT_NONE, PROT_READ and
PROT_WRITE.
CAP_MMAP new behaviour:
- Allow for mmap(2)+PROT_NONE.
Added CAP_MMAP_R:
- Allow for mmap(PROT_READ).
Added CAP_MMAP_W:
- Allow for mmap(PROT_WRITE).
Added CAP_MMAP_X:
- Allow for mmap(PROT_EXEC).
Added CAP_MMAP_RW:
- Allow for mmap(PROT_READ | PROT_WRITE).
Added CAP_MMAP_RX:
- Allow for mmap(PROT_READ | PROT_EXEC).
Added CAP_MMAP_WX:
- Allow for mmap(PROT_WRITE | PROT_EXEC).
Added CAP_MMAP_RWX:
- Allow for mmap(PROT_READ | PROT_WRITE | PROT_EXEC).
Renamed CAP_MKDIR to CAP_MKDIRAT.
Renamed CAP_MKFIFO to CAP_MKFIFOAT.
Renamed CAP_MKNODE to CAP_MKNODEAT.
CAP_READ old behaviour:
- Allow pread(2).
- Disallow read(2), readv(2) (if there is no CAP_SEEK).
CAP_READ new behaviour:
- Allow read(2), readv(2).
- Disallow pread(2) (CAP_SEEK was also required).
CAP_WRITE old behaviour:
- Allow pwrite(2).
- Disallow write(2), writev(2) (if there is no CAP_SEEK).
CAP_WRITE new behaviour:
- Allow write(2), writev(2).
- Disallow pwrite(2) (CAP_SEEK was also required).
Added convinient defines:
#define CAP_PREAD (CAP_SEEK | CAP_READ)
#define CAP_PWRITE (CAP_SEEK | CAP_WRITE)
#define CAP_MMAP_R (CAP_MMAP | CAP_SEEK | CAP_READ)
#define CAP_MMAP_W (CAP_MMAP | CAP_SEEK | CAP_WRITE)
#define CAP_MMAP_X (CAP_MMAP | CAP_SEEK | 0x0000000000000008ULL)
#define CAP_MMAP_RW (CAP_MMAP_R | CAP_MMAP_W)
#define CAP_MMAP_RX (CAP_MMAP_R | CAP_MMAP_X)
#define CAP_MMAP_WX (CAP_MMAP_W | CAP_MMAP_X)
#define CAP_MMAP_RWX (CAP_MMAP_R | CAP_MMAP_W | CAP_MMAP_X)
#define CAP_RECV CAP_READ
#define CAP_SEND CAP_WRITE
#define CAP_SOCK_CLIENT \
(CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \
CAP_PEELOFF | CAP_RECV | CAP_SEND | CAP_SETSOCKOPT | CAP_SHUTDOWN)
#define CAP_SOCK_SERVER \
(CAP_ACCEPT | CAP_BIND | CAP_GETPEERNAME | CAP_GETSOCKNAME | \
CAP_GETSOCKOPT | CAP_LISTEN | CAP_PEELOFF | CAP_RECV | CAP_SEND | \
CAP_SETSOCKOPT | CAP_SHUTDOWN)
Added defines for backward API compatibility:
#define CAP_MAPEXEC CAP_MMAP_X
#define CAP_DELETE CAP_UNLINKAT
#define CAP_MKDIR CAP_MKDIRAT
#define CAP_RMDIR CAP_UNLINKAT
#define CAP_MKFIFO CAP_MKFIFOAT
#define CAP_MKNOD CAP_MKNODAT
#define CAP_SOCK_ALL (CAP_SOCK_CLIENT | CAP_SOCK_SERVER)
Sponsored by: The FreeBSD Foundation
Reviewed by: Christoph Mallon <christoph.mallon@gmx.de>
Many aspects discussed with: rwatson, benl, jonathan
ABI compatibility discussed with: kib
2013-03-02 00:53:12 +00:00
|
|
|
return (NULL);
|
2013-09-05 11:58:12 +00:00
|
|
|
}
|
2017-09-09 06:04:05 +00:00
|
|
|
return ((struct linux_file *)file->f_data);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
2017-05-31 12:02:59 +00:00
|
|
|
extern void linux_file_free(struct linux_file *filp);
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
static inline void
|
|
|
|
fput(struct linux_file *filp)
|
|
|
|
{
|
2017-05-31 12:02:59 +00:00
|
|
|
if (refcount_release(filp->_file == NULL ?
|
|
|
|
&filp->f_count : &filp->_file->f_count)) {
|
|
|
|
linux_file_free(filp);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-31 12:02:59 +00:00
|
|
|
static inline unsigned int
|
|
|
|
file_count(struct linux_file *filp)
|
|
|
|
{
|
|
|
|
return (filp->_file == NULL ?
|
|
|
|
filp->f_count : filp->_file->f_count);
|
|
|
|
}
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
static inline void
|
|
|
|
put_unused_fd(unsigned int fd)
|
|
|
|
{
|
|
|
|
struct file *file;
|
|
|
|
|
2015-06-16 09:52:36 +00:00
|
|
|
if (fget_unlocked(curthread->td_proc->p_fd, fd,
|
2020-02-03 22:27:55 +00:00
|
|
|
&cap_no_rights, &file) != 0) {
|
2011-03-21 09:58:24 +00:00
|
|
|
return;
|
2013-09-05 11:58:12 +00:00
|
|
|
}
|
2015-01-06 10:02:14 +00:00
|
|
|
/*
|
|
|
|
* NOTE: We should only get here when the "fd" has not been
|
|
|
|
* installed, so no need to free the associated Linux file
|
|
|
|
* structure.
|
|
|
|
*/
|
2015-04-11 15:40:28 +00:00
|
|
|
fdclose(curthread, file, fd);
|
2015-01-06 10:02:14 +00:00
|
|
|
|
|
|
|
/* drop extra reference */
|
|
|
|
fdrop(file, curthread);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
fd_install(unsigned int fd, struct linux_file *filp)
|
|
|
|
{
|
|
|
|
struct file *file;
|
|
|
|
|
2015-06-16 09:52:36 +00:00
|
|
|
if (fget_unlocked(curthread->td_proc->p_fd, fd,
|
2020-02-03 22:27:55 +00:00
|
|
|
&cap_no_rights, &file) != 0) {
|
2015-12-31 14:47:45 +00:00
|
|
|
filp->_file = NULL;
|
|
|
|
} else {
|
|
|
|
filp->_file = file;
|
|
|
|
finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
|
2017-05-31 12:02:59 +00:00
|
|
|
|
|
|
|
/* transfer reference count from "filp" to "file" */
|
|
|
|
while (refcount_release(&filp->f_count) == 0)
|
|
|
|
refcount_acquire(&file->f_count);
|
2013-09-05 11:58:12 +00:00
|
|
|
}
|
2015-01-06 10:02:14 +00:00
|
|
|
|
|
|
|
/* drop the extra reference */
|
|
|
|
fput(filp);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
get_unused_fd(void)
|
|
|
|
{
|
|
|
|
struct file *file;
|
|
|
|
int error;
|
|
|
|
int fd;
|
|
|
|
|
2011-04-26 07:30:52 +00:00
|
|
|
error = falloc(curthread, &file, &fd, 0);
|
2011-03-21 09:58:24 +00:00
|
|
|
if (error)
|
|
|
|
return -error;
|
2015-01-06 10:02:14 +00:00
|
|
|
/* drop the extra reference */
|
|
|
|
fdrop(file, curthread);
|
2011-03-21 09:58:24 +00:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2015-11-30 09:24:12 +00:00
|
|
|
static inline int
|
|
|
|
get_unused_fd_flags(int flags)
|
|
|
|
{
|
|
|
|
struct file *file;
|
|
|
|
int error;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
error = falloc(curthread, &file, &fd, flags);
|
|
|
|
if (error)
|
|
|
|
return -error;
|
|
|
|
/* drop the extra reference */
|
|
|
|
fdrop(file, curthread);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2017-06-01 09:34:51 +00:00
|
|
|
extern struct linux_file *linux_file_alloc(void);
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
static inline struct linux_file *
|
2014-08-27 13:21:53 +00:00
|
|
|
alloc_file(int mode, const struct file_operations *fops)
|
2011-03-21 09:58:24 +00:00
|
|
|
{
|
|
|
|
struct linux_file *filp;
|
|
|
|
|
2017-06-01 09:34:51 +00:00
|
|
|
filp = linux_file_alloc();
|
2011-03-21 09:58:24 +00:00
|
|
|
filp->f_op = fops;
|
|
|
|
filp->f_mode = mode;
|
|
|
|
|
2017-06-01 09:34:51 +00:00
|
|
|
return (filp);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 13:21:53 +00:00
|
|
|
struct fd {
|
|
|
|
struct linux_file *linux_file;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void fdput(struct fd fd)
|
|
|
|
{
|
|
|
|
fput(fd.linux_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct fd fdget(unsigned int fd)
|
|
|
|
{
|
|
|
|
struct linux_file *f = linux_fget(fd);
|
|
|
|
return (struct fd){f};
|
|
|
|
}
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2017-05-31 12:02:59 +00:00
|
|
|
#define file linux_file
|
|
|
|
#define fget(...) linux_fget(__VA_ARGS__)
|
2011-03-21 09:58:24 +00:00
|
|
|
|
|
|
|
#endif /* _LINUX_FILE_H_ */
|