Skip to content

Commit 0f98621

Browse files
borkmanndavem330
authored andcommitted
bpf, inode: add support for symlinks and fix mtime/ctime
While commit bb35a6e ("bpf, inode: allow for rename and link ops") added support for hard links that can be used for prog and map nodes, this work adds simple symlink support, which can be used f.e. for directories also when unpriviledged and works with cmdline tooling that understands S_IFLNK anyway. Since the switch in e27f4a9 ("bpf: Use mount_nodev not mount_ns to mount the bpf filesystem"), there can be various mount instances with mount_nodev() and thus hierarchy can be flattened to facilitate object sharing. Thus, we can keep bpf tooling also working by repointing paths. Most of the functionality can be used from vfs library operations. The symlink is stored in the inode itself, that is in i_link, which is sufficient in our case as opposed to storing it in the page cache. While at it, I noticed that bpf_mkdir() and bpf_mkobj() don't update the directories mtime and ctime, so add a common helper for it called bpf_dentry_finalize() that takes care of it for all cases now. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 8778b27 commit 0f98621

File tree

1 file changed

+39
-6
lines changed

1 file changed

+39
-6
lines changed

kernel/bpf/inode.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ static struct inode *bpf_get_inode(struct super_block *sb,
8787
switch (mode & S_IFMT) {
8888
case S_IFDIR:
8989
case S_IFREG:
90+
case S_IFLNK:
9091
break;
9192
default:
9293
return ERR_PTR(-EINVAL);
@@ -119,6 +120,16 @@ static int bpf_inode_type(const struct inode *inode, enum bpf_type *type)
119120
return 0;
120121
}
121122

123+
static void bpf_dentry_finalize(struct dentry *dentry, struct inode *inode,
124+
struct inode *dir)
125+
{
126+
d_instantiate(dentry, inode);
127+
dget(dentry);
128+
129+
dir->i_mtime = current_time(dir);
130+
dir->i_ctime = dir->i_mtime;
131+
}
132+
122133
static int bpf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
123134
{
124135
struct inode *inode;
@@ -133,9 +144,7 @@ static int bpf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
133144
inc_nlink(inode);
134145
inc_nlink(dir);
135146

136-
d_instantiate(dentry, inode);
137-
dget(dentry);
138-
147+
bpf_dentry_finalize(dentry, inode, dir);
139148
return 0;
140149
}
141150

@@ -151,9 +160,7 @@ static int bpf_mkobj_ops(struct inode *dir, struct dentry *dentry,
151160
inode->i_op = iops;
152161
inode->i_private = dentry->d_fsdata;
153162

154-
d_instantiate(dentry, inode);
155-
dget(dentry);
156-
163+
bpf_dentry_finalize(dentry, inode, dir);
157164
return 0;
158165
}
159166

@@ -181,13 +188,37 @@ bpf_lookup(struct inode *dir, struct dentry *dentry, unsigned flags)
181188
{
182189
if (strchr(dentry->d_name.name, '.'))
183190
return ERR_PTR(-EPERM);
191+
184192
return simple_lookup(dir, dentry, flags);
185193
}
186194

195+
static int bpf_symlink(struct inode *dir, struct dentry *dentry,
196+
const char *target)
197+
{
198+
char *link = kstrdup(target, GFP_USER | __GFP_NOWARN);
199+
struct inode *inode;
200+
201+
if (!link)
202+
return -ENOMEM;
203+
204+
inode = bpf_get_inode(dir->i_sb, dir, S_IRWXUGO | S_IFLNK);
205+
if (IS_ERR(inode)) {
206+
kfree(link);
207+
return PTR_ERR(inode);
208+
}
209+
210+
inode->i_op = &simple_symlink_inode_operations;
211+
inode->i_link = link;
212+
213+
bpf_dentry_finalize(dentry, inode, dir);
214+
return 0;
215+
}
216+
187217
static const struct inode_operations bpf_dir_iops = {
188218
.lookup = bpf_lookup,
189219
.mknod = bpf_mkobj,
190220
.mkdir = bpf_mkdir,
221+
.symlink = bpf_symlink,
191222
.rmdir = simple_rmdir,
192223
.rename = simple_rename,
193224
.link = simple_link,
@@ -324,6 +355,8 @@ static void bpf_evict_inode(struct inode *inode)
324355
truncate_inode_pages_final(&inode->i_data);
325356
clear_inode(inode);
326357

358+
if (S_ISLNK(inode->i_mode))
359+
kfree(inode->i_link);
327360
if (!bpf_inode_type(inode, &type))
328361
bpf_any_put(inode->i_private, type);
329362
}

0 commit comments

Comments
 (0)