minix/lib/libc/sys-minix/mount.c
Lionel Sambuc a00e322bea libc/sys-minix/mount.c: fix overflow
Fix a bug where a filesystem label could overflow the reserved buffer.
This was already possible with 32 bits values, but is more proeminent
with dev_t being 64 bits.

Change-Id: Idc04ed355d1dd92b7a8ce4699de832661a5c4ccd
2014-03-02 12:28:32 +01:00

239 lines
5.7 KiB
C

#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <string.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <minix/syslib.h>
#include <minix/rs.h>
#include <paths.h>
#include <unistd.h>
#define OK 0
#ifdef __weak_alias
__weak_alias(mount, _mount)
__weak_alias(umount, _umount)
#endif
#define FSDEFAULT "mfs"
static char fspath[] = "/sbin/:/usr/pkg/bin/"; /* Must include trailing '/' */
static int rs_down(char *label)
{
char cmd[200];
if(strlen(_PATH_SERVICE)+strlen(label)+50 >= sizeof(cmd))
return -1;
sprintf(cmd, _PATH_SERVICE " down '%s'", label);
return system(cmd);
}
char *find_rslabel(char *args_line);
int mount(special, name, mountflags, srvflags, type, args)
char *name, *special, *type, *args;
int mountflags, srvflags;
{
int r;
message m;
struct stat statbuf;
char label[MNT_LABEL_LEN];
char path[PATH_MAX];
char cmd[200];
char *p;
char *rslabel;
int reuse = 0;
int use_existing = 0;
/* Default values. */
if (type == NULL) type = __UNCONST(FSDEFAULT);
if (args == NULL) args = __UNCONST("");
reuse = 0;
memset(path, '\0', sizeof(path));
/* Check service flags. */
if(srvflags & MS_REUSE)
reuse = 1;
if(srvflags & MS_EXISTING)
use_existing = 1;
/* Make a label for the file system process. This label must be unique and
* may currently not exceed 16 characters including terminating null. For
* requests with an associated block device, we use the last path component
* name of the block special file (truncated to 12 characters, which is
* hopefully enough). For requests with no associated block device, we use
* the device number and inode of the mount point, in hexadecimal form.
*/
if (!use_existing) {
if (special) {
p = strrchr(special, '/');
p = p ? p + 1 : special;
if (strchr(p, '\'')) {
errno = EINVAL;
return -1;
}
snprintf(label, MNT_LABEL_LEN, "fs_%.12s", p);
} else {
/* check for a rslabel option in the arguments and try to use
* that.
*/
rslabel = find_rslabel(args);
if (rslabel != NULL){
snprintf(label, MNT_LABEL_LEN, "%s", rslabel);
free(rslabel);
} else {
if (stat(name, &statbuf) < 0) return -1;
snprintf(label, MNT_LABEL_LEN, "fs_%llx_%llx", statbuf.st_dev, statbuf.st_ino);
}
}
} else {
/* label to long? */
if (strlen(type) < MNT_LABEL_LEN) {
snprintf(label, MNT_LABEL_LEN, "%s", type);
} else {
errno = ENOMEM;
return -1;
}
}
/* Sanity check on user input. */
if(strchr(args, '\'')) {
errno = EINVAL;
return -1;
}
/* start the fs-server if not using existing one */
if (!use_existing) {
/* See if the given type is even remotely valid. */
char *testpath;
testpath = strtok(fspath, ":");
do {
if (strlen(testpath) + strlen(type) >= sizeof(path)) {
errno = E2BIG;
return(-1);
}
strcpy(path, testpath);
strcat(path, type);
if (access(path, F_OK) == 0) break;
} while ((testpath = strtok(NULL, ":")) != NULL);
if (testpath == NULL) {
/* We were not able to find type somewhere in "fspath" */
errno = EINVAL;
return(-1);
}
if (strlen(_PATH_SERVICE) + strlen(path) + strlen(label) +
strlen(args) + 50 >= sizeof(cmd)) {
errno = E2BIG;
return -1;
}
sprintf(cmd, _PATH_SERVICE " %sup %s -label '%s' -args '%s %s %s%s'",
reuse ? "-r ": "", path, label, special, name,
args[0] ? "-o " : "", args);
if ((r = system(cmd)) != 0) {
fprintf(stderr, "mount: couldn't run %s\n", cmd);
errno = r;
return -1;
}
}
/* Now perform mount(). */
memset(&m, 0, sizeof(m));
m.VFS_MOUNT_FLAGS = mountflags;
m.VFS_MOUNT_DEVLEN = special ? strlen(special) + 1 : 0;
m.VFS_MOUNT_PATHLEN = strlen(name) + 1;
m.VFS_MOUNT_TYPELEN = strlen(type) + 1;
m.VFS_MOUNT_LABELLEN = strlen(label) + 1;
m.VFS_MOUNT_DEV = special;
m.VFS_MOUNT_PATH = name;
m.VFS_MOUNT_TYPE = type;
m.VFS_MOUNT_LABEL = label;
r = _syscall(VFS_PROC_NR, VFS_MOUNT, &m);
if (r != OK && !use_existing) {
/* If mount() failed, tell RS to shutdown FS process.
* No error check - won't do anything with this error anyway.
*/
rs_down(label);
}
return r;
}
int umount(name, srvflags)
const char *name;
int srvflags;
{
char label[MNT_LABEL_LEN];
message m;
int r;
memset(&m, 0, sizeof(m));
m.VFS_UMOUNT_NAME = __UNCONST(name);
m.VFS_UMOUNT_NAMELEN = strlen(name) + 1;
m.VFS_UMOUNT_LABEL = label;
m.VFS_UMOUNT_LABELLEN = sizeof(label);
r = _syscall(VFS_PROC_NR, VFS_UMOUNT, &m);
/* don't shut down the driver when exist flag is set */
if (!(srvflags & MS_EXISTING)) {
if (r == OK) {
/* VFS returns the label of the unmounted file system to us. */
rs_down(label);
}
}
return r;
}
char *find_rslabel(char *args_line)
{
/**
* Find and return the rslabel as given as optional
* agument to the mount command e.g.
* mount -o rslabel=bla
* or
* mount -o rw,rslabel=bla
* or as found in fstab
**/
char *buf, *input,*saveptr;
buf = input = saveptr = NULL;
if (args_line == NULL) return NULL;
/* copy the input args_line we are going to modify it*/
input = strndup(args_line,20);
if (input == NULL) /* EOM */
return NULL; /* it is not that bad to not find a label */
/* locate rslabel= in the input */
buf = strstr(input,"rslabel=");
if (buf == NULL) {
free(input);
return NULL;
}
/* tokenise on "," starting from rslabel (e.g null terminate )*/
buf = strtok_r(buf,",",&saveptr);
/* tokenise the result again using = and take the second entry */
buf = strtok_r(buf,"=",&saveptr);
buf = strtok_r(NULL,"=",&saveptr);
/* buf is now either NULL if there was no second token or
* the value we are searchig for
*/
if (buf != NULL)
buf = strdup(buf);
free(input);
return buf;
}