#include <linux/file.h>
#include <linux/uaccess.h>
#include <linux/namei.h>
-#include <linux/vmalloc.h>
#include <linux/poll.h>
#include <linux/anon_inodes.h>
}
- m->data = vmalloc(size);
+ m->data = palacios_valloc(size);
if (!m->data) {
palacios_free(m);
{
if (m) {
if (m->data) {
- vfree(m->data);
+ palacios_vfree(m->data);
}
m->data=0;
palacios_free(m);
static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
{
- void *data = vmalloc(new_size);
+ void *data = palacios_valloc(new_size);
uint32_t nc;
if (!data) {
memcpy(data,m->data,nc);
- vfree(m->data);
+ palacios_vfree(m->data);
m->data=data;
m->size=new_size;
return 0;
}
- strcpy(mykey,url+4);
+ strcpy(mykey,url+4); // will fit
mks = (struct mem_keyed_stream *) palacios_alloc(sizeof(struct mem_keyed_stream));
return 0;
}
- strcpy(mykey,key);
+ strcpy(mykey,key); // will fit
m = create_mem_stream();
return;
}
- strcpy(mykey,key);
+ strcpy(mykey,key); // will fit
m = create_mem_stream_internal(size);
struct file *f; // the opened file
};
+/* lookup directory, see if it is writeable, and if so, create it if asked*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,41)
+
+static int lookup_check_mkdir(const char *path, int need_write, int create, unsigned short perms)
+{
+ struct nameidata nd;
+
+ if (path_lookup(path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) {
+
+ // directory does does not exist.
+
+ if (!create) {
+ // we are not being asked to create it
+ ERROR("attempt to open %s, which does not exist\n",path);
+ return -1;
+ } else {
+ // We are being asked to create it
+
+ struct dentry *de;
+ int err;
+
+ // Find its parent
+ if (path_lookup(path,LOOKUP_PARENT|LOOKUP_FOLLOW,&nd)) {
+ ERROR("attempt to create %s failed because its parent cannot be looked up\n",path);
+ return -1;
+ }
+
+ // Can we write to the parent?
+
+ if (inode_permission(nd.path.dentry->d_inode, MAY_WRITE | MAY_EXEC)) {
+ ERROR("attempt to open %s, which has the wrong permissions for directory creation\n",path);
+ return -1;
+ }
+
+ // OK, we can, so let's create it
+
+ de = lookup_create(&nd,1);
+
+ if (!de || IS_ERR(de)) {
+ ERROR("cannot allocate dentry\n");
+ return -1;
+ }
+
+ err = vfs_mkdir(nd.path.dentry->d_inode, de, perms);
+
+ // lookup_create locks this for us!
+
+ mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
+
+ if (err) {
+ ERROR("attempt to create %s failed because mkdir failed\n",path);
+ return -1;
+ }
+
+ // successfully created it.
+ return 0;
+
+ }
+
+ } else {
+
+ // it exists, can we read (and write, if needed) to it?
+
+ if (inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_READ | need_write ? MAY_WRITE : 0 )) {
+ ERROR("attempt to open %s, which has the wrong permissions\n",path);
+ return -1;
+ }
+
+ return 0;
+ }
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,41)
+static int lookup_check_mkdir(const char *path, int need_write, int create, unsigned short perms)
+{
+ struct path p;
+
+ if (kern_path(path, LOOKUP_DIRECTORY|LOOKUP_FOLLOW, &p)) {
+
+ // directory does does not exist.
+
+ if (!create) {
+ // we are not being asked to create it
+ ERROR("attempt to open %s, which does not exist\n",path);
+ return -1;
+ } else {
+ // We are being asked to create it
+
+ struct dentry *de;
+ int err;
+
+ // Find its parent
+ if (kern_path(path,LOOKUP_PARENT|LOOKUP_FOLLOW,&p)) {
+ ERROR("attempt to create %s failed because its parent cannot be looked up\n",path);
+ return -1;
+ }
+
+ // Can we write to the parent?
+
+ if (inode_permission(p.dentry->d_inode, MAY_WRITE | MAY_EXEC)) {
+ ERROR("attempt to open %s, which has the wrong permissions for directory creation\n",path);
+ return -1;
+ }
+
+ // OK, we can, so let's create it
+
+ de = kern_path_create(AT_FDCWD,path,&p,1);
+
+ if (!de || IS_ERR(de)) {
+ ERROR("cannot allocate dentry\n");
+ return -1;
+ }
+
+ err = vfs_mkdir(p.dentry->d_inode, de, perms);
+
+ // lookup_create locks this for us!
+
+ mutex_unlock(&(p.dentry->d_inode->i_mutex));
+
+ if (err) {
+ ERROR("attempt to create %s failed because mkdir failed\n",path);
+ return -1;
+ }
+
+ // successfully created it.
+ return 0;
+
+ }
+
+ } else {
+
+ // it exists, can we read (and write, if needed) to it?
+
+ if (inode_permission(p.dentry->d_inode, MAY_EXEC | MAY_READ | need_write ? MAY_WRITE : 0 )) {
+ ERROR("attempt to open %s, which has the wrong permissions\n",path);
+ return -1;
+ }
+
+ return 0;
+ }
+}
+
+#endif
+
static v3_keyed_stream_t open_stream_file(char *url,
v3_keyed_stream_open_t ot)
{
struct file_keyed_stream *fks;
- struct nameidata nd;
if (strncasecmp(url,"file:",5)) {
WARNING("illegitimate attempt to open file stream \"%s\"\n",url);
return 0;
}
- strcpy(fks->path,url+5);
+ strcpy(fks->path,url+5); // will fit
fks->stype=STREAM_FILE;
fks->ot= ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
- // Does the directory exist, and can we read/write it?
-
- if (path_lookup(fks->path,LOOKUP_DIRECTORY|LOOKUP_FOLLOW,&nd)) {
-
- // directory does does not exist.
-
- if (ot==V3_KS_RD_ONLY || ot==V3_KS_WR_ONLY) {
-
- // we are not being asked to create it
- ERROR("attempt to open %s, which does not exist\n",fks->path);
- goto fail_out;
-
- } else {
-
- // We are being asked to create it
-
- struct dentry *de;
- int err;
-
- // Find its parent
- if (path_lookup(fks->path,LOOKUP_PARENT|LOOKUP_FOLLOW,&nd)) {
- ERROR("attempt to create %s failed because its parent cannot be looked up\n",fks->path);
- goto fail_out;
- }
-
- // Can we write to the parent?
-
- if (inode_permission(nd.path.dentry->d_inode, MAY_WRITE | MAY_EXEC)) {
- ERROR("attempt to open %s, which has the wrong permissions for directory creation\n",fks->path);
- goto fail_out;
- }
-
- // OK, we can, so let's create it
-
- de = lookup_create(&nd,1);
-
- if (IS_ERR(de)) {
- ERROR("cannot allocate dentry\n");
- goto fail_out;
- }
-
- err = vfs_mkdir(nd.path.dentry->d_inode, de, 0700);
-
- // lookup_create locks this for us!
-
- mutex_unlock(&(nd.path.dentry->d_inode->i_mutex));
-
- if (err) {
- ERROR("attempt to create %s failed because mkdir failed\n",fks->path);
- goto fail_out;
- }
-
- // now the directory should exist and have reasonable permissions
- return (v3_keyed_stream_t) fks;
- }
- }
-
-
- // we must be in V3_KS_RD_ONLY or V3_KS_WR_ONLY,
- // and the directory exists, so we must check the permissions
-
- if (inode_permission(nd.path.dentry->d_inode, MAY_EXEC | (ot==V3_KS_RD_ONLY ? MAY_READ : MAY_WRITE))) {
- ERROR("attempt to open %s, which has the wrong permissions\n",fks->path);
- goto fail_out;
- } else {
- return (v3_keyed_stream_t) fks;
+ if (lookup_check_mkdir(fks->path,ot!=V3_KS_RD_ONLY,ot==V3_KS_WR_ONLY_CREATE,0700)) {
+ ERROR("cannot find or create directory for stream\n");
+ goto fail_out;
}
+ return fks;
fail_out:
palacios_free(fks->path);
ERROR("cannot allocate file keyed stream for key %s\n",key);
return 0;
}
+ // this sequence will fit and terminate with a zero
strcpy(path,fks->path);
strcat(path,"/");
strcat(path,key);
- fs = (struct file_stream *) palacios_alloc(sizeof(struct file_stream *));
+ fs = (struct file_stream *) palacios_alloc(sizeof(struct file_stream));
if (!fs) {
ERROR("cannot allocate file keyed stream for key %s\n",key);
fs->stype=STREAM_FILE;
- fs->f = filp_open(path,O_RDWR|O_CREAT,0600);
-
- if (IS_ERR(fs->f)) {
+ fs->f = filp_open(path,O_RDWR|O_CREAT|O_LARGEFILE,0600);
+
+ if (!fs->f || IS_ERR(fs->f)) {
ERROR("cannot open relevent file \"%s\" for stream \"file:%s\" and key \"%s\"\n",path,fks->path,key);
palacios_free(fs);
palacios_free(path);
s->waiting = 1;
// release the stream
- spin_unlock_irqrestore(&(s->lock), *flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), *flags);
// wake up anyone waiting on it
wake_up_interruptible(&(s->user_wait_queue));
while (wait_event_interruptible(s->host_wait_queue, (s->waiting == 0)) != 0) {}
// reacquire the lock for our called
- spin_lock_irqsave(&(s->lock), *flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), *flags);
return 0;
}
s->waiting = 0;
// release the stream
- spin_unlock_irqrestore(&(s->lock), *flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), *flags);
// wake up anyone waiting on it
wake_up_interruptible(&(s->host_wait_queue));
return POLLERR;
}
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
+
+ poll_wait(filp, &(s->user_wait_queue), wait);
if (s->waiting) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return POLLIN | POLLRDNORM;
}
-
- poll_wait(filp, &(s->user_wait_queue), wait);
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return 0;
}
// inform request size
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (!(s->waiting)) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return 0;
}
size = sizeof(struct palacios_user_keyed_stream_op) + s->op->buf_len;
if (copy_to_user((void * __user) argp, &size, sizeof(uint64_t))) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
ERROR("palacios user key size request failed to copy data\n");
return -EFAULT;
}
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return 1;
// pull the request
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (!(s->waiting)) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
ERROR("palacios user key pull request when not waiting\n");
return 0;
}
if (copy_to_user((void __user *) argp, s->op, size)) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
ERROR("palacios user key pull request failed to copy data\n");
return -EFAULT;
}
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return 1;
// push the response
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (!(s->waiting)) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
ERROR("palacios user key push response when not waiting\n");
return 0;
}
if (copy_from_user(&size, (void __user *) argp, sizeof(uint64_t))) {
ERROR("palacios user key push response failed to copy size\n");
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return -EFAULT;
}
+ // overflow possible here for very large request
if (resize_op(&(s->op),size-sizeof(struct palacios_user_keyed_stream_op))) {
ERROR("unable to resize op in user key push response\n");
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return -EFAULT;
}
if (copy_from_user(s->op, (void __user *) argp, size)) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return -EFAULT;
}
struct user_keyed_stream *s = filp->private_data;
unsigned long f1,f2;
- spin_lock_irqsave(&(user_streams->lock),f1);
- spin_lock_irqsave(&(s->lock), f2);
+ palacios_spinlock_lock_irqsave(&(user_streams->lock),f1);
+ palacios_spinlock_lock_irqsave(&(s->lock), f2);
list_del(&(s->node));
- spin_unlock_irqrestore(&(s->lock), f2);
- spin_unlock_irqrestore(&(user_streams->lock), f1);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), f2);
+ palacios_spinlock_unlock_irqrestore(&(user_streams->lock), f1);
palacios_free(s->url);
palacios_free(s);
return -1;
}
+ // overflow possible here, but only if this is a huge guest request (>4GB)
url = palacios_alloc(len);
if (!url) {
// Check for duplicate handler
- spin_lock_irqsave(&(user_streams->lock), flags);
+ palacios_spinlock_lock_irqsave(&(user_streams->lock), flags);
list_for_each_entry(s, &(user_streams->streams), node) {
if (!strncasecmp(url, s->url, len)) {
ERROR("user keyed stream connection with url \"%s\" already exists\n", url);
return -1;
}
}
- spin_unlock_irqrestore(&(user_streams->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
// Create connection
s = palacios_alloc(sizeof(struct user_keyed_stream));
init_waitqueue_head(&(s->host_wait_queue));
// Insert connection into list
- spin_lock_irqsave(&(user_streams->lock), flags);
+ palacios_spinlock_lock_irqsave(&(user_streams->lock), flags);
list_add(&(s->node), &(user_streams->streams));
- spin_unlock_irqrestore(&(user_streams->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
return fd;
}
return NULL;
}
- spin_lock_irqsave(&(user_streams->lock), flags);
+ palacios_spinlock_lock_irqsave(&(user_streams->lock), flags);
list_for_each_entry(s, &(user_streams->streams), node) {
if (!strcasecmp(url, s->url)) {
- spin_unlock_irqrestore(&(user_streams->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
return s;
}
}
- spin_unlock_irqrestore(&(user_streams->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(user_streams->lock), flags);
return NULL;
}
return NULL;
}
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (s->waiting) {
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
ERROR("cannot open user stream %s as it is already in waiting state\n",url);
return NULL;
}
s->otype = ot==V3_KS_WR_ONLY_CREATE ? V3_KS_WR_ONLY : ot;
- spin_unlock_irqrestore(&(s->lock), flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock), flags);
return s;
uint64_t len = strlen(key)+1;
void *user_key;
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (resize_op(&(s->op),len)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("cannot resize op in opening key %s on user keyed stream %s\n",key,s->url);
return NULL;
}
s->op->type = PALACIOS_KSTREAM_OPEN_KEY;
s->op->buf_len = len;
- strncpy(s->op->buf,key,len);
+ strncpy(s->op->buf,key,len); // will terminate buffer
// enter with it locked
if (do_request_to_response(s,&flags)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("request/response handling failed\n");
return NULL;
}
user_key=s->op->user_key;
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
return user_key;
}
uint64_t len = 0;
unsigned long flags;
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (resize_op(&(s->op),len)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("cannot resize op in closing key 0x%p on user keyed stream %s\n",key,s->url);
return;
}
// enter with it locked
if (do_request_to_response(s,&flags)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("request/response handling failed\n");
return;
}
// return with it locked
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
return;
}
sint64_t xfer;
unsigned long flags;
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (s->otype != V3_KS_RD_ONLY) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("attempt to read key from stream that is not in read state on %s\n",s->url);
}
if (resize_op(&(s->op),len)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("cannot resize op in reading key 0x%p on user keyed stream %s\n",key,s->url);
return -1;
}
// enter with it locked
if (do_request_to_response(s,&flags)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("request/response handling failed\n");
return -1;
}
xfer=s->op->xfer;
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
return xfer;
}
unsigned long flags;
- spin_lock_irqsave(&(s->lock), flags);
+ palacios_spinlock_lock_irqsave(&(s->lock), flags);
if (s->otype != V3_KS_WR_ONLY) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("attempt to write key on stream that is not in write state on %s\n",s->url);
}
if (resize_op(&(s->op),len)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("cannot resize op in reading key 0x%p on user keyed stream %s\n",key,s->url);
return -1;
}
// enter with it locked
if (do_request_to_response(s,&flags)) {
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
ERROR("request/response handling failed\n");
return -1;
}
xfer=s->op->xfer;
- spin_unlock_irqrestore(&(s->lock),flags);
+ palacios_spinlock_unlock_irqrestore(&(s->lock),flags);
return xfer;
}
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
+#else
+ iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
+#endif
iov.iov_base = (char *)&(buf[len-left]);
iov.iov_len = (size_t)left;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
+#else
+ iov_iter_init(&(msg.msg_iter),READ,&iov,1,0);
+#endif
iov.iov_base = (void *)&(buf[len-left]);
iov.iov_len = (size_t)left;
ERROR("Could not send tag length in write_key_net\n");
return -1;
}
- if (send_msg(nks->ns,tag,taglen)!=len) {
+ if (send_msg(nks->ns,tag,taglen)!=taglen) {
ERROR("Could not send tag in write_key_net\n");
return -1;
}
INIT_LIST_HEAD(&(user_streams->streams));
- spin_lock_init(&(user_streams->lock));
+ palacios_spinlock_init(&(user_streams->lock));
V3_Init_Keyed_Streams(&hooks);
{
palacios_free_htable(mem_streams,1,1);
+ palacios_spinlock_deinit(&(user_streams->lock));
+
palacios_free(user_streams);
WARNING("Deinit of Palacios Keyed Streams likely leaked memory\n");
static int guest_deinit_keyed_streams(struct v3_guest * guest, void * vm_data)
{
+ remove_guest_ctrl(guest, V3_VM_KSTREAM_USER_CONNECT);
return 0;
}