Пример #1
0
int cpt_collect_tty(struct file *file, cpt_context_t * ctx)
{
	struct tty_struct *tty = file->private_data;

	if (tty) {
		if (cpt_object_add(CPT_OBJ_TTY, tty, ctx) == NULL)
			return -ENOMEM;
		if (tty->link) {
			cpt_object_t *obj;

			obj = cpt_object_add(CPT_OBJ_TTY, tty->link, ctx);
			if (obj == NULL)
				return -ENOMEM;
			/* Undo o_count, tty->link is not a reference */
			obj->o_count--;
		}
	}
	return 0;
}
Пример #2
0
static int open_listening_socket(loff_t pos, struct cpt_sock_image *si,
                                 struct cpt_context *ctx)
{
    int err;
    struct socket *sock;
    struct file *file;
    cpt_object_t *obj, *fobj;

    err = sock_create(si->cpt_family, si->cpt_type, si->cpt_protocol,
                      &sock);
    if (err) {
        eprintk_ctx("open_listening_socket: sock_create: %d\n", err);
        return err;
    }

    sock->sk->sk_reuse = 2;
    sock->sk->sk_bound_dev_if = si->cpt_bound_dev_if;

    if (sock->sk->sk_family == AF_UNIX) {
        err = bind_unix_socket(sock, si, ctx);
    } else if (si->cpt_laddrlen) {
        if (sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6)
            inet_sk(sock->sk)->freebind = 1;

        err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen);

        if (err) {
            eprintk_ctx("open_listening_socket: bind: %d\n", err);
            goto err_out;
        }
    }

    err = sock->ops->listen(sock, si->cpt_max_ack_backlog);
    if (err) {
        eprintk_ctx("open_listening_socket: listen: %d, %Ld, %d\n", err, pos, si->cpt_deleted);
        goto err_out;
    }

    /* Now we may access socket body directly and fixup all the things. */

    file = sock_mapfile(sock);
    err = PTR_ERR(file);
    if (IS_ERR(file)) {
        eprintk_ctx("open_listening_socket: map: %d\n", err);
        goto err_out;
    }

    err = -ENOMEM;
    if ((fobj = cpt_object_add(CPT_OBJ_FILE, file, ctx)) == NULL)
        goto err_out;
    if ((obj = cpt_object_add(CPT_OBJ_SOCKET, sock->sk, ctx)) == NULL)
        goto err_out;
    cpt_obj_setpos(obj, pos, ctx);
    cpt_obj_setindex(obj, si->cpt_index, ctx);
    obj->o_parent = file;
    cpt_obj_setpos(fobj, si->cpt_file, ctx);
    cpt_obj_setindex(fobj, si->cpt_index, ctx);

    setup_sock_common(sock->sk, si, pos, ctx);

    if (si->cpt_family == AF_INET || si->cpt_family == AF_INET6) {
        rst_listen_socket_in(sock->sk, si, pos, ctx);
        rst_restore_synwait_queue(sock->sk, si, pos, ctx);
    }

    return 0;

err_out:
    sock_release(sock);
    return err;
}
Пример #3
0
static int open_socket(cpt_object_t *obj, struct cpt_sock_image *si,
                       struct cpt_context *ctx)
{
    int err;
    struct socket *sock;
    struct socket *sock2 = NULL;
    struct file *file;
    cpt_object_t *fobj;
    cpt_object_t *pobj = NULL;

    err = sock_create(si->cpt_family, si->cpt_type, si->cpt_protocol,
                      &sock);
    if (err)
        return err;

    if (si->cpt_socketpair) {
        err = sock_create(si->cpt_family, si->cpt_type,
                          si->cpt_protocol, &sock2);
        if (err)
            goto err_out;

        err = sock->ops->socketpair(sock, sock2);
        if (err < 0)
            goto err_out;

        /* Socketpair with a peer outside our environment.
         * So, we create real half-open pipe and do not worry
         * about dead end anymore. */
        if (si->cpt_peer == -1) {
            sock_release(sock2);
            sock2 = NULL;
        }
    }

    cpt_obj_setobj(obj, sock->sk, ctx);

    if (si->cpt_file != CPT_NULL) {
        file = sock_mapfile(sock);
        err = PTR_ERR(file);
        if (IS_ERR(file))
            goto err_out;

        err = -ENOMEM;

        obj->o_parent = file;

        if ((fobj = cpt_object_add(CPT_OBJ_FILE, file, ctx)) == NULL)
            goto err_out;
        cpt_obj_setpos(fobj, si->cpt_file, ctx);
        cpt_obj_setindex(fobj, si->cpt_index, ctx);
    }

    if (sock2) {
        struct file *file2;

        pobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_peer, ctx);
        if (!pobj) BUG();
        if (pobj->o_obj) BUG();
        cpt_obj_setobj(pobj, sock2->sk, ctx);

        if (pobj->o_ppos != CPT_NULL) {
            file2 = sock_mapfile(sock2);
            err = PTR_ERR(file2);
            if (IS_ERR(file2))
                goto err_out;

            err = -ENOMEM;
            if ((fobj = cpt_object_add(CPT_OBJ_FILE, file2, ctx)) == NULL)
                goto err_out;
            cpt_obj_setpos(fobj, pobj->o_ppos, ctx);
            cpt_obj_setindex(fobj, si->cpt_peer, ctx);

            pobj->o_parent = file2;
        }
    }

    setup_sock_common(sock->sk, si, obj->o_pos, ctx);
    if (sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6) {
        int saved_reuse = sock->sk->sk_reuse;

        inet_sk(sock->sk)->freebind = 1;
        sock->sk->sk_reuse = 2;
        if (si->cpt_laddrlen) {
            err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen);
            if (err) {
                dprintk_ctx("binding failed: %d, do not worry\n", err);
            }
        }
        sock->sk->sk_reuse = saved_reuse;
        rst_socket_in(si, obj->o_pos, sock->sk, ctx);
    } else if (sock->sk->sk_family == AF_NETLINK) {
        struct sockaddr_nl *nl = (struct sockaddr_nl *)&si->cpt_laddr;
        if (nl->nl_pid) {
            err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen);
            if (err) {
                eprintk_ctx("AF_NETLINK binding failed: %d\n", err);
            }
        }
        if (si->cpt_raddrlen && nl->nl_pid) {
            err = sock->ops->connect(sock, (struct sockaddr *)&si->cpt_raddr, si->cpt_raddrlen, O_NONBLOCK);
            if (err) {
                eprintk_ctx("oops, AF_NETLINK connect failed: %d\n", err);
            }
        }
        generic_restore_queues(sock->sk, si, obj->o_pos, ctx);
    } else if (sock->sk->sk_family == PF_PACKET) {
        struct sockaddr_ll *ll = (struct sockaddr_ll *)&si->cpt_laddr;
        if (ll->sll_protocol || ll->sll_ifindex) {
            int alen = si->cpt_laddrlen;
            if (alen < sizeof(struct sockaddr_ll))
                alen = sizeof(struct sockaddr_ll);
            err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, alen);
            if (err) {
                eprintk_ctx("AF_PACKET binding failed: %d\n", err);
            }
        }
        generic_restore_queues(sock->sk, si, obj->o_pos, ctx);
    }
    fixup_unix_address(sock, si, ctx);

    if (sock2) {
        err = rst_get_object(CPT_OBJ_SOCKET, pobj->o_pos, si, ctx);
        if (err)
            return err;
        setup_sock_common(sock2->sk, si, pobj->o_pos, ctx);
        fixup_unix_address(sock2, si, ctx);
    }

    if ((sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6)
            && (int)si->cpt_parent != -1) {
        cpt_object_t *lobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_parent, ctx);
        if (lobj && cpt_attach_accept(lobj->o_obj, sock->sk, ctx) == 0)
            sock->sk = NULL;
    }


    if (si->cpt_file == CPT_NULL && sock->sk &&
            sock->sk->sk_family == AF_INET) {
        struct sock *sk = sock->sk;

        if (sk) {
            sock->sk = NULL;

            local_bh_disable();
            bh_lock_sock(sk);
            if (sock_owned_by_user(sk))
                eprintk_ctx("oops, sock is locked by user\n");

            sock_hold(sk);
            sock_orphan(sk);
            ub_inc_orphan_count(sk);
            bh_unlock_sock(sk);
            local_bh_enable();
            sock_put(sk);
            dprintk_ctx("orphaning socket %p\n", sk);
        }
    }

    if (si->cpt_file == CPT_NULL && sock->sk == NULL)
        sock_release(sock);

    return 0;

err_out:
    if (sock2)
        sock_release(sock2);
    sock_release(sock);
    return err;
}
Пример #4
0
struct file * rst_open_tty(cpt_object_t *mntobj, char *name,
			   struct cpt_file_image *fi, struct cpt_inode_image *ii,
			   unsigned flags, struct cpt_context *ctx)
{
	int err;
	cpt_object_t *obj;
	struct file *master, *slave;
	struct tty_struct *stty;
	struct cpt_tty_image *pi;
	static char *a = "pqrstuvwxyzabcde";
	static char *b = "0123456789abcdef";
	char pairname[16];
	unsigned master_flags, slave_flags;

	if (fi->cpt_priv == CPT_NULL)
		return ERR_PTR(-EINVAL);

	obj = lookup_cpt_obj_bypos(CPT_OBJ_TTY, fi->cpt_priv, ctx);
	if (obj && obj->o_parent) {
		dprintk_ctx("obtained pty as pair to existing\n");
		master = obj->o_parent;
		stty = file_tty(master);

		if (stty->driver->subtype == PTY_TYPE_MASTER &&
		    (stty->driver->flags&TTY_DRIVER_DEVPTS_MEM)) {
			wprintk_ctx("cloning ptmx\n");
			get_file(master);
			return master;
		}

		master = dentry_open(dget(master->f_dentry),
				     mntget(master->f_vfsmnt), flags,
				     current_cred());
		if (!IS_ERR(master)) {
			stty = file_tty(master);
			if (stty->driver->subtype != PTY_TYPE_MASTER)
				fixup_tty_attrs(ii, master, ctx);
		}
		return master;
	}

	pi = cpt_get_buf(ctx);
	err = rst_get_object(CPT_OBJ_TTY, fi->cpt_priv, pi, ctx);
	if (err) {
		cpt_release_buf(ctx);
		return ERR_PTR(err);
	}

	if (MAJOR(ii->cpt_rdev) == TTY_MAJOR ||
	    ii->cpt_rdev == MKDEV(TTYAUX_MAJOR, 1)) {
		if (mntobj && (mntobj->o_flags & CPT_VFSMOUNT_DELAYFS))
		       return ERR_PTR(-ENOTSUPP);
		master = rst_open_file(mntobj, name, fi,
				flags|O_NONBLOCK|O_NOCTTY, ctx);
		if (IS_ERR(master)) {
			eprintk_ctx("rst_open_tty: %s %Ld %ld\n",
					name, (long long)fi->cpt_priv,
					PTR_ERR(master));
			return master;
		}

		stty = file_tty(master);
		obj = cpt_object_add(CPT_OBJ_TTY, stty, ctx);
		obj->o_parent = master;
		cpt_obj_setpos(obj, fi->cpt_priv, ctx);

		obj = cpt_object_add(CPT_OBJ_FILE, master, ctx);
		cpt_obj_setpos(obj, CPT_NULL, ctx);
		get_file(master);

		/* Do not restore /dev/ttyX state */
		cpt_release_buf(ctx);
		return master;
	}

	master_flags = slave_flags = 0;
	if (pi->cpt_drv_subtype == PTY_TYPE_MASTER)
		master_flags = flags;
	else
		slave_flags = flags;

	/*
	 * Open pair master/slave.
	 */
	if (pi->cpt_drv_flags&TTY_DRIVER_DEVPTS_MEM) {
		master = ptmx_open(pi->cpt_index, master_flags);
	} else {
		sprintf(pairname, "/dev/pty%c%c", a[pi->cpt_index/16], b[pi->cpt_index%16]);
		master = filp_open(pairname, master_flags|O_NONBLOCK|O_NOCTTY|O_RDWR, 0);
	}
	if (IS_ERR(master)) {
		eprintk_ctx("filp_open master: %Ld %ld\n", (long long)fi->cpt_priv, PTR_ERR(master));
		cpt_release_buf(ctx);
		return master;
	}
	stty = file_tty(master);
	clear_bit(TTY_PTY_LOCK, &stty->flags);
	if (pi->cpt_drv_flags&TTY_DRIVER_DEVPTS_MEM)
		sprintf(pairname, "/dev/pts/%d", stty->index);
	else
		sprintf(pairname, "/dev/tty%c%c", a[stty->index/16], b[stty->index%16]);
	slave = filp_open(pairname, slave_flags|O_NONBLOCK|O_NOCTTY|O_RDWR, 0);
	if (IS_ERR(slave)) {
		eprintk_ctx("filp_open slave %s: %ld\n", pairname, PTR_ERR(slave));
		fput(master);
		cpt_release_buf(ctx);
		return slave;
	}

	if (pi->cpt_drv_subtype != PTY_TYPE_MASTER)
		fixup_tty_attrs(ii, slave, ctx);

	cpt_object_add(CPT_OBJ_TTY, file_tty(master), ctx);
	cpt_object_add(CPT_OBJ_TTY, file_tty(slave), ctx);
	cpt_object_add(CPT_OBJ_FILE, master, ctx);
	cpt_object_add(CPT_OBJ_FILE, slave, ctx);

	if (pi->cpt_drv_subtype == PTY_TYPE_MASTER) {
		loff_t pos;
		obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(master), ctx);
		obj->o_parent = master;
		cpt_obj_setpos(obj, fi->cpt_priv, ctx);
		pty_setup(stty, fi->cpt_priv, pi, ctx);

		obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(slave), ctx);
		obj->o_parent = slave;
		pos = find_pty_pair(stty->link, fi->cpt_priv, pi, ctx);
		cpt_obj_setpos(obj, pos, ctx);

		obj = lookup_cpt_object(CPT_OBJ_FILE, slave, ctx);
		cpt_obj_setpos(obj, CPT_NULL, ctx);
		get_file(master);
		cpt_release_buf(ctx);
		return master;
	} else {
		loff_t pos;
		obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(slave), ctx);
		obj->o_parent = slave;
		cpt_obj_setpos(obj, fi->cpt_priv, ctx);
		pty_setup(stty->link, fi->cpt_priv, pi, ctx);

		obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(master), ctx);
		obj->o_parent = master;
		pos = find_pty_pair(stty, fi->cpt_priv, pi, ctx);
		cpt_obj_setpos(obj, pos, ctx);

		obj = lookup_cpt_object(CPT_OBJ_FILE, master, ctx);
		cpt_obj_setpos(obj, CPT_NULL, ctx);
		get_file(slave);
		cpt_release_buf(ctx);
		return slave;
	}
}