diff --git a/daemon/nfs41_const.h b/daemon/nfs41_const.h index bfaebe5..82ec80f 100644 --- a/daemon/nfs41_const.h +++ b/daemon/nfs41_const.h @@ -55,6 +55,10 @@ /* "udp" "tcp" "udp6" "tcp6" */ #define NFS41_NETWORK_ID_LEN 4 +/* msdn: There is a maximum of 31 reparse points (and + * therefore symbolic links) allowed in a particular path. */ +#define NFS41_MAX_SYMLINK_DEPTH 31 + /* 424 bytes: max rpc header for reply with data */ /* 32 bytes: max COMPOUND response */ diff --git a/daemon/open.c b/daemon/open.c index b1f8f7f..51174c4 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -237,11 +237,22 @@ int handle_open(nfs41_upcall *upcall) &state->path, &state->parent, &state->file, &info, &state->session); if (status == ERROR_REPARSE) { + uint32_t depth = 0; /* one of the parent components was a symlink */ do { + if (++depth > NFS41_MAX_SYMLINK_DEPTH) { + status = ERROR_TOO_MANY_LINKS; + goto out_free_state; + } + /* replace the path with the symlink target's */ status = nfs41_symlink_target(state->session, &state->parent, &state->path); + if (status) { + /* can't do the reparse if we can't get the target */ + eprintf("nfs41_symlink_target() failed with %d\n", status); + goto out_free_state; + } /* redo the lookup until it doesn't return REPARSE */ status = nfs41_lookup(args->root, state->session, diff --git a/daemon/setattr.c b/daemon/setattr.c index 2df1a10..62ac20c 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -204,6 +204,7 @@ static int handle_nfs41_rename(setattr_upcall_args *args) nfs41_abs_path dst_path; nfs41_path_fh dst_dir; nfs41_component dst_name, *src_name; + uint32_t depth = 0; int status; ZeroMemory(&dst_path, sizeof(dst_path)); @@ -252,8 +253,17 @@ static int handle_nfs41_rename(setattr_upcall_args *args) &dst_path, &dst_dir, NULL, NULL, &dst_session); while (status == ERROR_REPARSE) { + if (++depth > NFS41_MAX_SYMLINK_DEPTH) { + status = ERROR_TOO_MANY_LINKS; + goto out; + } + /* replace the path with the symlink target's */ status = nfs41_symlink_target(dst_session, &dst_dir, &dst_path); + if (status) { + eprintf("nfs41_symlink_target() failed with %d\n", status); + goto out; + } /* redo the lookup until it doesn't return REPARSE */ status = nfs41_lookup(args->root, dst_session, @@ -336,6 +346,7 @@ int handle_nfs41_link(setattr_upcall_args *args) nfs41_abs_path dst_path; nfs41_path_fh dst_dir; nfs41_component dst_name; + uint32_t depth = 0; int status; ZeroMemory(&dst_path, sizeof(dst_path)); @@ -356,8 +367,17 @@ int handle_nfs41_link(setattr_upcall_args *args) &dst_path, &dst_dir, NULL, NULL, &dst_session); while (status == ERROR_REPARSE) { + if (++depth > NFS41_MAX_SYMLINK_DEPTH) { + status = ERROR_TOO_MANY_LINKS; + goto out; + } + /* replace the path with the symlink target's */ status = nfs41_symlink_target(dst_session, &dst_dir, &dst_path); + if (status) { + eprintf("nfs41_symlink_target() failed with %d\n", status); + goto out; + } /* redo the lookup until it doesn't return REPARSE */ status = nfs41_lookup(args->root, dst_session, diff --git a/daemon/symlink.c b/daemon/symlink.c index f54c1e3..0373f4b 100644 --- a/daemon/symlink.c +++ b/daemon/symlink.c @@ -152,6 +152,7 @@ int nfs41_symlink_follow( { nfs41_abs_path path; nfs41_path_fh file; + uint32_t depth = 0; int status = NO_ERROR; file.path = &path; @@ -160,6 +161,11 @@ int nfs41_symlink_follow( dprintf(2, "--> nfs41_symlink_follow('%s')\n", symlink->path->path); do { + if (++depth > NFS41_MAX_SYMLINK_DEPTH) { + status = ERROR_TOO_MANY_LINKS; + goto out; + } + /* construct the target path */ status = nfs41_symlink_target(session, symlink, &path); if (status) goto out;