If samba is compiled on a 32b machine, it may only support 32 bit offsets.
Therefore, rather than changing its ABI, we truncate the 64 bit offsets
supported in RPCs to 32b when calling samba apis, but fail if the
requests are bigger than what would fit in the representation.
---
smb.h | 1 -
smbnetfs.c | 137 +++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 117 insertions(+), 21 deletions(-)
diff --git a/smb.h b/smb.h
index 94575fc92..c62834470 100644
--- a/smb.h
+++ b/smb.h
@@ -18,7 +18,6 @@
*/
#define _GNU_SOURCE 1
-#define _FILE_OFFSET_BITS 64
#include <string.h>
#include <stdio.h>
#include <unistd.h>
diff --git a/smbnetfs.c b/smbnetfs.c
index fc436c4c4..232d68693 100644
--- a/smbnetfs.c
+++ b/smbnetfs.c
@@ -63,14 +63,48 @@ struct netnode
struct node *entries; /* entries, if a
directory */
};
-/* Return a zeroed stat buffer for CRED. */
+/* Downsize a stat64 structure to a stat for samba compat */
static struct stat
-empty_stat (void)
+stat64_to_stat (struct stat64 st64)
{
struct stat st;
memset (&st, 0, sizeof st);
+ if ((st64.st_ino > 0xffffffff)
+ || (st64.st_size > 0x7fffffff)
+ || (st64.st_blocks > 0x7fffffff))
+ return st;
+
+ st.st_fstype = st64.st_fstype;
+ st.st_fsid = st64.st_fsid;
+ st.st_ino = st64.st_ino;
+ st.st_gen = st64.st_gen;
+ st.st_rdev = st64.st_rdev;
+ st.st_mode = st64.st_mode;
+ st.st_nlink = st64.st_nlink;
+ st.st_uid = st64.st_uid;
+ st.st_gid = st64.st_gid;
+ st.st_size = st64.st_size;
+ st.st_atime = st64.st_atime;
+ st.st_mtime = st64.st_mtime;
+ st.st_ctime = st64.st_ctime;
+ st.st_blksize = st64.st_blksize;
+ st.st_blocks = st64.st_blocks;
+ st.st_author = st64.st_author;
+ st.st_flags = st64.st_flags;
+
+ return st;
+}
+
+/* Return a zeroed stat buffer for CRED. */
+static struct stat64
+empty_stat (void)
+{
+ struct stat64 st;
+
+ memset (&st, 0, sizeof st);
+
st.st_fstype = FSTYPE_MISC;
st.st_fsid = getpid ();
@@ -183,6 +217,7 @@ add_node (const char *filename, struct node *top, struct
netnode **nn)
int err;
struct netnode *n;
struct node *newnode;
+ struct stat st;
n = search_node (filename, top);
if (n == NULL)
@@ -208,9 +243,17 @@ add_node (const char *filename, struct node *top, struct
netnode **nn)
/* A node already exists for FILENAME. */
newnode = n->node;
+ /* Reduce stat64 to stat, or fail if values too big */
+ st = stat64_to_stat (n->node->nn_stat);
+ if (!st.st_fstype)
+ {
+ netfs_nput (newnode);
+ return E2BIG;
+ }
+
/* Make sure FILENAME actually exists. */
pthread_mutex_lock (&smb_mutex);
- err = smbc_getFunctionStat(ctx) (ctx, n->abs_file_name, &n->node->nn_stat);
+ err = smbc_getFunctionStat(ctx) (ctx, n->abs_file_name, &st);
pthread_mutex_unlock (&smb_mutex);
if (err != 0)
@@ -229,11 +272,18 @@ add_node (const char *filename, struct node *top, struct
netnode **nn)
error_t
netfs_validate_stat (struct node *np, struct iouser *cred)
{
+ struct stat st;
+
np->nn_stat = empty_stat ();
np->nn_stat.st_ino = (uintptr_t) np >> 3UL;
+ /* Reduce stat64 to stat, or fail if values too big */
+ st = stat64_to_stat (np->nn_stat);
+ if (!st.st_fstype)
+ return E2BIG;
+
pthread_mutex_lock (&smb_mutex);
- int err = smbc_getFunctionStat(ctx) (ctx, np->nn->abs_file_name,
&np->nn_stat);
+ int err = smbc_getFunctionStat(ctx) (ctx, np->nn->abs_file_name, &st);
pthread_mutex_unlock (&smb_mutex);
if (err)
return errno;
@@ -327,6 +377,18 @@ netfs_attempt_set_size (struct iouser *cred, struct node
*np, loff_t size)
{
int ret, saved_errno;
SMBCFILE *fd;
+ off_t size2;
+
+ if (sizeof(off_t) == 4)
+ {
+ if (size > 0x7fffffff)
+ {
+ fprintf(stderr, "WARNING: Possible 32b truncation detected, ignoring
set size\n");
+ return E2BIG;
+ }
+ }
+
+ size2 = size;
pthread_mutex_lock (&smb_mutex);
fd = smbc_getFunctionOpen(ctx) (ctx, np->nn->abs_file_name, O_WRONLY, 0);
@@ -336,7 +398,7 @@ netfs_attempt_set_size (struct iouser *cred, struct node
*np, loff_t size)
return errno;
pthread_mutex_lock (&smb_mutex);
- ret = smbc_getFunctionFtruncate(ctx) (ctx, fd, size);
+ ret = smbc_getFunctionFtruncate(ctx) (ctx, fd, size2);
saved_errno = ret != 0 ? errno : 0;
smbc_getFunctionClose(ctx) (ctx, fd);
pthread_mutex_unlock (&smb_mutex);
@@ -479,7 +541,7 @@ netfs_attempt_mkdir (struct iouser * user, struct node *
dir, const char *name,
pthread_mutex_lock (&smb_mutex);
err = smbc_getFunctionMkdir(ctx) (ctx, filename, mode);
pthread_mutex_unlock (&smb_mutex);
-
+
free (filename);
return err ? errno : 0;
}
@@ -568,21 +630,21 @@ netfs_check_open_permissions (struct iouser * user,
struct node * np,
int flags, int newnode)
{
error_t err;
- io_statbuf_t nn_stat;
+ struct stat st;
pthread_mutex_lock (&smb_mutex);
- err = smbc_getFunctionStat(ctx) (ctx, np->nn->abs_file_name, &nn_stat);
+ err = smbc_getFunctionStat(ctx) (ctx, np->nn->abs_file_name, &st);
pthread_mutex_unlock (&smb_mutex);
-
+
if (err)
return errno;
if (flags & O_READ)
- err = !(S_IREAD & nn_stat.st_mode);
+ err = !(S_IREAD & st.st_mode);
if (flags & O_WRITE)
- err |= !(S_IWRITE & nn_stat.st_mode);
+ err |= !(S_IWRITE & st.st_mode);
if (flags & O_EXEC)
- err |= !(S_IEXEC & nn_stat.st_mode);
+ err |= !(S_IEXEC & st.st_mode);
return err?EPERM:0;
}
@@ -593,7 +655,19 @@ netfs_attempt_read (struct iouser * cred, struct node *
np, loff_t offset,
{
SMBCFILE *fd;
int ret = 0;
+ off_t offset2;
+ if (sizeof(off_t) == 4)
+ {
+ if (offset + *len > 0x7fffffff)
+ {
+ fprintf(stderr, "WARNING: Possible 32b truncation detected, ignoring
read\n");
+ return E2BIG;
+ }
+ }
+
+ offset2 = offset;
+
pthread_mutex_lock (&smb_mutex);
fd = smbc_getFunctionOpen(ctx) (ctx, np->nn->abs_file_name, O_RDONLY, 0);
pthread_mutex_unlock (&smb_mutex);
@@ -605,10 +679,10 @@ netfs_attempt_read (struct iouser * cred, struct node *
np, loff_t offset,
}
pthread_mutex_lock (&smb_mutex);
- ret = smbc_getFunctionLseek(ctx) (ctx, fd, offset, SEEK_SET);
+ ret = smbc_getFunctionLseek(ctx) (ctx, fd, offset2, SEEK_SET);
pthread_mutex_unlock (&smb_mutex);
- if ((ret < 0) || (ret != offset))
+ if ((ret < 0) || (ret != offset2))
{
*len = 0;
pthread_mutex_lock (&smb_mutex);
@@ -643,6 +717,18 @@ netfs_attempt_write (struct iouser * cred, struct node *
np, loff_t offset,
{
int ret = 0;
SMBCFILE *fd;
+ off_t offset2;
+
+ if (sizeof(off_t) == 4)
+ {
+ if (offset + *len > 0x7fffffff)
+ {
+ fprintf(stderr, "WARNING: Possible 32b truncation detected, ignoring
write\n");
+ return E2BIG;
+ }
+ }
+
+ offset2 = offset;
pthread_mutex_lock (&smb_mutex);
fd = smbc_getFunctionOpen(ctx) (ctx, np->nn->abs_file_name, O_WRONLY, 0);
@@ -654,10 +740,10 @@ netfs_attempt_write (struct iouser * cred, struct node *
np, loff_t offset,
return errno;
}
pthread_mutex_lock (&smb_mutex);
- ret = smbc_getFunctionLseek(ctx) (ctx, fd, offset, SEEK_SET);
+ ret = smbc_getFunctionLseek(ctx) (ctx, fd, offset2, SEEK_SET);
pthread_mutex_unlock (&smb_mutex);
- if ((ret < 0) || (ret != offset))
+ if ((ret < 0) || (ret != offset2))
{
*len = 0;
pthread_mutex_lock (&smb_mutex);
@@ -719,7 +805,8 @@ netfs_get_dirents (struct iouser *cred, struct node *dir,
int entry,
mach_msg_type_number_t * datacnt, vm_size_t bufsize,
int *amt)
{
- io_statbuf_t st;
+ struct stat64 st64;
+ struct stat st;
struct smbc_dirent * dirent;
int size = 0;
SMBCFILE *dd;
@@ -874,8 +961,13 @@ netfs_get_dirents (struct iouser *cred, struct node *dir,
int entry,
}
else if (!strcmp (dirent->name, ".."))
{
- st = empty_stat ();
- st.st_mode |= S_IFDIR;
+ st64 = empty_stat ();
+ st64.st_mode |= S_IFDIR;
+
+ /* Reduce stat64 to stat, or fail if values too big */
+ st = stat64_to_stat (st64);
+ if (!st.st_fstype)
+ err = errno = E2BIG;
}
else
{
@@ -893,8 +985,13 @@ netfs_get_dirents (struct iouser *cred, struct node *dir,
int entry,
if (err)
{
/* STAT_FILE_NAME is not accessible but ought to be listed. */
- st = empty_stat ();
+ st64 = empty_stat ();
err = 0;
+
+ /* Reduce stat64 to stat, or fail if values too big */
+ st = stat64_to_stat (st64);
+ if (!st.st_fstype)
+ err = errno = E2BIG;
}
}
--
2.51.0