11/* SPDX-License-Identifier: LGPL-3.0-or-later */
22/* Copyright (C) 2022 Intel Corporation
3+ * Copyright (C) 2024 Fortanix, Inc.
34 * Paweł Marczewski <[email protected] > 5+ * Bobby Marinov <[email protected] > 46 */
57
68/*
4042#include "stat.h"
4143#include "toml_utils.h"
4244
45+ #define USEC_IN_SEC 1000000
46+
4347/*
4448 * Always add read and write permissions to files created on host. PAL requires opening the file
4549 * even for operations such as `unlink` or `chmod`, and the underlying `libos_fs_encrypted` module
@@ -258,7 +262,7 @@ static int chroot_encrypted_mkdir(struct libos_dentry* dent, mode_t perm) {
258262 /* This opens a "dir:..." URI */
259263 PAL_HANDLE palhdl ;
260264 ret = PalStreamOpen (uri , PAL_ACCESS_RDONLY , HOST_PERM (perm ), PAL_CREATE_ALWAYS ,
261- PAL_OPTION_PASSTHROUGH , & palhdl );
265+ PAL_OPTION_PASSTHROUGH , false, & palhdl );
262266 if (ret < 0 ) {
263267 ret = pal_to_unix_errno (ret );
264268 goto out ;
@@ -290,7 +294,7 @@ static int chroot_encrypted_unlink(struct libos_dentry* dent) {
290294
291295 PAL_HANDLE palhdl ;
292296 ret = PalStreamOpen (uri , PAL_ACCESS_RDONLY , /*share_flags=*/ 0 , PAL_CREATE_NEVER ,
293- PAL_OPTION_PASSTHROUGH , & palhdl );
297+ PAL_OPTION_PASSTHROUGH , false, & palhdl );
294298 if (ret < 0 ) {
295299 ret = pal_to_unix_errno (ret );
296300 goto out ;
@@ -308,6 +312,147 @@ static int chroot_encrypted_unlink(struct libos_dentry* dent) {
308312 return ret ;
309313}
310314
315+ static int chroot_encrypted_create_symlink_file (struct libos_dentry * link_dent ,
316+ const char * targetpath ) {
317+ assert (locked (& g_dcache_lock ));
318+ assert (link_dent -> mount != NULL );
319+
320+ if (link_dent -> inode != NULL )
321+ return - EEXIST ;
322+
323+ uint64_t time_us ;
324+ if (PalSystemTimeQuery (& time_us ) < 0 )
325+ return - EPERM ;
326+
327+ bool do_unlock = false;
328+ char * uri ;
329+ int ret = chroot_dentry_uri (link_dent , S_IFREG , & uri );
330+ if (ret < 0 )
331+ return ret ;
332+
333+ mode_t perm = 0755 ;
334+ if ((link_dent -> parent != NULL ) && (link_dent -> parent -> inode != NULL ))
335+ perm = link_dent -> parent -> inode -> perm ;
336+
337+ struct libos_encrypted_file * enc = NULL ;
338+ struct libos_inode * inode = get_new_inode (link_dent -> mount , S_IFLNK , HOST_PERM (perm ));
339+ if (inode == NULL ) {
340+ ret = - ENOMEM ;
341+ goto out ;
342+ }
343+
344+ lock (& inode -> lock );
345+ do_unlock = true;
346+
347+ struct libos_encrypted_files_key * key = link_dent -> mount -> data ;
348+ ret = encrypted_file_create (uri , HOST_PERM (perm ), key , & enc );
349+ if (ret < 0 )
350+ goto out ;
351+ inode -> type = S_IFLNK ;
352+
353+ inode -> data = enc ;
354+ link_dent -> inode = inode ;
355+ get_inode (inode );
356+
357+ file_off_t pos = 0 ;
358+ size_t out_count = 0 ;
359+ size_t target_len = strlen (targetpath );
360+ ret = encrypted_file_write (enc , targetpath , target_len , pos , & out_count );
361+ if (ret < 0 )
362+ goto out ;
363+ assert (out_count <= target_len );
364+
365+ inode -> size = target_len ;
366+ inode -> mtime = time_us / USEC_IN_SEC ;
367+
368+ out :
369+ if (enc != NULL )
370+ encrypted_file_put (enc );
371+ if (inode != NULL ) {
372+ if (do_unlock )
373+ unlock (& inode -> lock );
374+ put_inode (inode );
375+ }
376+ free (uri );
377+ return ret ;
378+ }
379+
380+ static int chroot_encrypted_set_link (struct libos_dentry * link_dent , const char * targetpath ,
381+ bool is_soft_link ) {
382+ assert (locked (& g_dcache_lock ));
383+
384+ int ret ;
385+ if (is_soft_link )
386+ ret = chroot_encrypted_create_symlink_file (link_dent , targetpath );
387+ else
388+ ret = - EPERM ;
389+ if (ret < 0 )
390+ goto out ;
391+ ret = 0 ;
392+
393+ out :
394+ return ret ;
395+ }
396+
397+ static int chroot_encrypted_follow_symlink (struct libos_dentry * link_dent , char * * out_target ) {
398+ assert (locked (& g_dcache_lock ));
399+
400+ if (link_dent -> inode == NULL )
401+ return - ENOENT ;
402+ struct libos_inode * inode = link_dent -> inode ;
403+ bool put_required = false;
404+ char * targetpath = NULL ;
405+ int ret = 0 ;
406+
407+ lock (& inode -> lock );
408+
409+ /* open file, if not opened yet */
410+ struct libos_encrypted_file * enc = inode -> data ;
411+ ret = encrypted_file_get (enc );
412+ if (ret < 0 )
413+ goto out ;
414+ put_required = true;
415+
416+ file_off_t file_sz = 0 ;
417+ ret = encrypted_file_get_size (enc , & file_sz );
418+ if (ret < 0 )
419+ goto out ;
420+ if (file_sz > PATH_MAX ) {
421+ ret = - EPERM ;
422+ goto out ;
423+ }
424+
425+ targetpath = malloc (file_sz + 1 );
426+ if (targetpath == NULL ) {
427+ ret = - ENOMEM ;
428+ goto out ;
429+ }
430+
431+ size_t out_count = 0 ;
432+ ret = encrypted_file_read (enc , targetpath , file_sz , 0 , & out_count );
433+ if (ret < 0 )
434+ goto out ;
435+ static_assert (sizeof (out_count ) >= sizeof (file_sz ));
436+ assert (out_count <= (size_t )file_sz );
437+ * (targetpath + out_count ) = '\x00' ;
438+
439+ * out_target = targetpath ;
440+ targetpath = NULL ; /* to skip freeing it below */
441+
442+ out :
443+ if (put_required )
444+ encrypted_file_put (enc );
445+ unlock (& inode -> lock );
446+ free (targetpath );
447+ return ret ;
448+ }
449+
450+ static int chroot_encrypted_follow_link (struct libos_dentry * link_dent , char * * out_target ) {
451+ assert (locked (& g_dcache_lock ));
452+
453+ return chroot_encrypted_follow_symlink (link_dent , out_target );
454+ }
455+
311456static int chroot_encrypted_rename (struct libos_dentry * old , struct libos_dentry * new ) {
312457 assert (locked (& g_dcache_lock ));
313458 assert (old -> inode );
@@ -348,7 +493,7 @@ static int chroot_encrypted_chmod(struct libos_dentry* dent, mode_t perm) {
348493
349494 PAL_HANDLE palhdl ;
350495 ret = PalStreamOpen (uri , PAL_ACCESS_RDONLY , /*share_flags=*/ 0 , PAL_CREATE_NEVER ,
351- PAL_OPTION_PASSTHROUGH , & palhdl );
496+ PAL_OPTION_PASSTHROUGH , false, & palhdl );
352497 if (ret < 0 ) {
353498 ret = pal_to_unix_errno (ret );
354499 goto out ;
@@ -518,6 +663,8 @@ struct libos_d_ops chroot_encrypted_d_ops = {
518663 .stat = & generic_inode_stat ,
519664 .readdir = & chroot_readdir , /* same as in `chroot` filesystem */
520665 .unlink = & chroot_encrypted_unlink ,
666+ .follow_link = & chroot_encrypted_follow_link ,
667+ .set_link = & chroot_encrypted_set_link ,
521668 .rename = & chroot_encrypted_rename ,
522669 .chmod = & chroot_encrypted_chmod ,
523670 .idrop = & chroot_encrypted_idrop ,
0 commit comments