xiaoxiang781216 commented on code in PR #19900:
URL: https://github.com/apache/nuttx/pull/19900#discussion_r3811913678
##########
include/nuttx/fs/fs.h:
##########
@@ -635,6 +635,27 @@ extern "C"
void fs_initialize(void);
+/****************************************************************************
+ * Name: inode_addref
Review Comment:
do you need remove the prototype from the internal header file
##########
sched/group/group_create.c:
##########
@@ -98,6 +98,49 @@ static inline void group_inherit_identity(FAR struct
task_group_s *group)
# define group_inherit_identity(group)
#endif
+#ifdef CONFIG_FS_CHROOT
+/****************************************************************************
+ * Name: group_inherit_chroot
+ *
+ * Description:
+ * Inherit the chroot jail from the parent task group.
+ *
+ ****************************************************************************/
+
+static int group_inherit_chroot(FAR struct task_group_s *group)
+{
+ FAR struct tcb_s *rtcb = this_task();
+ FAR struct task_group_s *rgroup = rtcb->group;
+
+ DEBUGASSERT(group != NULL && rgroup != NULL);
+
+ if (rgroup->tg_root == NULL)
+ {
+ return OK;
+ }
+
+ group->tg_root = rgroup->tg_root;
+ inode_addref(group->tg_root);
+
+ if (rgroup->tg_rootrel != NULL)
+ {
+ size_t len = strlen(rgroup->tg_rootrel) + 1;
+
+ group->tg_rootrel = kmm_malloc(len);
Review Comment:
call strdup directly
##########
sched/group/group_create.c:
##########
@@ -98,6 +98,49 @@ static inline void group_inherit_identity(FAR struct
task_group_s *group)
# define group_inherit_identity(group)
#endif
+#ifdef CONFIG_FS_CHROOT
Review Comment:
where we define this config
##########
fs/vfs/fs_chroot.c:
##########
@@ -0,0 +1,263 @@
+/****************************************************************************
+ * fs/vfs/fs_chroot.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/sched.h>
+
+#include "inode/inode.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: chroot_strip_slash
+ ****************************************************************************/
+
+static void chroot_strip_slash(FAR char *path)
+{
+ size_t len;
+
+ if (path == NULL)
+ {
+ return;
+ }
+
+ len = strlen(path);
+ while (len > 1 && path[len - 1] == '/')
+ {
+ path[--len] = '\0';
+ }
+}
+
+/****************************************************************************
+ * Name: chroot_set_pwd
+ *
+ * Description:
+ * Rewrite PWD so relative lookups stay inside the jail. If the current
+ * directory is not under the new root, PWD becomes "/".
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_ENVIRON
+static void chroot_set_pwd(FAR struct inode *root, FAR const char *relpath)
+{
+ char rootpath[PATH_MAX];
+ FAR const char *pwd;
+ size_t rootlen;
+
+ rootpath[0] = '\0';
+ if (root != NULL)
+ {
+ if (inode_getpath(root, rootpath, sizeof(rootpath)) < 0)
+ {
+ setenv("PWD", "/", TRUE);
+ return;
+ }
+ }
+ else
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ if (relpath != NULL && relpath[0] != '\0')
+ {
+ chroot_strip_slash(rootpath);
Review Comment:
why strip slash and then append one
##########
fs/inode/fs_inodesearch.c:
##########
@@ -221,6 +341,11 @@ static int _inode_search(FAR struct inode_search_s *desc)
FAR struct inode *left = NULL;
FAR struct inode *above = NULL;
FAR const char *relpath = NULL;
+#ifdef CONFIG_FS_CHROOT
+ FAR struct inode *search_root = g_root_inode;
Review Comment:
it's more simple to:
1. prepend the root to the path
2. normalize the new path
3. ensure the result is under the root
4. continue the original flow
##########
fs/vfs/fs_chroot.c:
##########
@@ -0,0 +1,263 @@
+/****************************************************************************
+ * fs/vfs/fs_chroot.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/sched.h>
+
+#include "inode/inode.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: chroot_strip_slash
+ ****************************************************************************/
+
+static void chroot_strip_slash(FAR char *path)
+{
+ size_t len;
+
+ if (path == NULL)
+ {
+ return;
+ }
+
+ len = strlen(path);
+ while (len > 1 && path[len - 1] == '/')
+ {
+ path[--len] = '\0';
+ }
+}
+
+/****************************************************************************
+ * Name: chroot_set_pwd
+ *
+ * Description:
+ * Rewrite PWD so relative lookups stay inside the jail. If the current
+ * directory is not under the new root, PWD becomes "/".
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_ENVIRON
+static void chroot_set_pwd(FAR struct inode *root, FAR const char *relpath)
+{
+ char rootpath[PATH_MAX];
+ FAR const char *pwd;
+ size_t rootlen;
+
+ rootpath[0] = '\0';
+ if (root != NULL)
+ {
+ if (inode_getpath(root, rootpath, sizeof(rootpath)) < 0)
+ {
+ setenv("PWD", "/", TRUE);
+ return;
+ }
+ }
+ else
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ if (relpath != NULL && relpath[0] != '\0')
+ {
+ chroot_strip_slash(rootpath);
+ if (rootpath[0] != '\0' && strcmp(rootpath, "/") != 0)
+ {
+ strlcat(rootpath, "/", sizeof(rootpath));
+ }
+ else if (strcmp(rootpath, "/") != 0)
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ strlcat(rootpath, relpath, sizeof(rootpath));
+ }
+
+ chroot_strip_slash(rootpath);
+ if (rootpath[0] == '\0')
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ pwd = getenv("PWD");
+ if (pwd == NULL)
+ {
+ pwd = CONFIG_LIBC_HOMEDIR;
+ }
+
+ rootlen = strlen(rootpath);
+ if (strcmp(pwd, rootpath) == 0)
+ {
+ setenv("PWD", "/", TRUE);
+ }
+ else if (rootlen > 1 && strncmp(pwd, rootpath, rootlen) == 0 &&
+ pwd[rootlen] == '/')
+ {
+ setenv("PWD", pwd + rootlen, TRUE);
+ }
+ else
+ {
+ setenv("PWD", "/", TRUE);
+ }
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: chroot
+ *
+ * Description:
+ * Cause the named directory to become the root directory, that is, the
+ * starting point for path names beginning with '/'.
+ *
+ * Input Parameters:
+ * path - Directory to use as the new root
+ *
+ * Returned Value:
+ * 0(OK) on success; -1(ERROR) on failure with errno set appropriately.
+ *
+ ****************************************************************************/
+
+int chroot(FAR const char *path)
+{
+ struct inode_search_s desc;
+ FAR struct tcb_s *rtcb;
+ FAR struct task_group_s *group;
+ FAR struct inode *oldroot;
+ FAR char *oldrel;
+ FAR char *newrel = NULL;
+ struct stat buf;
+ int errcode;
+ int ret;
+
+ if (path == NULL || path[0] == '\0')
+ {
+ set_errno(ENOENT);
+ return ERROR;
+ }
+
+ rtcb = nxsched_self();
+ DEBUGASSERT(rtcb != NULL && rtcb->group != NULL);
+ group = rtcb->group;
+
+#ifdef CONFIG_SCHED_USER_IDENTITY
+ if (group->tg_euid != 0)
+ {
+ set_errno(EPERM);
+ return ERROR;
+ }
+#endif
+
+ ret = nx_stat(path, &buf, 1);
+ if (ret < 0)
+ {
+ set_errno(-ret);
+ return ERROR;
+ }
+
+ if (!S_ISDIR(buf.st_mode))
+ {
+ set_errno(ENOTDIR);
+ return ERROR;
+ }
+
+ SETUP_SEARCH(&desc, path, false);
+
+ ret = inode_find(&desc);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout_with_search;
+ }
+
+ /* chroot("/") from the global root is a no-op jail (tg_root NULL). */
+
+ if (desc.node == g_root_inode &&
+ (desc.relpath == NULL || desc.relpath[0] == '\0'))
+ {
+ inode_release(desc.node);
+ RELEASE_SEARCH(&desc);
+ return OK;
+ }
+ else if (desc.relpath != NULL && desc.relpath[0] != '\0')
+ {
+ size_t len = strlen(desc.relpath) + 1;
+
+ newrel = kmm_malloc(len);
Review Comment:
strdup
##########
sched/group/group_create.c:
##########
@@ -98,6 +98,49 @@ static inline void group_inherit_identity(FAR struct
task_group_s *group)
# define group_inherit_identity(group)
#endif
+#ifdef CONFIG_FS_CHROOT
+/****************************************************************************
+ * Name: group_inherit_chroot
+ *
+ * Description:
+ * Inherit the chroot jail from the parent task group.
+ *
+ ****************************************************************************/
+
+static int group_inherit_chroot(FAR struct task_group_s *group)
+{
+ FAR struct tcb_s *rtcb = this_task();
+ FAR struct task_group_s *rgroup = rtcb->group;
+
+ DEBUGASSERT(group != NULL && rgroup != NULL);
+
+ if (rgroup->tg_root == NULL)
+ {
+ return OK;
+ }
+
+ group->tg_root = rgroup->tg_root;
Review Comment:
move after line 139 and remove line 132-133
##########
sched/group/group_create.c:
##########
@@ -98,6 +98,49 @@ static inline void group_inherit_identity(FAR struct
task_group_s *group)
# define group_inherit_identity(group)
#endif
+#ifdef CONFIG_FS_CHROOT
+/****************************************************************************
+ * Name: group_inherit_chroot
+ *
+ * Description:
+ * Inherit the chroot jail from the parent task group.
+ *
+ ****************************************************************************/
+
+static int group_inherit_chroot(FAR struct task_group_s *group)
+{
+ FAR struct tcb_s *rtcb = this_task();
+ FAR struct task_group_s *rgroup = rtcb->group;
+
+ DEBUGASSERT(group != NULL && rgroup != NULL);
+
+ if (rgroup->tg_root == NULL)
+ {
+ return OK;
+ }
+
+ group->tg_root = rgroup->tg_root;
Review Comment:
move after line 139 and remove line 132
##########
sched/group/group_create.c:
##########
@@ -190,6 +233,19 @@ int group_allocate(FAR struct tcb_s *tcb, uint8_t ttype)
group_inherit_identity(group);
+#ifdef CONFIG_FS_CHROOT
Review Comment:
add an empty macro like group_inherit_identity and remove this check
##########
sched/group/group_create.c:
##########
@@ -190,6 +233,19 @@ int group_allocate(FAR struct tcb_s *tcb, uint8_t ttype)
group_inherit_identity(group);
+#ifdef CONFIG_FS_CHROOT
+ /* Kernel threads share g_kthread_group and must not inherit a user jail */
+
+ if (ttype != TCB_FLAG_TTYPE_KERNEL)
Review Comment:
move the check into group_inherit_chroot
##########
fs/vfs/fs_chroot.c:
##########
@@ -0,0 +1,263 @@
+/****************************************************************************
+ * fs/vfs/fs_chroot.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/sched.h>
+
+#include "inode/inode.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: chroot_strip_slash
+ ****************************************************************************/
+
+static void chroot_strip_slash(FAR char *path)
+{
+ size_t len;
+
+ if (path == NULL)
+ {
+ return;
+ }
+
+ len = strlen(path);
+ while (len > 1 && path[len - 1] == '/')
+ {
+ path[--len] = '\0';
+ }
+}
+
+/****************************************************************************
+ * Name: chroot_set_pwd
+ *
+ * Description:
+ * Rewrite PWD so relative lookups stay inside the jail. If the current
+ * directory is not under the new root, PWD becomes "/".
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_ENVIRON
+static void chroot_set_pwd(FAR struct inode *root, FAR const char *relpath)
+{
+ char rootpath[PATH_MAX];
+ FAR const char *pwd;
+ size_t rootlen;
+
+ rootpath[0] = '\0';
+ if (root != NULL)
+ {
+ if (inode_getpath(root, rootpath, sizeof(rootpath)) < 0)
+ {
+ setenv("PWD", "/", TRUE);
+ return;
+ }
+ }
+ else
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ if (relpath != NULL && relpath[0] != '\0')
+ {
+ chroot_strip_slash(rootpath);
Review Comment:
why strip '\' and readd at line 102/106
##########
fs/vfs/fs_chroot.c:
##########
@@ -0,0 +1,263 @@
+/****************************************************************************
+ * fs/vfs/fs_chroot.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/sched.h>
+
+#include "inode/inode.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: chroot_strip_slash
+ ****************************************************************************/
+
+static void chroot_strip_slash(FAR char *path)
+{
+ size_t len;
+
+ if (path == NULL)
+ {
+ return;
+ }
+
+ len = strlen(path);
+ while (len > 1 && path[len - 1] == '/')
+ {
+ path[--len] = '\0';
+ }
+}
+
+/****************************************************************************
+ * Name: chroot_set_pwd
+ *
+ * Description:
+ * Rewrite PWD so relative lookups stay inside the jail. If the current
+ * directory is not under the new root, PWD becomes "/".
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_ENVIRON
+static void chroot_set_pwd(FAR struct inode *root, FAR const char *relpath)
+{
+ char rootpath[PATH_MAX];
+ FAR const char *pwd;
+ size_t rootlen;
+
+ rootpath[0] = '\0';
+ if (root != NULL)
+ {
+ if (inode_getpath(root, rootpath, sizeof(rootpath)) < 0)
+ {
+ setenv("PWD", "/", TRUE);
+ return;
+ }
+ }
+ else
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ if (relpath != NULL && relpath[0] != '\0')
+ {
+ chroot_strip_slash(rootpath);
+ if (rootpath[0] != '\0' && strcmp(rootpath, "/") != 0)
+ {
+ strlcat(rootpath, "/", sizeof(rootpath));
+ }
+ else if (strcmp(rootpath, "/") != 0)
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ strlcat(rootpath, relpath, sizeof(rootpath));
+ }
+
+ chroot_strip_slash(rootpath);
+ if (rootpath[0] == '\0')
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ pwd = getenv("PWD");
+ if (pwd == NULL)
+ {
+ pwd = CONFIG_LIBC_HOMEDIR;
+ }
+
+ rootlen = strlen(rootpath);
+ if (strcmp(pwd, rootpath) == 0)
+ {
+ setenv("PWD", "/", TRUE);
+ }
+ else if (rootlen > 1 && strncmp(pwd, rootpath, rootlen) == 0 &&
+ pwd[rootlen] == '/')
+ {
+ setenv("PWD", pwd + rootlen, TRUE);
+ }
+ else
+ {
+ setenv("PWD", "/", TRUE);
+ }
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: chroot
+ *
+ * Description:
+ * Cause the named directory to become the root directory, that is, the
+ * starting point for path names beginning with '/'.
+ *
+ * Input Parameters:
+ * path - Directory to use as the new root
+ *
+ * Returned Value:
+ * 0(OK) on success; -1(ERROR) on failure with errno set appropriately.
+ *
+ ****************************************************************************/
+
+int chroot(FAR const char *path)
+{
+ struct inode_search_s desc;
+ FAR struct tcb_s *rtcb;
+ FAR struct task_group_s *group;
+ FAR struct inode *oldroot;
+ FAR char *oldrel;
+ FAR char *newrel = NULL;
+ struct stat buf;
+ int errcode;
+ int ret;
+
+ if (path == NULL || path[0] == '\0')
+ {
+ set_errno(ENOENT);
+ return ERROR;
+ }
+
+ rtcb = nxsched_self();
+ DEBUGASSERT(rtcb != NULL && rtcb->group != NULL);
+ group = rtcb->group;
+
+#ifdef CONFIG_SCHED_USER_IDENTITY
+ if (group->tg_euid != 0)
+ {
+ set_errno(EPERM);
+ return ERROR;
+ }
+#endif
+
+ ret = nx_stat(path, &buf, 1);
+ if (ret < 0)
+ {
+ set_errno(-ret);
+ return ERROR;
+ }
+
+ if (!S_ISDIR(buf.st_mode))
+ {
+ set_errno(ENOTDIR);
+ return ERROR;
+ }
+
+ SETUP_SEARCH(&desc, path, false);
+
+ ret = inode_find(&desc);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout_with_search;
+ }
+
+ /* chroot("/") from the global root is a no-op jail (tg_root NULL). */
+
+ if (desc.node == g_root_inode &&
+ (desc.relpath == NULL || desc.relpath[0] == '\0'))
+ {
+ inode_release(desc.node);
+ RELEASE_SEARCH(&desc);
+ return OK;
+ }
+ else if (desc.relpath != NULL && desc.relpath[0] != '\0')
+ {
+ size_t len = strlen(desc.relpath) + 1;
+
+ newrel = kmm_malloc(len);
+ if (newrel == NULL)
+ {
+ errcode = ENOMEM;
+ inode_release(desc.node);
+ goto errout_with_search;
+ }
+
+ memcpy(newrel, desc.relpath, len);
+ }
+
+ oldroot = group->tg_root;
+ oldrel = group->tg_rootrel;
+
+ group->tg_root = desc.node;
Review Comment:
why not free directly
##########
fs/inode/fs_inodesearch.c:
##########
@@ -193,6 +199,120 @@ static int _inode_linktarget(FAR struct inode *inode,
}
#endif
+#ifdef CONFIG_FS_CHROOT
+/****************************************************************************
+ * Name: inode_get_chroot
+ ****************************************************************************/
+
+static FAR struct inode *inode_get_chroot(FAR const char **relpath)
+{
+ FAR struct tcb_s *tcb = nxsched_self();
+
+ if (relpath != NULL)
+ {
+ *relpath = NULL;
+ }
+
+ if (tcb != NULL && tcb->group != NULL && tcb->group->tg_root != NULL)
+ {
+ if (relpath != NULL)
+ {
+ *relpath = tcb->group->tg_rootrel;
+ }
+
+ return tcb->group->tg_root;
+ }
+
+ return g_root_inode;
+}
+
+/****************************************************************************
+ * Name: inode_normalize_abs
+ *
+ * Description:
+ * Normalize an absolute path: drop empty and "." segments, and clamp
+ * ".." at the search root. Needed even before a jail is installed:
+ * chroot(".") becomes "$PWD/.", and if PWD sits under a mountpoint
+ * (tmpfs /tmp) the leftover "." is passed to the filesystem as
+ * relpath and fails with ENOENT.
+ *
+ ****************************************************************************/
+
+static int inode_normalize_abs(FAR const char *in, FAR char *out,
+ size_t outlen)
+{
+ FAR char *dst;
+ FAR const char *src = in;
+
+ if (outlen < 2)
+ {
+ return -ENAMETOOLONG;
+ }
+
+ out[0] = '/';
+ dst = out + 1;
+
+ while (*src == '/')
+ {
+ src++;
+ }
+
+ while (*src != '\0')
+ {
+ FAR const char *end = src;
+ size_t seglen;
+
+ while (*end != '\0' && *end != '/')
Review Comment:
why not assign to out directly? we should touch in only once in the loop
##########
fs/vfs/fs_chroot.c:
##########
@@ -0,0 +1,263 @@
+/****************************************************************************
+ * fs/vfs/fs_chroot.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/sched.h>
+
+#include "inode/inode.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: chroot_strip_slash
+ ****************************************************************************/
+
+static void chroot_strip_slash(FAR char *path)
+{
+ size_t len;
+
+ if (path == NULL)
+ {
+ return;
+ }
+
+ len = strlen(path);
+ while (len > 1 && path[len - 1] == '/')
+ {
+ path[--len] = '\0';
+ }
+}
+
+/****************************************************************************
+ * Name: chroot_set_pwd
+ *
+ * Description:
+ * Rewrite PWD so relative lookups stay inside the jail. If the current
+ * directory is not under the new root, PWD becomes "/".
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_ENVIRON
+static void chroot_set_pwd(FAR struct inode *root, FAR const char *relpath)
+{
+ char rootpath[PATH_MAX];
+ FAR const char *pwd;
+ size_t rootlen;
+
+ rootpath[0] = '\0';
+ if (root != NULL)
+ {
+ if (inode_getpath(root, rootpath, sizeof(rootpath)) < 0)
+ {
+ setenv("PWD", "/", TRUE);
+ return;
+ }
+ }
+ else
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ if (relpath != NULL && relpath[0] != '\0')
+ {
+ chroot_strip_slash(rootpath);
+ if (rootpath[0] != '\0' && strcmp(rootpath, "/") != 0)
+ {
+ strlcat(rootpath, "/", sizeof(rootpath));
+ }
+ else if (strcmp(rootpath, "/") != 0)
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ strlcat(rootpath, relpath, sizeof(rootpath));
+ }
+
+ chroot_strip_slash(rootpath);
+ if (rootpath[0] == '\0')
+ {
+ strlcpy(rootpath, "/", sizeof(rootpath));
+ }
+
+ pwd = getenv("PWD");
+ if (pwd == NULL)
+ {
+ pwd = CONFIG_LIBC_HOMEDIR;
+ }
+
+ rootlen = strlen(rootpath);
+ if (strcmp(pwd, rootpath) == 0)
+ {
+ setenv("PWD", "/", TRUE);
Review Comment:
why change PWD? chroot should only touch fs related data, not environ.
##########
include/nuttx/sched.h:
##########
@@ -558,6 +558,13 @@ struct task_group_s
struct fdlist tg_fdlist; /* Maps file descriptor to file */
+#ifdef CONFIG_FS_CHROOT
+ /* chroot() jail **********************************************************/
+
+ FAR struct inode *tg_root; /* NULL means global pseudo-root */
+ FAR char *tg_rootrel; /* Relpath prefix if tg_root is a mount */
Review Comment:
why not save the absolute path directly? it's complex to handle tg_root and
tg_rootrel in the late patch.
BTW, the same path may remount to other file system, the current
implementation can't handle it correctly.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]