mirror of
https://github.com/libfuse/libfuse.git
synced 2026-07-07 14:47:41 +08:00
nullfs: support fuse systemd service mode
This is the only example fuse server that exports a regular file instead of a directory tree. Port it to be usable as a systemd fuse service so that we can test that capability. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
This commit is contained in:
committed by
Bernd Schubert
parent
e25d7b9e25
commit
e881b37462
@@ -10,6 +10,12 @@ if not platform.endswith('bsd') and platform != 'dragonfly'
|
||||
# support mounting files, This is enforced in vfs_domount_first()
|
||||
# with the v_type != VDIR check.
|
||||
examples += [ 'null' ]
|
||||
|
||||
if platform.endswith('linux')
|
||||
configure_file(input: 'null.socket.in',
|
||||
output: 'null.socket',
|
||||
configuration: private_cfg)
|
||||
endif
|
||||
endif
|
||||
|
||||
single_file_examples = [ ]
|
||||
|
||||
+48
-3
@@ -17,15 +17,24 @@
|
||||
*
|
||||
* gcc -Wall null.c `pkg-config fuse3 --cflags --libs` -o null
|
||||
*
|
||||
* Change the ExecStart line in nullfile@.service:
|
||||
*
|
||||
* ExecStart=/path/to/null
|
||||
*
|
||||
* to point to the actual path of the null binary.
|
||||
*
|
||||
* Finally, install the null@.service and null.socket files to the
|
||||
* systemd service directory, usually /run/systemd/system.
|
||||
*
|
||||
* ## Source code ##
|
||||
* \include passthrough_fh.c
|
||||
*/
|
||||
|
||||
|
||||
#define FUSE_USE_VERSION 31
|
||||
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 19)
|
||||
|
||||
#include <fuse.h>
|
||||
#include <fuse_lowlevel.h>
|
||||
#include <fuse_service.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -33,6 +42,8 @@
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
static mode_t mode = 0644;
|
||||
|
||||
static int null_getattr(const char *path, struct stat *stbuf,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
@@ -41,7 +52,7 @@ static int null_getattr(const char *path, struct stat *stbuf,
|
||||
if(strcmp(path, "/") != 0)
|
||||
return -ENOENT;
|
||||
|
||||
stbuf->st_mode = S_IFREG | 0644;
|
||||
stbuf->st_mode = S_IFREG | mode;
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_uid = getuid();
|
||||
stbuf->st_gid = getgid();
|
||||
@@ -112,11 +123,45 @@ static const struct fuse_operations null_oper = {
|
||||
.write = null_write,
|
||||
};
|
||||
|
||||
static int null_service(struct fuse_service *service, struct fuse_args *args)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (fuse_service_append_args(service, args))
|
||||
goto err_service;
|
||||
|
||||
if (fuse_service_finish_file_requests(service))
|
||||
goto err_service;
|
||||
|
||||
fuse_service_expect_mount_format(service, S_IFREG);
|
||||
|
||||
/*
|
||||
* In non-service mode, we set up the file to be owned and writable
|
||||
* by the same user that starts the fuse server. When running in a
|
||||
* container as a dynamic user, we just grant world write access.
|
||||
*/
|
||||
mode = 0666;
|
||||
ret = fuse_service_main(service, args, &null_oper, NULL);
|
||||
|
||||
err_service:
|
||||
fuse_service_send_goodbye(service, ret);
|
||||
fuse_service_destroy(&service);
|
||||
fuse_opt_free_args(args);
|
||||
return fuse_service_exit(ret);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
struct fuse_cmdline_opts opts;
|
||||
struct stat stbuf;
|
||||
struct fuse_service *service = NULL;
|
||||
|
||||
if (fuse_service_accept(&service) != 0)
|
||||
return 1;
|
||||
|
||||
if (fuse_service_accepted(service))
|
||||
return null_service(service, &args);
|
||||
|
||||
if (fuse_parse_cmdline(&args, &opts) != 0)
|
||||
return 1;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (C) 2026 Oracle. All Rights Reserved.
|
||||
# Author: Darrick J. Wong <djwong@kernel.org>
|
||||
[Unit]
|
||||
Description=Socket for null Service
|
||||
|
||||
[Socket]
|
||||
ListenSequentialPacket=@FUSE_SERVICE_SOCKET_DIR_RAW@/null
|
||||
Accept=yes
|
||||
SocketMode=@FUSE_SERVICE_SOCKET_PERMS@
|
||||
RemoveOnStop=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
@@ -0,0 +1,102 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (C) 2026 Oracle. All Rights Reserved.
|
||||
# Author: Darrick J. Wong <djwong@kernel.org>
|
||||
[Unit]
|
||||
Description=null Sample Fuse Service
|
||||
|
||||
# Don't leave failed units behind, systemd does not clean them up!
|
||||
CollectMode=inactive-or-failed
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
ExecStart=/path/to/null
|
||||
|
||||
# Try to capture core dumps
|
||||
LimitCORE=infinity
|
||||
|
||||
SyslogIdentifier=%N
|
||||
|
||||
# No realtime CPU scheduling
|
||||
RestrictRealtime=true
|
||||
|
||||
# Don't let us see anything in the regular system, and don't run as root
|
||||
DynamicUser=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
PrivateDevices=true
|
||||
PrivateUsers=true
|
||||
|
||||
# No network access
|
||||
PrivateNetwork=true
|
||||
ProtectHostname=true
|
||||
RestrictAddressFamilies=none
|
||||
IPAddressDeny=any
|
||||
|
||||
# Don't let the program mess with the kernel configuration at all
|
||||
ProtectKernelLogs=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectControlGroups=true
|
||||
ProtectProc=invisible
|
||||
RestrictNamespaces=true
|
||||
RestrictFileSystems=
|
||||
|
||||
# Hide everything in /proc, even /proc/mounts
|
||||
ProcSubset=pid
|
||||
|
||||
# Only allow the default personality Linux
|
||||
LockPersonality=true
|
||||
|
||||
# No writable memory pages
|
||||
MemoryDenyWriteExecute=true
|
||||
|
||||
# Don't let our mounts leak out to the host
|
||||
PrivateMounts=true
|
||||
|
||||
# Restrict system calls to the native arch and only enough to get things going
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallFilter=~@privileged
|
||||
SystemCallFilter=~@resources
|
||||
|
||||
SystemCallFilter=~@clock
|
||||
SystemCallFilter=~@cpu-emulation
|
||||
SystemCallFilter=~@debug
|
||||
SystemCallFilter=~@module
|
||||
SystemCallFilter=~@reboot
|
||||
SystemCallFilter=~@swap
|
||||
|
||||
SystemCallFilter=~@mount
|
||||
|
||||
# libfuse io_uring wants to pin cores and memory
|
||||
SystemCallFilter=mbind
|
||||
SystemCallFilter=sched_setaffinity
|
||||
|
||||
# Leave a breadcrumb if we get whacked by the system call filter
|
||||
SystemCallErrorNumber=EL3RST
|
||||
|
||||
# Log to the kernel dmesg, just like an in-kernel filesystem driver
|
||||
StandardOutput=append:/dev/ttyprintk
|
||||
StandardError=append:/dev/ttyprintk
|
||||
|
||||
# Run with no capabilities at all
|
||||
CapabilityBoundingSet=
|
||||
AmbientCapabilities=
|
||||
NoNewPrivileges=true
|
||||
|
||||
# We don't create files
|
||||
UMask=7777
|
||||
|
||||
# No access to hardware /dev files at all
|
||||
ProtectClock=true
|
||||
DevicePolicy=closed
|
||||
|
||||
# Don't mess with set[ug]id anything.
|
||||
RestrictSUIDSGID=true
|
||||
|
||||
# Don't let OOM kills of processes in this containment group kill the whole
|
||||
# service, because we don't want filesystem drivers to go down.
|
||||
OOMPolicy=continue
|
||||
OOMScoreAdjust=-1000
|
||||
Reference in New Issue
Block a user